@@ -30,8 +30,8 @@ pub fn add(lib: Vec<String>, test: Vec<String>, bench: Vec<String>) {
3030}
3131
3232enum VersionTag {
33− Manual(String),
34− Auto(String),
33+ Manual(Version),
34+ Auto(Version),
3535}
3636
3737impl VersionTag {
@@ -42,7 +42,7 @@ impl VersionTag {
4242 }
4343 }
4444
45− fn version(&self) -> &str {
45+ fn version(&self) -> &Version {
4646 match self {
4747 VersionTag::Manual(s) => s,
4848 VersionTag::Auto(s) => s,
@@ -52,41 +52,50 @@ impl VersionTag {
5252
5353pub fn outdated() {
5454 let mut all: Vec<String> = vec![];
55− let versioned = handle(false, |_loc, lines| {
55+ let (versioned, disabled) = handle(false, |_loc, lines| {
5656 all.extend(lines);
5757 vec![]
5858 });
59− let mut map: BTreeMap<String, VersionTag> = BTreeMap::new();
59+
60+ for DisabledPackage { package } in disabled {
61+ println!("WARN: {package} is disabled without a noted version");
62+ }
63+
64+ let mut map: BTreeMap<Package, VersionTag> = BTreeMap::new();
6065 for VersionedPackage { package, version } in versioned {
6166 map.insert(package, VersionTag::Manual(version));
6267 }
63− let mut support: BTreeMap<(String, String), BTreeSet<(String, String)>> = BTreeMap::new();
68+ let mut support: BTreeMap<(Package, Version), BTreeSet<(Package, Version)>> = BTreeMap::new();
6469 for v in all.into_iter() {
6570 let caps = regex!("tried ([^ ]+)-([^,-]+),").captures(&v).unwrap();
66− let package = caps.get(1).unwrap().as_str().to_owned();
67− let version = caps.get(2).unwrap().as_str().to_owned();
71+ let package = Package(caps.get(1).unwrap().as_str().to_owned());
72+ let version = Version(caps.get(2).unwrap().as_str().to_owned());
6873 map.insert(package.clone(), VersionTag::Auto(version.clone()));
6974
7075 if let Some(caps) = regex!("does not support: ([^ ]+)-([^-]+)").captures(&v) {
71− let dep_package = caps.get(1).unwrap().as_str().to_owned();
72− let dep_version = caps.get(2).unwrap().as_str().to_owned();
76+ let dep_package = Package(caps.get(1).unwrap().as_str().to_owned());
77+ let dep_version = Version(caps.get(2).unwrap().as_str().to_owned());
7378 let entry = support.entry((dep_package, dep_version)).or_default();
7479 entry.insert((package, version));
7580 }
7681 }
7782
78− let entries = map.len() + support.len();
79− let mut i = 0;
83+ let latest_versions = {
84+ let mut packages: Vec<Package> = map.iter().map(|(package, _)| package.clone()).collect();
85+ packages.append(
86+ &mut support
87+ .iter()
88+ .map(|((package, _), _)| package.clone())
89+ .collect(),
90+ );
91+ latest_version(packages.into_iter())
92+ };
8093
8194 for (package, version) in map {
8295 if is_boot(&package) {
8396 continue;
8497 }
85− if i % 100 == 0 {
86− println!("{:02}%", ((i as f64 / entries as f64) * 100.0).floor());
87− }
88− i += 1;
89− let latest = latest_version(&package);
98+ let latest = latest_versions.get(&package).unwrap();
9099 if version.version() != latest {
91100 println!(
92101 "{package} mismatch, {tag}: {version}, hackage: {latest}",
@@ -101,12 +110,8 @@ pub fn outdated() {
101110 continue;
102111 }
103112
104− if i % 100 == 0 {
105− println!("{:02}%", ((i as f64 / entries as f64) * 100.0).floor());
106− }
107− i += 1;
108− let latest = latest_version(&package);
109− if version != latest {
113+ let latest = latest_versions.get(&package).unwrap();
114+ if &version != latest {
110115 let max = 3;
111116 let dependents_stripped = dependents.len().saturating_sub(max);
112117 let dependents = dependents
@@ -128,7 +133,7 @@ pub fn outdated() {
128133 }
129134}
130135
131−fn is_boot(package: &str) -> bool {
136+fn is_boot(package: &Package) -> bool {
132137 [
133138 "Cabal",
134139 "base",
@@ -151,13 +156,13 @@ fn is_boot(package: &str) -> bool {
151156 "text",
152157 "time",
153158 ]
154− .contains(&package)
159+ .contains(&&*package.0)
155160}
156161
157−fn latest_version(pkg: &str) -> String {
162+fn latest_version(packages: impl Iterator<Item = Package>) -> BTreeMap<Package, Version> {
158163 String::from_utf8(
159164 Command::new("latest-version")
160− .args([pkg])
165+ .args(packages.map(|p| p.0))
161166 .output()
162167 .unwrap()
163168 .stdout,
@@ -165,6 +170,12 @@ fn latest_version(pkg: &str) -> String {
165170 .unwrap()
166171 .trim()
167172 .to_owned()
173+ .lines()
174+ .map(|s| {
175+ let VersionedPackage { package, version } = parse_versioned_package_canonical(s).unwrap();
176+ (package, version)
177+ })
178+ .collect()
168179}
169180
170181enum State {
@@ -178,37 +189,67 @@ enum State {
178189}
179190
180191struct VersionedPackage {
181− package: String,
182− version: String,
192+ package: Package,
193+ version: Version,
183194}
184195
185−fn parse_versioned_package(s: &str) -> Option<VersionedPackage> {
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 })
201+ } else {
202+ None
203+ }
204+}
205+
206+fn parse_versioned_package_yaml(s: &str) -> Option<VersionedPackage> {
186207 if let Some(caps) = regex!(r#"- *([^ ]+) < *0 *# *([\d.]+)"#).captures(s) {
187− let package = caps.get(1).unwrap().as_str().to_owned();
188− let version = caps.get(2).unwrap().as_str().to_owned();
208+ let package = Package(caps.get(1).unwrap().as_str().to_owned());
209+ let version = Version(caps.get(2).unwrap().as_str().to_owned());
189210 Some(VersionedPackage { package, version })
190211 } else if let Some(caps) = regex!(r#"- *([^ ]+) *# *([\d.]+)"#).captures(s) {
191− let package = caps.get(1).unwrap().as_str().to_owned();
192− let version = caps.get(2).unwrap().as_str().to_owned();
212+ let package = Package(caps.get(1).unwrap().as_str().to_owned());
213+ let version = Version(caps.get(2).unwrap().as_str().to_owned());
193214 Some(VersionedPackage { package, version })
194215 } else {
195216 None
196217 }
197218}
198219
199−fn handle<F>(write: bool, mut f: F) -> Vec<VersionedPackage>
220+struct DisabledPackage {
221+ package: String,
222+}
223+
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 })
229+ } else {
230+ None
231+ }
232+ } else {
233+ None
234+ }
235+}
236+
237+fn handle<F>(write: bool, mut f: F) -> (Vec<VersionedPackage>, Vec<DisabledPackage>)
200238where
201239 F: FnMut(Location, Vec<String>) -> Vec<String>,
202240{
203241 let path = "build-constraints.yaml";
204242 let mut new_lines: Vec<String> = vec![];
205243 let mut versioned_packages: Vec<VersionedPackage> = vec![];
244+ let mut disabled_packages: Vec<DisabledPackage> = vec![];
206245
207246 let mut state = State::LookingForLibBounds;
208247 let mut buf = vec![];
209248 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) {
211250 versioned_packages.push(versioned_package);
251+ } else if let Some(disabled_package) = parse_disabled_package(&line) {
252+ disabled_packages.push(disabled_package);
212253 }
213254
214255 match state {
@@ -279,7 +320,7 @@ where
279320 file.flush().unwrap();
280321 }
281322
282− versioned_packages
323+ (versioned_packages, disabled_packages)
283324}
284325
285326enum Location {
@@ -298,7 +339,7 @@ where
298339
299340#[derive(Deserialize)]
300341struct SnapshotYaml {
301− // flags: BTreeMap<PackageName, BTreeMap<PackageFlag, bool>>,
342+ // flags: BTreeMap<Package, BTreeMap<PackageFlag, bool>>,
302343 // publish_time
303344 packages: Vec<SnapshotPackage>,
304345 // hidden
@@ -312,9 +353,9 @@ struct SnapshotPackage {
312353}
313354
314355#[derive(PartialOrd, Ord, PartialEq, Eq, Clone)]
315−struct PackageName(String);
356+struct Package(String);
316357
317−impl fmt::Display for PackageName {
358+impl fmt::Display for Package {
318359 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
319360 self.0.fmt(f)
320361 }
@@ -331,7 +372,7 @@ impl fmt::Display for Version {
331372
332373// zstd-0.1.3.0@sha256:4c0a372251068eb6086b8c3a0a9f347488f08b570a7705844ffeb2c720c97223,3723
333374struct PackageWithVersionAndSha {
334− name: PackageName,
375+ name: Package,
335376 version: Version,
336377}
337378
@@ -343,7 +384,7 @@ impl<'de> serde::Deserialize<'de> for PackageWithVersionAndSha {
343384 let s: String = String::deserialize(deserializer)?;
344385 let r = regex!(r#"^(.+?)-([.\d]+)@sha256:[\da-z]+,\d+$"#);
345386 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());
347388 let version = Version(caps.get(2).unwrap().as_str().to_owned());
348389 Ok(Self { name, version })
349390 } else {
@@ -366,7 +407,7 @@ where
366407}
367408
368409struct Snapshot {
369− packages: BTreeMap<PackageName, Diff<Version>>,
410+ packages: BTreeMap<Package, Diff<Version>>,
370411}
371412
372413#[derive(Clone, Copy)]