on master help sign in
Merge pull request #6349 from commercialhaskell/commenter-automation-2
5783bb8Adam Bergmark
etc/commenter/Cargo.lock+1−1
@@ -54,7 +54,7 @@ dependencies = [
54
54
55[[package]]
55[[package]]
56name = "commenter"
56name = "commenter"
57−version = "0.1.0"
57+version = "0.2.0"
58dependencies = [
58dependencies = [
59 "lazy-regex",
59 "lazy-regex",
60 "regex",
60 "regex",
etc/commenter/latest-version/LICENSEnew file+30
@@ -0,0 +1,30 @@
1+Copyright Adam Bergmark (c) 2021
2+
3+All rights reserved.
4+
5+Redistribution and use in source and binary forms, with or without
6+modification, are permitted provided that the following conditions are met:
7+
8+ * Redistributions of source code must retain the above copyright
9+ notice, this list of conditions and the following disclaimer.
10+
11+ * Redistributions in binary form must reproduce the above
12+ copyright notice, this list of conditions and the following
13+ disclaimer in the documentation and/or other materials provided
14+ with the distribution.
15+
16+ * Neither the name of Author name here nor the names of other
17+ contributors may be used to endorse or promote products derived
18+ from this software without specific prior written permission.
19+
20+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
etc/commenter/latest-version/README.mdnew file+1
@@ -0,0 +1 @@
1+# latest-version
etc/commenter/latest-version/Setup.hsnew file+2
@@ -0,0 +1,2 @@
1+import Distribution.Simple
2+main = defaultMain
etc/commenter/latest-version/cabal.projectnew file+6
@@ -0,0 +1,6 @@
1+source-repository-package
2+ type: git
3+ location: git://github.com/commercialhaskell/pantry.git
4+
5+packages: ./latest-version.cabal
6+with-compiler: ghc-8.10.7
etc/commenter/latest-version/latest-version.cabalnew file+23
@@ -0,0 +1,23 @@
1+name: latest-version
2+version: 0.1.0.0
3+homepage: https://github.com/githubuser/latest-version#readme
4+license: BSD3
5+license-file: LICENSE
6+author: Adam Bergmark
7+maintainer: adam@bergmark.nl
8+copyright: 2021 Adam Bergmark
9+category: Web
10+build-type: Simple
11+cabal-version: >=1.10
12+extra-source-files: README.md
13+
14+executable latest-version
15+ ghc-options: -Wall
16+ hs-source-dirs: src
17+ main-is: Main.hs
18+ default-language: Haskell2010
19+ build-depends: base >= 4.7 && < 5
20+ , pantry
21+ , Cabal
22+ , rio
23+ , containers
etc/commenter/latest-version/src/Main.hsnew file+18
@@ -0,0 +1,18 @@
1+module Main where
2+
3+import Data.List
4+import Distribution.Types.PackageName
5+import Distribution.Types.Version
6+import Pantry
7+import RIO
8+import System.Environment
9+import qualified Data.Map as Map
10+
11+main :: IO ()
12+main =
13+ runPantryApp $
14+ liftIO . putStrLn
15+ . intercalate "." . map show . versionNumbers
16+ . fst . head . Map.toDescList
17+ =<< getHackagePackageVersions YesRequireHackageIndex IgnorePreferredVersions
18+ . mkPackageName =<< head <$> liftIO getArgs
etc/commenter/latest-version/stack.yamlnew file+4
@@ -0,0 +1,4 @@
1+resolver:
2+ url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/18/18.yaml
3+packages:
4+- .
etc/commenter/src/lib.rs+91−9
@@ -1,9 +1,13 @@
1+use std::collections::{BTreeMap, BTreeSet};
1use std::fs::File;
2use std::fs::File;
2use std::io::{BufRead, BufReader, LineWriter, Lines, Write};
3use std::io::{BufRead, BufReader, LineWriter, Lines, Write};
3use std::path::Path;
4use std::path::Path;
5+use std::process::Command;
6+
7+use lazy_regex::regex;
4
8
5pub fn clear() {
9pub fn clear() {
6− handle(|loc, _lines| match loc {
10+ handle(true, |loc, _lines| match loc {
7 // Add empty array to keep yaml valid
11 // Add empty array to keep yaml valid
8 Location::Lib => vec![" []".to_owned()],
12 Location::Lib => vec![" []".to_owned()],
9 Location::Test | Location::Bench => vec![],
13 Location::Test | Location::Bench => vec![],
@@ -11,7 +15,7 @@ pub fn clear() {
11}
15}
12
16
13pub fn add(lib: Vec<String>, test: Vec<String>, bench: Vec<String>) {
17pub fn add(lib: Vec<String>, test: Vec<String>, bench: Vec<String>) {
14− handle(|loc, mut lines| {
18+ handle(true, |loc, mut lines| {
15 lines.extend(match loc {
19 lines.extend(match loc {
16 Location::Lib => lib.clone(),
20 Location::Lib => lib.clone(),
17 Location::Test => test.clone(),
21 Location::Test => test.clone(),
@@ -22,6 +26,82 @@ pub fn add(lib: Vec<String>, test: Vec<String>, bench: Vec<String>) {
22 })
26 })
23}
27}
24
28
29+pub fn outdated() {
30+ let mut all = vec![];
31+ handle(false, |_loc, lines| {
32+ all.extend(lines);
33+ vec![]
34+ });
35+ let mut map = BTreeMap::new();
36+ let mut support: BTreeMap<(String, String), BTreeSet<(String, String)>> = BTreeMap::new();
37+ for v in all.into_iter() {
38+ let caps = regex!("tried ([^ ]+)-([^,-]+),").captures(&v).unwrap();
39+ let package = caps.get(1).unwrap().as_str().to_owned();
40+ let version = caps.get(2).unwrap().as_str().to_owned();
41+ map.insert(package.clone(), version.clone());
42+
43+ if let Some(caps) = regex!("does not support: ([^ ]+)-([^-]+)").captures(&v) {
44+ let dep_package = caps.get(1).unwrap().as_str().to_owned();
45+ let dep_version = caps.get(2).unwrap().as_str().to_owned();
46+ let entry = support
47+ .entry((dep_package, dep_version))
48+ .or_default();
49+ entry.insert((package, version));
50+ }
51+ }
52+
53+ let entries = map.len() + support.len();
54+ let mut i = 0;
55+
56+ for (package, version) in map {
57+ if i % 100 == 0 {
58+ println!("{:02}%", ((i as f64 / entries as f64) * 100.0).floor());
59+ }
60+ i += 1;
61+ let latest = latest_version(&package);
62+ if version != latest {
63+ println!(
64+ "{} mismatch, snapshot: {}, hackage: {}",
65+ package, version, latest
66+ );
67+ }
68+ }
69+
70+ for ((package, version), dependents) in support {
71+ if i % 100 == 0 {
72+ println!("{:02}%", ((i as f64 / entries as f64) * 100.0).floor());
73+ }
74+ i += 1;
75+ let latest = latest_version(&package);
76+ if version != latest {
77+ println!(
78+ "{} mismatch, snapshot: {}, hackage: {}, dependents: {}",
79+ package,
80+ version,
81+ latest,
82+ dependents
83+ .into_iter()
84+ .map(|(p, v)| format!("{}-{}", p, v))
85+ .collect::<Vec<String>>()
86+ .join(", "),
87+ );
88+ }
89+ }
90+}
91+
92+fn latest_version(pkg: &str) -> String {
93+ String::from_utf8(
94+ Command::new("latest-version")
95+ .args([pkg])
96+ .output()
97+ .unwrap()
98+ .stdout,
99+ )
100+ .unwrap()
101+ .trim()
102+ .to_owned()
103+}
104+
25enum State {
105enum State {
26 LookingForLibBounds,
106 LookingForLibBounds,
27 ProcessingLibBounds,
107 ProcessingLibBounds,
@@ -32,9 +112,9 @@ enum State {
32 Done,
112 Done,
33}
113}
34
114
35−fn handle<F>(f: F)
115+fn handle<F>(write: bool, mut f: F)
36where
116where
37− F: Fn(Location, Vec<String>) -> Vec<String>,
117+ F: FnMut(Location, Vec<String>) -> Vec<String>,
38{
118{
39 let path = "build-constraints.yaml";
119 let path = "build-constraints.yaml";
40 let mut new_lines: Vec<String> = vec![];
120 let mut new_lines: Vec<String> = vec![];
@@ -100,13 +180,15 @@ where
100 }
180 }
101 }
181 }
102
182
183+ if write {
103− let file = File::create(path).unwrap();
184+ let file = File::create(path).unwrap();
104− let mut file = LineWriter::new(file);
185+ let mut file = LineWriter::new(file);
105
186
106− for line in new_lines {
187+ for line in new_lines {
107− file.write_all((line + "\n").as_bytes()).unwrap();
188+ file.write_all((line + "\n").as_bytes()).unwrap();
189+ }
190+ file.flush().unwrap();
108 }
191 }
109− file.flush().unwrap();
110}
192}
111
193
112enum Location {
194enum Location {
etc/commenter/src/main.rs+6
@@ -21,6 +21,7 @@ enum Header {
21enum Opt {
21enum Opt {
22 Clear,
22 Clear,
23 Add,
23 Add,
24+ Outdated,
24}
25}
25
26
26fn main() {
27fn main() {
@@ -28,6 +29,7 @@ fn main() {
28 match opt {
29 match opt {
29 Opt::Clear => clear(),
30 Opt::Clear => clear(),
30 Opt::Add => add(),
31 Opt::Add => add(),
32+ Opt::Outdated => outdated(),
31 }
33 }
32}
34}
33
35
@@ -35,6 +37,10 @@ fn clear() {
35 commenter::clear();
37 commenter::clear();
36}
38}
37
39
40+fn outdated() {
41+ commenter::outdated();
42+}
43+
38fn add() {
44fn add() {
39 let mut lib_exes: H = Default::default();
45 let mut lib_exes: H = Default::default();
40 let mut tests: H = Default::default();
46 let mut tests: H = Default::default();