use std::collections::{BTreeMap, BTreeSet}; use std::fs::File; use std::io::{BufRead, BufReader, LineWriter, Lines, Write}; use std::path::Path; use std::process::Command; use lazy_regex::regex; pub fn clear() { handle(true, |loc, _lines| match loc { // Add empty array to keep yaml valid Location::Lib => vec![" []".to_owned()], Location::Test | Location::Bench => vec![], }); } pub fn add(lib: Vec, test: Vec, bench: Vec) { handle(true, |loc, mut lines| { lines.extend(match loc { Location::Lib => lib.clone(), Location::Test => test.clone(), Location::Bench => bench.clone(), }); lines.sort(); lines }) } pub fn outdated() { let mut all = vec![]; handle(false, |_loc, lines| { all.extend(lines); vec![] }); let mut map = BTreeMap::new(); let mut support: BTreeMap<(String, String), BTreeSet<(String, String)>> = BTreeMap::new(); for v in all.into_iter() { let caps = regex!("tried ([^ ]+)-([^,-]+),").captures(&v).unwrap(); let package = caps.get(1).unwrap().as_str().to_owned(); let version = caps.get(2).unwrap().as_str().to_owned(); map.insert(package.clone(), version.clone()); if let Some(caps) = regex!("does not support: ([^ ]+)-([^-]+)").captures(&v) { let dep_package = caps.get(1).unwrap().as_str().to_owned(); let dep_version = caps.get(2).unwrap().as_str().to_owned(); let entry = support .entry((dep_package, dep_version)) .or_default(); entry.insert((package, version)); } } let entries = map.len() + support.len(); let mut i = 0; for (package, version) in map { if i % 100 == 0 { println!("{:02}%", ((i as f64 / entries as f64) * 100.0).floor()); } i += 1; let latest = latest_version(&package); if version != latest { println!( "{} mismatch, snapshot: {}, hackage: {}", package, version, latest ); } } for ((package, version), dependents) in support { if i % 100 == 0 { println!("{:02}%", ((i as f64 / entries as f64) * 100.0).floor()); } i += 1; let latest = latest_version(&package); if version != latest { println!( "{} mismatch, snapshot: {}, hackage: {}, dependents: {}", package, version, latest, dependents .into_iter() .map(|(p, v)| format!("{}-{}", p, v)) .collect::>() .join(", "), ); } } } fn latest_version(pkg: &str) -> String { String::from_utf8( Command::new("latest-version") .args([pkg]) .output() .unwrap() .stdout, ) .unwrap() .trim() .to_owned() } enum State { LookingForLibBounds, ProcessingLibBounds, LookingForTestBounds, ProcessingTestBounds, LookingForBenchBounds, ProcessingBenchBounds, Done, } fn handle(write: bool, mut f: F) where F: FnMut(Location, Vec) -> Vec, { let path = "build-constraints.yaml"; let mut new_lines: Vec = vec![]; let mut state = State::LookingForLibBounds; let mut buf = vec![]; for line in read_lines(path).map(|s| s.unwrap()) { match state { State::LookingForLibBounds => { if line == r#" "Library and exe bounds failures":"# { state = State::ProcessingLibBounds; } new_lines.push(line); } State::ProcessingLibBounds => { if line == r#" # End of Library and exe bounds failures"# { new_lines.extend(f(Location::Lib, buf).into_iter()); buf = vec![]; new_lines.push(line); state = State::LookingForTestBounds; } else { // Remove empty section if line != " []" { buf.push(line); } } } State::LookingForTestBounds => { if line == r#" # Test bounds issues"# { state = State::ProcessingTestBounds; } new_lines.push(line); } State::ProcessingTestBounds => { if line == r#" # End of Test bounds issues"# { new_lines.extend(f(Location::Test, buf).into_iter()); buf = vec![]; new_lines.push(line); state = State::LookingForBenchBounds; } else { buf.push(line); } } State::LookingForBenchBounds => { if line == r#" # Benchmark bounds issues"# { state = State::ProcessingBenchBounds; } new_lines.push(line); } State::ProcessingBenchBounds => { if line == r#" # End of Benchmark bounds issues"# { new_lines.extend(f(Location::Bench, buf).into_iter()); buf = vec![]; new_lines.push(line); state = State::Done; } else { buf.push(line); } } State::Done => { new_lines.push(line); } } } if write { let file = File::create(path).unwrap(); let mut file = LineWriter::new(file); for line in new_lines { file.write_all((line + "\n").as_bytes()).unwrap(); } file.flush().unwrap(); } } enum Location { Lib, Test, Bench, } fn read_lines

(filename: P) -> Lines> where P: AsRef, { let file = File::open(filename).unwrap(); BufReader::new(file).lines() }