@@ -30,8 +30,8 @@ pub fn add(lib: Vec<String>, test: Vec<String>, bench: Vec<String>) {
32enum VersionTag {
32enum VersionTag {
33− Manual(String),
33+ Manual(Version),
34− Auto(String),
34+ Auto(Version),
37impl VersionTag {
37impl VersionTag {
@@ -42,7 +42,7 @@ impl VersionTag {
45− fn version(&self) -> &str {
45+ fn version(&self) -> &Version {
46 match self {
46 match self {
47 VersionTag::Manual(s) => s,
47 VersionTag::Manual(s) => s,
48 VersionTag::Auto(s) => s,
48 VersionTag::Auto(s) => s,
@@ -52,41 +52,50 @@ impl VersionTag {
53pub fn outdated() {
53pub fn outdated() {
54 let mut all: Vec<String> = vec![];
54 let mut all: Vec<String> = vec![];
55− let versioned = handle(false, |_loc, lines| {
55+ let (versioned, disabled) = handle(false, |_loc, lines| {
56 all.extend(lines);
56 all.extend(lines);
60+ for DisabledPackage { package } in disabled {
61+ println!("WARN: {package} is disabled without a noted version");
59− let mut map: BTreeMap<String, VersionTag> = BTreeMap::new();
64+ let mut map: BTreeMap<Package, VersionTag> = BTreeMap::new();
60 for VersionedPackage { package, version } in versioned {
65 for VersionedPackage { package, version } in versioned {
61 map.insert(package, VersionTag::Manual(version));
66 map.insert(package, VersionTag::Manual(version));
63− let mut support: BTreeMap<(String, String), BTreeSet<(String, String)>> = BTreeMap::new();
68+ let mut support: BTreeMap<(Package, Version), BTreeSet<(Package, Version)>> = BTreeMap::new();
64 for v in all.into_iter() {
69 for v in all.into_iter() {
65 let caps = regex!("tried ([^ ]+)-([^,-]+),").captures(&v).unwrap();
70 let caps = regex!("tried ([^ ]+)-([^,-]+),").captures(&v).unwrap();
66− let package = caps.get(1).unwrap().as_str().to_owned();
71+ let package = Package(caps.get(1).unwrap().as_str().to_owned());
67− let version = caps.get(2).unwrap().as_str().to_owned();
72+ let version = Version(caps.get(2).unwrap().as_str().to_owned());
68 map.insert(package.clone(), VersionTag::Auto(version.clone()));
73 map.insert(package.clone(), VersionTag::Auto(version.clone()));
70 if let Some(caps) = regex!("does not support: ([^ ]+)-([^-]+)").captures(&v) {
75 if let Some(caps) = regex!("does not support: ([^ ]+)-([^-]+)").captures(&v) {
71− let dep_package = caps.get(1).unwrap().as_str().to_owned();
76+ let dep_package = Package(caps.get(1).unwrap().as_str().to_owned());
72− let dep_version = caps.get(2).unwrap().as_str().to_owned();
77+ let dep_version = Version(caps.get(2).unwrap().as_str().to_owned());
73 let entry = support.entry((dep_package, dep_version)).or_default();
78 let entry = support.entry((dep_package, dep_version)).or_default();
74 entry.insert((package, version));
79 entry.insert((package, version));
78− let entries = map.len() + support.len();
83+ let latest_versions = {
79− let mut i = 0;
84+ let mut packages: Vec<Package> = map.iter().map(|(package, _)| package.clone()).collect();
88+ .map(|((package, _), _)| package.clone())
91+ latest_version(packages.into_iter())
81 for (package, version) in map {
94 for (package, version) in map {
82 if is_boot(&package) {
95 if is_boot(&package) {
86− println!("{:02}%", ((i as f64 / entries as f64) * 100.0).floor());
89− let latest = latest_version(&package);
98+ let latest = latest_versions.get(&package).unwrap();
90 if version.version() != latest {
99 if version.version() != latest {
91 println!(
100 println!(
92 "{package} mismatch, {tag}: {version}, hackage: {latest}",
101 "{package} mismatch, {tag}: {version}, hackage: {latest}",
@@ -101,12 +110,8 @@ pub fn outdated() {
101 continue;
110 continue;
105− println!("{:02}%", ((i as f64 / entries as f64) * 100.0).floor());
108− let latest = latest_version(&package);
113+ let latest = latest_versions.get(&package).unwrap();
109− if version != latest {
114+ if &version != latest {
110 let max = 3;
115 let max = 3;
111 let dependents_stripped = dependents.len().saturating_sub(max);
116 let dependents_stripped = dependents.len().saturating_sub(max);
112 let dependents = dependents
117 let dependents = dependents
@@ -128,7 +133,7 @@ pub fn outdated() {
131−fn is_boot(package: &str) -> bool {
136+fn is_boot(package: &Package) -> bool {
@@ -151,13 +156,13 @@ fn is_boot(package: &str) -> bool {
154− .contains(&package)
159+ .contains(&&*package.0)
157−fn latest_version(pkg: &str) -> String {
162+fn latest_version(packages: impl Iterator<Item = Package>) -> BTreeMap<Package, Version> {
158 String::from_utf8(
163 String::from_utf8(
159 Command::new("latest-version")
164 Command::new("latest-version")
160− .args([pkg])
165+ .args(packages.map(|p| p.0))
161 .output()
166 .output()
162 .unwrap()
167 .unwrap()
@@ -165,6 +170,12 @@ fn latest_version(pkg: &str) -> String {
165 .unwrap()
170 .unwrap()
167 .to_owned()
172 .to_owned()
175+ let VersionedPackage { package, version } = parse_versioned_package_canonical(s).unwrap();
170enum State {
181enum State {
@@ -178,37 +189,67 @@ enum State {
180struct VersionedPackage {
191struct VersionedPackage {
181− package: String,
192+ package: Package,
182− version: String,
193+ version: Version,
196+fn parse_versioned_package_canonical(s: &str) -> Option<VersionedPackage> {
197+ if let Some(caps) = regex!(r#"^(.+)-([\d.]+)$"#).captures(s) {
198+ let package = Package(caps.get(1).unwrap().as_str().to_owned());
199+ let version = Version(caps.get(2).unwrap().as_str().to_owned());
200+ Some(VersionedPackage { package, version })
185−fn parse_versioned_package(s: &str) -> Option<VersionedPackage> {
206+fn parse_versioned_package_yaml(s: &str) -> Option<VersionedPackage> {
186 if let Some(caps) = regex!(r#"- *([^ ]+) < *0 *# *([\d.]+)"#).captures(s) {
207 if let Some(caps) = regex!(r#"- *([^ ]+) < *0 *# *([\d.]+)"#).captures(s) {
187− let package = caps.get(1).unwrap().as_str().to_owned();
208+ let package = Package(caps.get(1).unwrap().as_str().to_owned());
188− let version = caps.get(2).unwrap().as_str().to_owned();
209+ let version = Version(caps.get(2).unwrap().as_str().to_owned());
189 Some(VersionedPackage { package, version })
210 Some(VersionedPackage { package, version })
190 } else if let Some(caps) = regex!(r#"- *([^ ]+) *# *([\d.]+)"#).captures(s) {
211 } else if let Some(caps) = regex!(r#"- *([^ ]+) *# *([\d.]+)"#).captures(s) {
191− let package = caps.get(1).unwrap().as_str().to_owned();
212+ let package = Package(caps.get(1).unwrap().as_str().to_owned());
192− let version = caps.get(2).unwrap().as_str().to_owned();
213+ let version = Version(caps.get(2).unwrap().as_str().to_owned());
193 Some(VersionedPackage { package, version })
214 Some(VersionedPackage { package, version })
220+struct DisabledPackage {
224+fn parse_disabled_package(s: &str) -> Option<DisabledPackage> {
225+ if !regex!(r#"- *([^ ]+) < *0 *# tried"#).is_match(s) {
226+ if let Some(caps) = regex!(r#"- *([^ ]+) < *0 *# *[^\d]"#).captures(s) {
227+ let package = caps.get(1).unwrap().as_str().to_owned();
228+ Some(DisabledPackage { package })
199−fn handle<F>(write: bool, mut f: F) -> Vec<VersionedPackage>
237+fn handle<F>(write: bool, mut f: F) -> (Vec<VersionedPackage>, Vec<DisabledPackage>)
201 F: FnMut(Location, Vec<String>) -> Vec<String>,
239 F: FnMut(Location, Vec<String>) -> Vec<String>,
203 let path = "build-constraints.yaml";
241 let path = "build-constraints.yaml";
204 let mut new_lines: Vec<String> = vec![];
242 let mut new_lines: Vec<String> = vec![];
205 let mut versioned_packages: Vec<VersionedPackage> = vec![];
243 let mut versioned_packages: Vec<VersionedPackage> = vec![];
244+ let mut disabled_packages: Vec<DisabledPackage> = vec![];
207 let mut state = State::LookingForLibBounds;
246 let mut state = State::LookingForLibBounds;
208 let mut buf = vec![];
247 let mut buf = vec![];
209 for line in read_lines(path).map(|s| s.unwrap()) {
248 for line in read_lines(path).map(|s| s.unwrap()) {
210− if let Some(versioned_package) = parse_versioned_package(&line) {
249+ if let Some(versioned_package) = parse_versioned_package_yaml(&line) {
211 versioned_packages.push(versioned_package);
250 versioned_packages.push(versioned_package);
251+ } else if let Some(disabled_package) = parse_disabled_package(&line) {
252+ disabled_packages.push(disabled_package);
214 match state {
255 match state {
@@ -279,7 +320,7 @@ where
279 file.flush().unwrap();
320 file.flush().unwrap();
282− versioned_packages
323+ (versioned_packages, disabled_packages)
285enum Location {
326enum Location {
@@ -298,7 +339,7 @@ where
299#[derive(Deserialize)]
340#[derive(Deserialize)]
300struct SnapshotYaml {
341struct SnapshotYaml {
301− // flags: BTreeMap<PackageName, BTreeMap<PackageFlag, bool>>,
342+ // flags: BTreeMap<Package, BTreeMap<PackageFlag, bool>>,
302 // publish_time
343 // publish_time
303 packages: Vec<SnapshotPackage>,
344 packages: Vec<SnapshotPackage>,
304 // hidden
345 // hidden
@@ -312,9 +353,9 @@ struct SnapshotPackage {
314#[derive(PartialOrd, Ord, PartialEq, Eq, Clone)]
355#[derive(PartialOrd, Ord, PartialEq, Eq, Clone)]
315−struct PackageName(String);
356+struct Package(String);
317−impl fmt::Display for PackageName {
358+impl fmt::Display for Package {
318 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
359 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
319 self.0.fmt(f)
360 self.0.fmt(f)
@@ -331,7 +372,7 @@ impl fmt::Display for Version {
332// zstd-0.1.3.0@sha256:4c0a372251068eb6086b8c3a0a9f347488f08b570a7705844ffeb2c720c97223,3723
373// zstd-0.1.3.0@sha256:4c0a372251068eb6086b8c3a0a9f347488f08b570a7705844ffeb2c720c97223,3723
333struct PackageWithVersionAndSha {
374struct PackageWithVersionAndSha {
334− name: PackageName,
375+ name: Package,
335 version: Version,
376 version: Version,
@@ -343,7 +384,7 @@ impl<'de> serde::Deserialize<'de> for PackageWithVersionAndSha {
343 let s: String = String::deserialize(deserializer)?;
384 let s: String = String::deserialize(deserializer)?;
344 let r = regex!(r#"^(.+?)-([.\d]+)@sha256:[\da-z]+,\d+$"#);
385 let r = regex!(r#"^(.+?)-([.\d]+)@sha256:[\da-z]+,\d+$"#);
345 if let Some(caps) = r.captures(&s) {
386 if let Some(caps) = r.captures(&s) {
346− let name = PackageName(caps.get(1).unwrap().as_str().to_owned());
387+ let name = Package(caps.get(1).unwrap().as_str().to_owned());
347 let version = Version(caps.get(2).unwrap().as_str().to_owned());
388 let version = Version(caps.get(2).unwrap().as_str().to_owned());
348 Ok(Self { name, version })
389 Ok(Self { name, version })
@@ -366,7 +407,7 @@ where
368struct Snapshot {
409struct Snapshot {
369− packages: BTreeMap<PackageName, Diff<Version>>,
410+ packages: BTreeMap<Package, Diff<Version>>,
372#[derive(Clone, Copy)]
413#[derive(Clone, Copy)]