Skip to content

Commit fa4b6b6

Browse files
codexmxcl
authored andcommitted
Refine ffmpeg and imagemagick stub exclusions
Signed-off-by: Max Howell <mxcl@me.com>
1 parent bb63971 commit fa4b6b6

4 files changed

Lines changed: 230 additions & 4 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "substrate"
3-
version = "0.5.0"
3+
version = "0.5.1"
44
edition = "2024"
55
autobins = false
66

data/stub_exclusions.json

Lines changed: 88 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,90 @@
11
{
2-
"brew:bash": ["bashbug"]
2+
"brew:bash": ["bashbug"],
3+
"brew:awscli": ["aws_completer"],
4+
"brew:ffmpeg-full": [
5+
"aviocat",
6+
"bisect-create",
7+
"check_arm_indent.sh",
8+
"clean-diff",
9+
"compare-cvelists.sh",
10+
"crypto_bench",
11+
"cws2fws",
12+
"dvd2concat",
13+
"enc_recon_frame_test",
14+
"enum_options",
15+
"ffescape",
16+
"ffeval",
17+
"ffhash",
18+
"fourcc2pixfmt",
19+
"gen-rc",
20+
"general_assembly.pl",
21+
"graph2dot",
22+
"indent_arm_assembly.pl",
23+
"ismindex",
24+
"loudnorm.rb",
25+
"make_chlayout_test",
26+
"merge-all-source-plugins",
27+
"missing_codec_desc",
28+
"murge",
29+
"normalize.py",
30+
"patcheck",
31+
"pktdumper",
32+
"plotframes",
33+
"probetest",
34+
"qt-faststart",
35+
"scale_slice_test",
36+
"seek_print",
37+
"sidxindex",
38+
"source2c",
39+
"target_dec_fate.sh",
40+
"trasher",
41+
"uncoded_frame",
42+
"unwrap-diff",
43+
"venc_data_dump",
44+
"zmqsend",
45+
"zmqshell.py"
46+
],
47+
"brew:ffmpeg": [
48+
"aviocat",
49+
"bisect-create",
50+
"check_arm_indent.sh",
51+
"clean-diff",
52+
"compare-cvelists.sh",
53+
"crypto_bench",
54+
"cws2fws",
55+
"dvd2concat",
56+
"enc_recon_frame_test",
57+
"enum_options",
58+
"ffescape",
59+
"ffeval",
60+
"ffhash",
61+
"fourcc2pixfmt",
62+
"gen-rc",
63+
"general_assembly.pl",
64+
"graph2dot",
65+
"indent_arm_assembly.pl",
66+
"ismindex",
67+
"loudnorm.rb",
68+
"make_chlayout_test",
69+
"merge-all-source-plugins",
70+
"missing_codec_desc",
71+
"murge",
72+
"normalize.py",
73+
"patcheck",
74+
"pktdumper",
75+
"plotframes",
76+
"probetest",
77+
"qt-faststart",
78+
"scale_slice_test",
79+
"seek_print",
80+
"sidxindex",
81+
"source2c",
82+
"target_dec_fate.sh",
83+
"trasher",
84+
"uncoded_frame",
85+
"unwrap-diff",
86+
"venc_data_dump",
87+
"zmqsend",
88+
"zmqshell.py"
89+
]
390
}

src/lib.rs

Lines changed: 140 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2068,6 +2068,49 @@ fn package_stub_exclusions(package_name: &str) -> HashSet<String> {
20682068
.unwrap_or_default()
20692069
}
20702070

