Ignore MSI installers with no cabs (#160)

* Ignore MSI installers with no cabs

At least aarch64, but possibly more, reference MSI installers that don't actually reference any cabinet files. These are utterly fucking worthless, so we just ignore them instead of show an error. VS install is such a garbage fire.

* Fix lints

* Rustfmt

* Update CHANGELOG
This commit is contained in:
Jake Shadle
2025-08-15 09:02:54 +02:00
committed by GitHub
parent 8ca8273151
commit b848cfebb6
7 changed files with 219 additions and 41 deletions
+1 -1
View File
@@ -43,7 +43,7 @@ jobs:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
# Add the actual target we compile for in the test
- run: rustup target add x86_64-pc-windows-msvc
- run: rustup target add x86_64-pc-windows-msvc aarch64-pc-windows-msvc
- name: symlinks
run: |
set -eux
+4
View File
@@ -8,6 +8,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
<!-- next-header -->
## [Unreleased] - ReleaseDate
### Fixed
- [PR#160](https://github.com/Jake-Shadle/xwin/pull/160) resolved [#126](https://github.com/Jake-Shadle/xwin/issues/126) by ignoring MSI installers that don't reference any cabinet files. Why do such utterly fucking useless installers exist? Because fuck me I guess.
- [PR#159](https://github.com/Jake-Shadle/xwin/pull/159) fixed an issue where enabling native TLS was not actually doing anything. No one actually reported this not working which makes me think no one is using this feature. :)
## [0.6.6] - 2025-06-19
### Fixed
- [PR#143](https://github.com/Jake-Shadle/xwin/pull/142) is a second attempt to resolve [#141](https://github.com/Jake-Shadle/xwin/issues/141) by switching to a new `3.0.0-rc1` version of ureq that might not have the same issue, as well as adding support for retries for EOF I/O errors seen by users which can be configured via `--http-retry` or `XWIN_HTTP_RETRY`.
+17 -13
View File
@@ -366,6 +366,11 @@ impl Ctx {
return Ok(None);
}
let Some(payload_contents) = payload_contents else {
wi.progress.abandon_with_message("MSI with no cabs");
return Ok(None);
};
let ft = crate::unpack::unpack(self.clone(), &wi, payload_contents)?;
if let crate::Ops::Unpack = ops {
@@ -482,19 +487,18 @@ impl Ctx {
unpack_dir.push(".unpack");
if let Ok(unpack) = std::fs::read(&unpack_dir) {
if let Ok(um) = serde_json::from_slice::<crate::unpack::UnpackMeta>(&unpack) {
if payload.sha256 == um.sha256 {
tracing::debug!("already unpacked");
unpack_dir.pop();
return Ok(Unpack::Present {
output_dir: unpack_dir,
compressed: um.compressed,
decompressed: um.decompressed,
num_files: um.num_files,
});
}
}
if let Ok(unpack) = std::fs::read(&unpack_dir)
&& let Ok(um) = serde_json::from_slice::<crate::unpack::UnpackMeta>(&unpack)
&& payload.sha256 == um.sha256
{
tracing::debug!("already unpacked");
unpack_dir.pop();
return Ok(Unpack::Present {
output_dir: unpack_dir,
compressed: um.compressed,
decompressed: um.decompressed,
num_files: um.num_files,
});
}
unpack_dir.pop();
+9 -5
View File
@@ -30,7 +30,7 @@ pub(crate) fn download(
ctx: Arc<Ctx>,
pkgs: Arc<std::collections::BTreeMap<String, manifest::ManifestItem>>,
item: &crate::WorkItem,
) -> Result<PayloadContents, Error> {
) -> Result<Option<PayloadContents>, Error> {
item.progress.set_message("📥 downloading..");
let contents = ctx.get_and_validate(
@@ -70,7 +70,7 @@ pub(crate) fn download(
download_cabs(ctx, &cabs, item, contents)
}
Some("vsix") => Ok(PayloadContents::Vsix(contents)),
Some("vsix") => Ok(Some(PayloadContents::Vsix(contents))),
ext => anyhow::bail!("unknown extension {ext:?}"),
};
@@ -86,7 +86,7 @@ fn download_cabs(
cabs: &[Cab],
msi: &crate::WorkItem,
msi_content: bytes::Bytes,
) -> Result<PayloadContents, Error> {
) -> Result<Option<PayloadContents>, Error> {
use rayon::prelude::*;
let msi_filename = &msi.payload.filename;
@@ -136,6 +136,10 @@ fn download_cabs(
})
.collect();
if cab_files.is_empty() {
return Ok(None);
}
let cabs = cab_files
.into_par_iter()
.map(
@@ -151,8 +155,8 @@ fn download_cabs(
)
.collect::<Result<Vec<_>, _>>()?;
Ok(PayloadContents::Msi {
Ok(Some(PayloadContents::Msi {
msi: msi_content,
cabs,
})
}))
}
+10 -13
View File
@@ -408,7 +408,7 @@ pub(crate) fn splat(
mappings
}
PayloadKind::VcrDebug => {
if vcrd_version.is_some() {
if let Some(version) = vcrd_version {
let mut src = src.clone();
let mut target = roots.vcrd.clone();
@@ -420,7 +420,7 @@ pub(crate) fn splat(
});
};
target.push(vcrd_version.unwrap());
target.push(version);
target.push("bin");
target.push(item.payload.target_arch.unwrap().as_str());
@@ -588,18 +588,15 @@ pub(crate) fn splat(
if !include_debug_libs
&& (mapping.kind == PayloadKind::CrtLibs
|| mapping.kind == PayloadKind::Ucrt)
&& let Some(stripped) = fname_str.strip_suffix(".lib")
&& (stripped.ends_with('d')
|| stripped.ends_with("d_netcore")
|| stripped
.strip_suffix(|c: char| c.is_ascii_digit())
.is_some_and(|fname| fname.ends_with('d')))
{
if let Some(stripped) = fname_str.strip_suffix(".lib") {
if stripped.ends_with('d')
|| stripped.ends_with("d_netcore")
|| stripped
.strip_suffix(|c: char| c.is_ascii_digit())
.is_some_and(|fname| fname.ends_with('d'))
{
tracing::debug!("skipping {fname}");
continue;
}
}
tracing::debug!("skipping {fname}");
continue;
}
tar.push(fname);
+9 -9
View File
@@ -176,11 +176,11 @@ pub(crate) fn unpack(
fs_path.push(comp);
}
if let Some(parent) = fs_path.parent() {
if !parent.exists() {
std::fs::create_dir_all(parent)
.with_context(|| format!("unable to create unpack dir '{parent}'"))?;
}
if let Some(parent) = fs_path.parent()
&& !parent.exists()
{
std::fs::create_dir_all(parent)
.with_context(|| format!("unable to create unpack dir '{parent}'"))?;
}
let mut dest = std::fs::File::create(&fs_path).with_context(|| {
@@ -526,10 +526,10 @@ pub(crate) fn unpack(
let unpack_path = output_dir.join(&file.name);
if let Some(parent) = unpack_path.parent() {
if !parent.exists() {
std::fs::create_dir_all(parent)?;
}
if let Some(parent) = unpack_path.parent()
&& !parent.exists()
{
std::fs::create_dir_all(parent)?;
}
let unpacked_file = std::fs::File::create(&unpack_path)?;
+169
View File
@@ -290,3 +290,172 @@ fn verify_compiles_minimized() {
assert!(cmd.status().unwrap().success());
}
#[test]
fn verify_compiles_aarch64() {
let ctx = xwin::Ctx::with_dir(
xwin::PathBuf::from(".xwin-cache/compiles-aarch64"),
xwin::util::ProgressTarget::Hidden,
ureq::agent(),
0,
)
.unwrap();
let ctx = std::sync::Arc::new(ctx);
let hidden = indicatif::ProgressBar::hidden();
// TODO: Bump to CI to 17 once github actions isn't using an ancient version,
// we could install in the action run, but not really worth it since I can
// test locally
let manifest_version = if std::env::var_os("CI").is_some() {
"16"
} else {
"17"
};
let manifest =
xwin::manifest::get_manifest(&ctx, manifest_version, "release", hidden.clone()).unwrap();
let pkg_manifest =
xwin::manifest::get_package_manifest(&ctx, &manifest, hidden.clone()).unwrap();
let pruned = xwin::prune_pkg_list(
&pkg_manifest,
xwin::Arch::Aarch64 as u32,
xwin::Variant::Desktop as u32,
false,
false,
None,
None,
)
.unwrap();
#[derive(Debug)]
enum Style {
Default,
WinSysRoot,
}
for style in [Style::Default, Style::WinSysRoot] {
let output_dir = ctx.work_dir.join(format!("{style:?}"));
if !output_dir.exists() {
std::fs::create_dir_all(&output_dir).unwrap();
}
if !cfg!(target_os = "windows") && matches!(style, Style::WinSysRoot) {
continue;
}
let op = xwin::Ops::Splat(xwin::SplatConfig {
include_debug_libs: false,
include_debug_symbols: false,
enable_symlinks: matches!(style, Style::Default),
preserve_ms_arch_notation: matches!(style, Style::WinSysRoot),
use_winsysroot_style: matches!(style, Style::WinSysRoot),
map: None,
copy: true,
output: output_dir.clone(),
});
ctx.clone()
.execute(
pkg_manifest.packages.clone(),
pruned
.payloads
.clone()
.into_iter()
.map(|payload| xwin::WorkItem {
progress: hidden.clone(),
payload: std::sync::Arc::new(payload),
})
.collect(),
pruned.crt_version.clone(),
pruned.sdk_version.clone(),
pruned.vcr_version.clone(),
xwin::Arch::Aarch64 as u32,
xwin::Variant::Desktop as u32,
op,
)
.unwrap();
if xwin::Path::new("tests/xwin-test/target").exists() {
std::fs::remove_dir_all("tests/xwin-test/target").expect("failed to remove target dir");
}
let mut cmd = std::process::Command::new("cargo");
cmd.args([
"build",
"--target",
"aarch64-pc-windows-msvc",
"--manifest-path",
"tests/xwin-test/Cargo.toml",
]);
let od = xwin::util::canonicalize(&output_dir).unwrap();
let includes = match style {
Style::Default => {
cmd.env("RUSTFLAGS", format!("-C linker=lld-link -Lnative={od}/crt/lib/aarch64 -Lnative={od}/sdk/lib/um/aarch64 -Lnative={od}/sdk/lib/ucrt/aarch64"));
format!(
"-Wno-unused-command-line-argument -fuse-ld=lld-link /imsvc{od}/crt/include /imsvc{od}/sdk/include/ucrt /imsvc{od}/sdk/include/um /imsvc{od}/sdk/include/shared"
)
}
Style::WinSysRoot => {
const SEP: char = '\x1F';
cmd.env("CARGO_ENCODED_RUSTFLAGS", format!("-C{SEP}linker=lld-link{SEP}-Lnative={od}/VC/Tools/MSVC/{crt_version}/Lib/x64{SEP}-Lnative={od}/Windows Kits/10/Lib/{sdk_version}/um/x64{SEP}-Lnative={od}/Windows Kits/10/Lib/{sdk_version}/ucrt/x64", crt_version = &pruned.crt_version, sdk_version = &pruned.sdk_version));
format!("-Wno-unused-command-line-argument -fuse-ld=lld-link /winsysroot {od}")
}
};
let cc_env = [
("CC_aarch64_pc_windows_msvc", "clang-cl"),
("CXX_aarch64_pc_windows_msvc", "clang-cl"),
("AR_aarch64_pc_windows_msvc", "llvm-lib"),
("CFLAGS_aarch64_pc_windows_msvc", &includes),
("CXXFLAGS_aarch64_pc_windows_msvc", &includes),
];
cmd.envs(cc_env);
assert!(cmd.status().unwrap().success());
// Ignore the /vctoolsdir /winsdkdir test below on CI since it fails, I'm assuming
// due to the clang version in GHA being outdated, but don't have the will to
// look into it now
if !matches!(style, Style::Default) || std::env::var("CI").is_ok() {
return;
}
std::fs::remove_dir_all("tests/xwin-test/target").expect("failed to remove target dir");
let mut cmd = std::process::Command::new("cargo");
cmd.args([
"build",
"--target",
"aarch64-pc-windows-msvc",
"--manifest-path",
"tests/xwin-test/Cargo.toml",
]);
let includes = format!(
"-Wno-unused-command-line-argument -fuse-ld=lld-link /vctoolsdir {od}/crt /winsdkdir {od}/sdk"
);
let libs = format!(
"-C linker=lld-link -Lnative={od}/crt/lib/aarch64 -Lnative={od}/sdk/lib/um/aarch64 -Lnative={od}/sdk/lib/ucrt/aarch64"
);
let cc_env = [
("CC_aarch4_pc_windows_msvc", "clang-cl"),
("CXX_aarch64_pc_windows_msvc", "clang-cl"),
("AR_aarch64_pc_windows_msvc", "llvm-lib"),
("CFLAGS_aarch64_pc_windows_msvc", &includes),
("CXXFLAGS_aarch64_pc_windows_msvc", &includes),
("RUSTFLAGS", &libs),
];
cmd.envs(cc_env);
assert!(cmd.status().unwrap().success());
}
}