on 010fd11 help sign in
180 lines 5.6 kB history raw
1use std::collections::HashMap;
2use std::io::{self, BufRead};
4use lazy_regex::regex;
5use regex::Regex;
6use structopt::StructOpt;
8type H = HashMap<Header, Vec<(String, String, String)>>;
10#[derive(Debug, Clone, PartialEq, Eq, Hash)]
11enum Header {
12 Versioned { package: String, version: String },
13 Missing { package: String },
16#[derive(Debug, StructOpt)]
17#[structopt(
18 name = "commenter",
19 about = "Automates generation of bounds in build-constraints.yaml"
20)]
21enum Opt {
22 Clear,
23 Add,
24 Outdated,
27fn main() {
28 let opt = Opt::from_args();
29 match opt {
30 Opt::Clear => clear(),
31 Opt::Add => add(),
32 Opt::Outdated => outdated(),
33 }
36fn clear() {
37 commenter::clear();
40fn outdated() {
41 commenter::outdated();
44fn add() {
45 let mut lib_exes: H = Default::default();
46 let mut tests: H = Default::default();
47 let mut benches: H = Default::default();
48 let mut last_header: Option<Header> = None;
50 let header_versioned = regex!(
51 r#"^(?P<package>[a-zA-z]([a-zA-z0-9.-]*?))-(?P<version>(\d+(\.\d+)*)).+?is out of bounds for:$"#
52 );
53 let header_missing = regex!(r#"^(?P<package>[a-zA-z]([a-zA-z0-9.-]*)).+?depended on by:$"#);
54 let package = regex!(
55 r#"^- \[ \] (?P<package>[a-zA-z]([a-zA-z0-9.-]*?))-(?P<version>(\d+(\.\d+)*)).+?Used by: (?P<component>.+)$"#
56 );
58 // Ignore everything until the bounds issues show up.
59 let mut process_line = false;
61 for line in io::stdin().lock().lines().flatten() {
62 if is_reg_match(&line, regex!(r#"^\s*$"#)) {
63 // noop
64 } else if line == "curator: Snapshot dependency graph contains errors:" {
65 process_line = true;
66 } else if !process_line {
67 println!("[INFO] {}", line);
68 } else if let Some(cap) = package.captures(&line) {
69 let root = last_header.clone().unwrap();
70 let package = cap.name("package").unwrap().as_str();
71 let version = cap.name("version").unwrap().as_str();
72 let component = cap.name("component").unwrap().as_str();
73 match component {
74 "library" | "executable" => {
75 insert(&mut lib_exes, root, package, version, component)
76 }
77 "benchmark" => insert(&mut benches, root, package, version, "benchmarks"),
78 "test-suite" => insert(&mut tests, root, package, version, component),
79 _ => panic!("Bad component: {}", component),
80 }
81 } else if let Some(cap) = header_versioned.captures(&line) {
82 let package = cap.name("package").unwrap().as_str().to_owned();
83 let version = cap.name("version").unwrap().as_str().to_owned();
84 last_header = Some(Header::Versioned { package, version });
85 } else if let Some(cap) = header_missing.captures(&line) {
86 let package = cap.name("package").unwrap().as_str().to_owned();
87 last_header = Some(Header::Missing { package });
88 } else {
89 panic!("Unhandled: {:?}", line);
90 }
91 }
93 let mut auto_lib_exes = vec![];
94 let mut auto_tests = vec![];
95 let mut auto_benches = vec![];
97 if !lib_exes.is_empty() {
98 println!("\nLIBS + EXES\n");
99 }
100 for (header, packages) in lib_exes {
101 for (package, version, component) in packages {
102 let s = printer(" ", &package, true, &version, &component, &header);
103 println!("{}", s);
104 auto_lib_exes.push(s);
105 }
106 }
108 if !tests.is_empty() {
109 println!("\nTESTS\n");
110 }
111 for (header, packages) in tests {
112 for (package, version, component) in packages {
113 let s = printer(" ", &package, false, &version, &component, &header);
114 println!("{}", s);
115 auto_tests.push(s);
116 }
117 }
119 if !benches.is_empty() {
120 println!("\nBENCHMARKS\n");
121 }
122 for (header, packages) in benches {
123 for (package, version, component) in packages {
124 let s = printer(" ", &package, false, &version, &component, &header);
125 println!("{}", s);
126 auto_benches.push(s);
127 }
128 }
130 println!();
131 println!(
132 "Adding {lib_exes} libs, {tests} tests, {benches} benches to build-constraints.yaml",
133 lib_exes = auto_lib_exes.len(),
134 tests = auto_tests.len(),
135 benches = auto_benches.len()
136 );
137 commenter::add(auto_lib_exes, auto_tests, auto_benches);
140fn printer(
141 indent: &str,
142 package: &str,
143 lt0: bool,
144 version: &str,
145 component: &str,
146 header: &Header,
147) -> String {
148 let lt0 = if lt0 { " < 0" } else { "" };
149 format!(
150 "{indent}- {package}{lt0} # tried {package}-{version}, but its *{component}* {cause}",
151 indent = indent,
152 package = package,
153 lt0 = lt0,
154 version = version,
155 component = component,
156 cause = match header {
157 Header::Versioned { package, version } => format!(
158 "does not support: {package}-{version}",
159 package = package,
160 version = version
161 ),
162 Header::Missing { package } => format!(
163 "requires the disabled package: {package}",
164 package = package
165 ),
166 },
167 )
170fn insert(h: &mut H, header: Header, package: &str, version: &str, component: &str) {
171 (*h.entry(header).or_insert_with(Vec::new)).push((
172 package.to_owned(),
173 version.to_owned(),
174 component.to_owned(),
175 ));
178fn is_reg_match(s: &str, r: &Regex) -> bool {
179 r.captures(s).is_some()