2071+
fn imagemagick_stub_exclusions(
2072+
plan: &InstallPlan,
2073+
current: &[(String, PathBuf)],
2074+
) -> HashSet<String> {
2075+
if !should_only_stub_magick(plan) {
2076+
return HashSet::new();
2077+
}
2078+
2079+
current
2080+
.iter()
2081+
.filter_map(|(name, _)| (name != "magick").then(|| name.clone()))
2082+
.collect()
2083+
}
2084+
2085+
fn should_only_stub_magick(plan: &InstallPlan) -> bool {
2086+
match plan.root_formula.as_str() {
2087+
"imagemagick-full" => true,
2088+
"imagemagick" => installed_formula_major_version(plan).is_some_and(|major| major >= 7),
2089+
_ => false,
2090+
}
2091+
}
2092+
2093+
fn installed_formula_major_version(plan: &InstallPlan) -> Option<u64> {
2094+
let receipt = load_package_receipt(&plan.root_receipt_path())
2095+
.ok()
2096+
.flatten()?;
2097+
let PackageReceiptSource::Formula { root_formula } = receipt.source else {
2098+
return None;
2099+
};
2100+
if root_formula != plan.root_formula {
2101+
return None;
2102+
}
2103+
parse_homebrew_major_version(&receipt.version)
2104+
}
2105+
2106+
fn parse_homebrew_major_version(version: &str) -> Option<u64> {
2107+
let trimmed = version.strip_prefix('v').unwrap_or(version);
2108+
trimmed
2109+
.split(|ch: char| !ch.is_ascii_digit())
2110+
.find(|part| !part.is_empty())
2111+
.and_then(|major| major.parse().ok())
2112+
}
2113+
20712114
fn versioned_python_stub_exclusions(formula: &str) -> HashSet<String> {
20722115
let Some((major, minor)) = parse_python_formula_version(formula) else {
20732116
return HashSet::new();
@@ -3635,7 +3678,6 @@ fn sync_stubs(
36353678

36363679
fs::create_dir_all(USR_LOCAL_BIN)
36373680
.map_err(|err| format!("failed to create {}: {err}", USR_LOCAL_BIN))?;
3638-
let excluded_stubs = formula_stub_exclusions(&plan.root_formula);
36393681
let current = if plan.mode == Mode::I {
36403682
let manifest = load_root_executable_manifest(&plan.root_executables_manifest_path())?;
36413683
if manifest.stubs.is_empty() {
@@ -3649,6 +3691,8 @@ fn sync_stubs(
36493691
} else {
36503692
collect_root_executables(&plan.stable_root)?
36513693
};
3694+
let mut excluded_stubs = formula_stub_exclusions(&plan.root_formula);
3695+
excluded_stubs.extend(imagemagick_stub_exclusions(plan, &current));
36523696
let current = filter_stub_executables(current, &excluded_stubs);
36533697
for stub in previous_stubs {
36543698
if !current.iter().any(|(name, _)| name == stub) {
@@ -7674,6 +7718,14 @@ long_prefix = re.compile(r'/opt/python@3.12/[0-9\\._abrc]+')\n"
76747718
);
76757719
}
76767720

7721+
#[test]
7722+
fn formula_stub_exclusions_alias_ffmpeg_to_ffmpeg_full() {
7723+
assert_eq!(
7724+
formula_stub_exclusions("ffmpeg"),
7725+
formula_stub_exclusions("ffmpeg-full")
7726+
);
7727+
}
7728+
76777729
#[test]
76787730
fn formula_stub_exclusions_cover_dead_python_tools() {
76797731
let exclusions = formula_stub_exclusions("python@3.12");
@@ -7698,6 +7750,93 @@ long_prefix = re.compile(r'/opt/python@3.12/[0-9\\._abrc]+')\n"
76987750
assert!(!exclusions.contains("pip3.12"));
76997751
}
77007752

7753+
#[test]
7754+
fn imagemagick_full_only_stubs_magick() {
7755+
let temp = TempDir::new().unwrap();
7756+
let plan = InstallPlan {
7757+
mode: Mode::I,
7758+
package_name: "imagemagick-full".to_string(),
7759+
root_formula: "imagemagick-full".to_string(),
7760+
stable_root: temp.path().join("opt/imagemagick-full"),
7761+
install_root: temp.path().join("opt/imagemagick-full"),
7762+
tmp_root: temp.path().join("tmp"),
7763+
};
7764+
let current = vec![
7765+
("convert".to_string(), PathBuf::from("/tmp/bin/convert")),
7766+
("magick".to_string(), PathBuf::from("/tmp/bin/magick")),
7767+
("identify".to_string(), PathBuf::from("/tmp/bin/identify")),
7768+
];
7769+
7770+
assert_eq!(
7771+
imagemagick_stub_exclusions(&plan, &current),
7772+
HashSet::from(["convert".to_string(), "identify".to_string()])
7773+
);
7774+
}
7775+
7776+
#[test]
7777+
fn imagemagick_v7_only_stubs_magick() {
7778+
let temp = TempDir::new().unwrap();
7779+
let plan = InstallPlan {
7780+
mode: Mode::I,
7781+
package_name: "imagemagick".to_string(),
7782+
root_formula: "imagemagick".to_string(),
7783+
stable_root: temp.path().join("opt/imagemagick"),
7784+
install_root: temp.path().join("opt/imagemagick"),
7785+
tmp_root: temp.path().join("tmp"),
7786+
};
7787+
write_package_receipt(
7788+
&plan.root_receipt_path(),
7789+
&PackageReceipt {
7790+
package_name: "imagemagick".to_string(),
7791+
version: "7.1.2_3".to_string(),
7792+
source: PackageReceiptSource::Formula {
7793+
root_formula: "imagemagick".to_string(),
7794+
},
7795+
},
7796+
)
7797+
.unwrap();
7798+
let current = vec![
7799+
("convert".to_string(), PathBuf::from("/tmp/bin/convert")),
7800+
("magick".to_string(), PathBuf::from("/tmp/bin/magick")),
7801+
("mogrify".to_string(), PathBuf::from("/tmp/bin/mogrify")),
7802+
];
7803+
7804+
assert_eq!(
7805+
imagemagick_stub_exclusions(&plan, &current),
7806+
HashSet::from(["convert".to_string(), "mogrify".to_string()])
7807+
);
7808+
}
7809+
7810+
#[test]
7811+
fn imagemagick_v6_keeps_legacy_stubs() {
7812+
let temp = TempDir::new().unwrap();
7813+
let plan = InstallPlan {
7814+
mode: Mode::I,
7815+
package_name: "imagemagick".to_string(),
7816+
root_formula: "imagemagick".to_string(),
7817+
stable_root: temp.path().join("opt/imagemagick"),
7818+
install_root: temp.path().join("opt/imagemagick"),
7819+
tmp_root: temp.path().join("tmp"),
7820+
};
7821+
write_package_receipt(
7822+
&plan.root_receipt_path(),
7823+
&PackageReceipt {
7824+
package_name: "imagemagick".to_string(),
7825+
version: "6.9.13_7".to_string(),
7826+
source: PackageReceiptSource::Formula {
7827+
root_formula: "imagemagick".to_string(),
7828+
},
7829+
},
7830+
)
7831+
.unwrap();
7832+
let current = vec![
7833+
("convert".to_string(), PathBuf::from("/tmp/bin/convert")),
7834+
("magick".to_string(), PathBuf::from("/tmp/bin/magick")),
7835+
];
7836+
7837+
assert!(imagemagick_stub_exclusions(&plan, &current).is_empty());
7838+
}
7839+
77017840
#[test]
77027841
fn stage_formula_merges_dependency_into_i_root() {
77037842
let temp = TempDir::new().unwrap();

0 commit comments

Comments
 (0)