diff --git a/commenter b/commenter index d2a1b93c..6fde28e9 100755 --- a/commenter +++ b/commenter @@ -1,20 +1,9 @@ #!/usr/bin/env bash -if ! command -v cargo +if ! command -v commenter &> /dev/null then - echo "Rust doesn't seem to be installed. https://rustup.rs/" + echo "commenter is not installed, get it from https://github.com/bergmark/commenter" exit 1 fi -if [ "$1" = "outdated" ]; -then - if ! command -v latest-version &> /dev/null - then - echo "This command requires latest-version in your PATH" - echo "Install it with: " - echo "stack install --stack-yaml etc/commenter/latest-version/stack.yaml" - exit 1 - fi -fi - -cargo run -q --release --manifest-path etc/commenter/Cargo.toml $@ +commenter $@ diff --git a/etc/commenter/.gitignore b/etc/commenter/.gitignore deleted file mode 100644 index 72b58cc3..00000000 --- a/etc/commenter/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/target -/comments.txt -/out.txt diff --git a/etc/commenter/Cargo.lock b/etc/commenter/Cargo.lock deleted file mode 100644 index 85dbdfe9..00000000 --- a/etc/commenter/Cargo.lock +++ /dev/null @@ -1,365 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "aho-corasick" -version = "0.7.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" -dependencies = [ - "memchr", -] - -[[package]] -name = "ansi_term" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" -dependencies = [ - "winapi", -] - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi", - "libc", - "winapi", -] - -[[package]] -name = "autocfg" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "clap" -version = "2.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" -dependencies = [ - "ansi_term", - "atty", - "bitflags", - "strsim", - "textwrap", - "unicode-width", - "vec_map", -] - -[[package]] -name = "commenter" -version = "0.2.0" -dependencies = [ - "lazy-regex", - "regex", - "serde", - "serde_yaml", - "structopt", -] - -[[package]] -name = "hashbrown" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" - -[[package]] -name = "heck" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" -dependencies = [ - "unicode-segmentation", -] - -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "indexmap" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223" -dependencies = [ - "autocfg", - "hashbrown", -] - -[[package]] -name = "lazy-regex" -version = "2.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "919a16773ebf2de27e95fc58460110932e55bb0780e23aa51fa5a6b59c9e2b3d" -dependencies = [ - "lazy-regex-proc_macros", - "once_cell", - "regex", -] - -[[package]] -name = "lazy-regex-proc_macros" -version = "2.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fbe6bf0a04af51c07976625d5007e75ed9b8b955befc21c77b3947733496e36" -dependencies = [ - "proc-macro2", - "quote", - "regex", - "syn", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.112" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" - -[[package]] -name = "linked-hash-map" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" - -[[package]] -name = "memchr" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" - -[[package]] -name = "once_cell" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - -[[package]] -name = "proc-macro2" -version = "1.0.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" -dependencies = [ - "unicode-xid", -] - -[[package]] -name = "quote" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47aa80447ce4daf1717500037052af176af5d38cc3e571d9ec1c7353fc10c87d" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "regex" -version = "1.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.6.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" - -[[package]] -name = "ryu" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" - -[[package]] -name = "serde" -version = "1.0.133" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97565067517b60e2d1ea8b268e59ce036de907ac523ad83a0475da04e818989a" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.133" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed201699328568d8d08208fdd080e3ff594e6c422e438b6705905da01005d537" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_yaml" -version = "0.8.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a521f2940385c165a24ee286aa8599633d162077a54bdcae2a6fd5a7bfa7a0" -dependencies = [ - "indexmap", - "ryu", - "serde", - "yaml-rust", -] - -[[package]] -name = "strsim" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" - -[[package]] -name = "structopt" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40b9788f4202aa75c240ecc9c15c65185e6a39ccdeb0fd5d008b98825464c87c" -dependencies = [ - "clap", - "lazy_static", - "structopt-derive", -] - -[[package]] -name = "structopt-derive" -version = "0.4.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" -dependencies = [ - "heck", - "proc-macro-error", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "syn" -version = "1.0.85" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a684ac3dcd8913827e18cd09a68384ee66c1de24157e3c556c9ab16d85695fb7" -dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", -] - -[[package]] -name = "textwrap" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -dependencies = [ - "unicode-width", -] - -[[package]] -name = "unicode-segmentation" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" - -[[package]] -name = "unicode-width" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" - -[[package]] -name = "unicode-xid" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" - -[[package]] -name = "vec_map" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "yaml-rust" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" -dependencies = [ - "linked-hash-map", -] diff --git a/etc/commenter/Cargo.toml b/etc/commenter/Cargo.toml deleted file mode 100644 index 4c57ad43..00000000 --- a/etc/commenter/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "commenter" -version = "0.2.0" -authors = ["Adam Bergmark "] -edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -lazy-regex = "2.2.1" -regex = "1.5.4" -serde = { version = "1.0.133", features = ["derive"] } -serde_yaml = "0.8.23" -structopt = "0.3.25" diff --git a/etc/commenter/README.md b/etc/commenter/README.md deleted file mode 100644 index 29b7ed7e..00000000 --- a/etc/commenter/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Helps automate mass-disabling of packages in Stackage's build-constraint.yaml. - -See CURATORS.md for usage instructions. diff --git a/etc/commenter/commenter b/etc/commenter/commenter deleted file mode 100755 index 2380d69d..00000000 --- a/etc/commenter/commenter +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -cargo run -- $@ diff --git a/etc/commenter/latest-version/LICENSE b/etc/commenter/latest-version/LICENSE deleted file mode 100644 index 89f25d28..00000000 --- a/etc/commenter/latest-version/LICENSE +++ /dev/null @@ -1,30 +0,0 @@ -Copyright Adam Bergmark (c) 2021 - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - - * Neither the name of Author name here nor the names of other - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/etc/commenter/latest-version/README.md b/etc/commenter/latest-version/README.md deleted file mode 100644 index d4dbf071..00000000 --- a/etc/commenter/latest-version/README.md +++ /dev/null @@ -1 +0,0 @@ -# latest-version diff --git a/etc/commenter/latest-version/Setup.hs b/etc/commenter/latest-version/Setup.hs deleted file mode 100644 index 9a994af6..00000000 --- a/etc/commenter/latest-version/Setup.hs +++ /dev/null @@ -1,2 +0,0 @@ -import Distribution.Simple -main = defaultMain diff --git a/etc/commenter/latest-version/cabal.project b/etc/commenter/latest-version/cabal.project deleted file mode 100644 index d5d2dcf1..00000000 --- a/etc/commenter/latest-version/cabal.project +++ /dev/null @@ -1,6 +0,0 @@ -source-repository-package - type: git - location: git://github.com/commercialhaskell/pantry.git - -packages: ./latest-version.cabal -with-compiler: ghc-8.10.7 diff --git a/etc/commenter/latest-version/latest-version.cabal b/etc/commenter/latest-version/latest-version.cabal deleted file mode 100644 index 1be4e493..00000000 --- a/etc/commenter/latest-version/latest-version.cabal +++ /dev/null @@ -1,23 +0,0 @@ -name: latest-version -version: 0.1.0.0 -homepage: https://github.com/githubuser/latest-version#readme -license: BSD3 -license-file: LICENSE -author: Adam Bergmark -maintainer: adam@bergmark.nl -copyright: 2021 Adam Bergmark -category: Web -build-type: Simple -cabal-version: >=1.10 -extra-source-files: README.md - -executable latest-version - ghc-options: -Wall -threaded - hs-source-dirs: src - main-is: Main.hs - default-language: Haskell2010 - build-depends: base >= 4.7 && < 5 - , pantry - , Cabal - , rio - , containers diff --git a/etc/commenter/latest-version/src/Main.hs b/etc/commenter/latest-version/src/Main.hs deleted file mode 100644 index cae07be0..00000000 --- a/etc/commenter/latest-version/src/Main.hs +++ /dev/null @@ -1,28 +0,0 @@ -module Main where - -import Data.List -import Distribution.Types.PackageName -import Distribution.Types.Version -import Pantry -import RIO -import System.Environment -import qualified Data.Map as Map - -main :: IO () -main = do - args <- getArgs - (onlyVersion, packages) <- pure $ case args of - "only-version" : packages -> (True, packages) - packages -> (False, packages) - runPantryApp $ liftIO . putStrLn . unlines_ =<< mapM (latestVersion onlyVersion) packages - where - -- unlines adds an extra trailing newline which can be annoying... - unlines_ = intercalate "\n" - -latestVersion :: (HasPantryConfig env, HasLogFunc env) => Bool -> String -> RIO env String -latestVersion onlyVersion name = fmap (displayVersion onlyVersion) . getVersion . mkPackageName $ name - where - showVersion = intercalate "." . map show . versionNumbers . fst . head . Map.toDescList - getVersion = getHackagePackageVersions YesRequireHackageIndex UsePreferredVersions - displayVersion True v = showVersion v - displayVersion False v = name <> "-" <> showVersion v diff --git a/etc/commenter/latest-version/stack.yaml b/etc/commenter/latest-version/stack.yaml deleted file mode 100644 index ef03d7c0..00000000 --- a/etc/commenter/latest-version/stack.yaml +++ /dev/null @@ -1,4 +0,0 @@ -resolver: - url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/18/18.yaml -packages: -- . diff --git a/etc/commenter/latest-version/stack.yaml.lock b/etc/commenter/latest-version/stack.yaml.lock deleted file mode 100644 index cc26a008..00000000 --- a/etc/commenter/latest-version/stack.yaml.lock +++ /dev/null @@ -1,13 +0,0 @@ -# This file was autogenerated by Stack. -# You should not edit this file by hand. -# For more information, please see the documentation at: -# https://docs.haskellstack.org/en/stable/lock_files - -packages: [] -snapshots: -- completed: - size: 586296 - url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/18/18.yaml - sha256: 63539429076b7ebbab6daa7656cfb079393bf644971156dc349d7c0453694ac2 - original: - url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/18/18.yaml diff --git a/etc/commenter/src/lib.rs b/etc/commenter/src/lib.rs deleted file mode 100644 index 930c0532..00000000 --- a/etc/commenter/src/lib.rs +++ /dev/null @@ -1,574 +0,0 @@ -use std::collections::{BTreeMap, BTreeSet}; -use std::error::Error; -use std::fmt; -use std::fs::File; -use std::io::{BufRead, BufReader, LineWriter, Lines, Write}; -use std::path::Path; -use std::process::Command; - -use lazy_regex::regex; -use serde::{Deserialize, Deserializer}; - -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 - }); -} - -enum VersionTag { - Manual(Version), - Auto(Version), -} - -impl VersionTag { - fn tag(&self) -> &'static str { - match self { - VersionTag::Manual(_) => "manual", - VersionTag::Auto(_) => "auto", - } - } - - fn version(&self) -> &Version { - match self { - VersionTag::Manual(s) => s, - VersionTag::Auto(s) => s, - } - } -} - -pub fn outdated() { - let mut all: Vec = vec![]; - let (versioned, disabled) = handle(false, |_loc, lines| { - all.extend(lines); - vec![] - }); - - for DisabledPackage { package } in disabled { - println!("WARN: {package} is disabled without a noted version"); - } - - let mut map: BTreeMap = BTreeMap::new(); - for VersionedPackage { package, version } in versioned { - map.insert(package, VersionTag::Manual(version)); - } - let mut support: BTreeMap<(Package, Version), BTreeSet<(Package, Version)>> = BTreeMap::new(); - for v in all.into_iter() { - let caps = regex!("tried ([^ ]+)-([^,-]+),").captures(&v).unwrap(); - let package = Package(caps.get(1).unwrap().as_str().to_owned()); - let version = Version(caps.get(2).unwrap().as_str().to_owned()); - map.insert(package.clone(), VersionTag::Auto(version.clone())); - - if let Some(caps) = regex!("does not support: ([^ ]+)-([^-]+)").captures(&v) { - let dep_package = Package(caps.get(1).unwrap().as_str().to_owned()); - let dep_version = Version(caps.get(2).unwrap().as_str().to_owned()); - let entry = support.entry((dep_package, dep_version)).or_default(); - entry.insert((package, version)); - } - } - - let latest_versions = { - let mut packages: Vec = map.iter().map(|(package, _)| package.clone()).collect(); - packages.append( - &mut support - .iter() - .map(|((package, _), _)| package.clone()) - .collect(), - ); - latest_version(packages.into_iter()) - }; - - for (package, version) in map { - if is_boot(&package) { - continue; - } - let latest = latest_versions.get(&package).unwrap(); - if version.version() != latest { - println!( - "{package} mismatch, {tag}: {version}, hackage: {latest}", - tag = version.tag(), - version = version.version(), - ); - } - } - - for ((package, version), dependents) in support { - if is_boot(&package) { - continue; - } - - let latest = latest_versions.get(&package).unwrap(); - if &version != latest { - let max = 3; - let dependents_stripped = dependents.len().saturating_sub(max); - let dependents = dependents - .into_iter() - .take(max) - .map(|(p, v)| format!("{p}-{v}")) - .collect::>() - .join(", "); - let dependents = if dependents_stripped > 0 { - format!("{dependents} and {dependents_stripped} more") - } else { - dependents - }; - - println!( - "{package} mismatch, snapshot: {version}, hackage: {latest}, dependents: {dependents}" - ); - } - } -} - -fn is_boot(package: &Package) -> bool { - [ - "Cabal", - "base", - "bytestring", - "containers", - "containers", - "directory", - "filepath", - "deepseq", - "ghc", - "ghc-bignum", - "ghc-boot", - "ghc-boot-th", - "ghc-prim", - "ghc-lib-parser", // not a boot lib, but tied to the GHC version. - "integer-gmp", - "process", - "stm", - "template-haskell", - "text", - "time", - ] - .contains(&&*package.0) -} - -fn latest_version(packages: impl Iterator) -> BTreeMap { - String::from_utf8( - Command::new("latest-version") - .args(packages.map(|p| p.0)) - .output() - .expect("Could not find latest-version in PATH") - .stdout, - ) - .unwrap() - .trim() - .to_owned() - .lines() - .map(|s| { - let VersionedPackage { package, version } = parse_versioned_package_canonical(s).unwrap(); - (package, version) - }) - .collect() -} - -enum State { - LookingForLibBounds, - ProcessingLibBounds, - LookingForTestBounds, - ProcessingTestBounds, - LookingForBenchBounds, - ProcessingBenchBounds, - Done, -} - -#[derive(PartialEq, Eq, Debug)] -struct VersionedPackage { - package: Package, - version: Version, -} - -fn parse_versioned_package_canonical(s: &str) -> Option { - if let Some(caps) = regex!(r#"^(.+)-([\d.]+)$"#).captures(s) { - let package = Package(caps.get(1).unwrap().as_str().to_owned()); - let version = Version(caps.get(2).unwrap().as_str().to_owned()); - Some(VersionedPackage { package, version }) - } else { - None - } -} - -fn parse_versioned_package_yaml(s: &str) -> Option { - if let Some(caps) = regex!(r#"- *([^ ]+) < *0 *# *([\d.]+)"#).captures(s) { - let package = Package(caps.get(1).unwrap().as_str().to_owned()); - let version = Version(caps.get(2).unwrap().as_str().to_owned()); - Some(VersionedPackage { package, version }) - } else if let Some(caps) = regex!(r#"- *([^ ]+) *# *([\d.]+)"#).captures(s) { - let package = Package(caps.get(1).unwrap().as_str().to_owned()); - let version = Version(caps.get(2).unwrap().as_str().to_owned()); - Some(VersionedPackage { package, version }) - } else { - None - } -} - -struct DisabledPackage { - package: String, -} - -fn parse_disabled_package(s: &str) -> Option { - if !regex!(r#"- *([^ ]+) < *0 *# tried"#).is_match(s) { - if let Some(caps) = regex!(r#"- *([^ ]+) < *0 *# *\d*[^\d ]"#).captures(s) { - let package = caps.get(1).unwrap().as_str().to_owned(); - Some(DisabledPackage { package }) - } else { - None - } - } else { - None - } -} - -fn handle(write: bool, mut f: F) -> (Vec, Vec) -where - F: FnMut(Location, Vec) -> Vec, -{ - let path = "build-constraints.yaml"; - let mut new_lines: Vec = vec![]; - let mut versioned_packages: Vec = vec![]; - let mut disabled_packages: Vec = vec![]; - - let mut state = State::LookingForLibBounds; - let mut buf = vec![]; - for line in read_lines(path).map(|s| s.unwrap()) { - if let Some(versioned_package) = parse_versioned_package_yaml(&line) { - versioned_packages.push(versioned_package); - } else if let Some(disabled_package) = parse_disabled_package(&line) { - disabled_packages.push(disabled_package); - } - - 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(); - } - - (versioned_packages, disabled_packages) -} - -enum Location { - Lib, - Test, - Bench, -} - -fn read_lines

(filename: P) -> Lines> -where - P: AsRef, -{ - let file = File::open(filename).unwrap(); - BufReader::new(file).lines() -} - -#[derive(Deserialize)] -struct SnapshotYaml { - // flags: BTreeMap>, - // publish_time - packages: Vec, - // hidden - // resolver -} - -#[derive(Deserialize)] -struct SnapshotPackage { - hackage: PackageWithVersionAndSha, - // pantry-tree -} - -#[derive(PartialOrd, Ord, PartialEq, Eq, Clone, Debug)] -struct Package(String); - -impl fmt::Display for Package { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) - } -} - -#[derive(Clone, PartialOrd, Ord, PartialEq, Eq, Debug)] -struct Version(String); - -impl fmt::Display for Version { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) - } -} - -// zstd-0.1.3.0@sha256:4c0a372251068eb6086b8c3a0a9f347488f08b570a7705844ffeb2c720c97223,3723 -struct PackageWithVersionAndSha { - name: Package, - version: Version, -} - -impl<'de> serde::Deserialize<'de> for PackageWithVersionAndSha { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let s: String = String::deserialize(deserializer)?; - let r = regex!(r#"^(.+?)-([.\d]+)@sha256:[\da-z]+,\d+$"#); - if let Some(caps) = r.captures(&s) { - let name = Package(caps.get(1).unwrap().as_str().to_owned()); - let version = Version(caps.get(2).unwrap().as_str().to_owned()); - Ok(Self { name, version }) - } else { - Err(serde::de::Error::invalid_value( - serde::de::Unexpected::Other(&s), - &"Invalid PackageVersionWithSha", - )) - } - } -} - -fn yaml_from_file>(path: P) -> Result> -where - A: for<'de> Deserialize<'de>, -{ - let file = File::open(path)?; - let reader = BufReader::new(file); - let u = serde_yaml::from_reader(reader)?; - Ok(u) -} - -struct Snapshot { - packages: BTreeMap>, -} - -#[derive(Clone, Copy)] -enum Diff { - Left(A), - Right(A), - Both(A, A), -} - -fn to_diff(a: SnapshotYaml, b: SnapshotYaml) -> Snapshot { - let mut packages = BTreeMap::new(); - for s in a.packages { - let package = s.hackage; - packages.insert(package.name, Diff::Left(package.version)); - } - for s in b.packages { - let package = s.hackage; - let name = package.name; - let version = package.version; - if let Some(a) = packages.remove(&name) { - match a { - Diff::Left(a) => { - if a == version { - packages.remove(&name); - } else { - packages.insert(name, Diff::Both(a, version)); - } - } - _ => unreachable!(), - } - } else { - packages.insert(name, Diff::Right(version)); - } - } - - Snapshot { packages } -} - -pub fn diff_snapshot(a: String, b: String) { - let diff = to_diff(yaml_from_file(a).unwrap(), yaml_from_file(b).unwrap()); - for (name, diff) in diff.packages { - let s = match diff { - Diff::Left(a) => format!("- {name}-{a}"), - Diff::Right(b) => format!("+ {name}-{b}"), - Diff::Both(a, b) => format!("~ {name}-{a} -> {b}"), - }; - println!("{s}"); - } -} - -#[derive(PartialEq, Eq, Debug)] -struct DisabledTransitively { - child: VersionedPackage, - parent: Package, -} - -fn parse_disabled_transitviely(s: &str) -> Option { - let r = regex!( - r#"- *([^ ]+) < *0 *# tried [^ ]+-([\d.]+), but its \*[^*]+\* requires the disabled package: ([^ ]+)"# - ); - if let Some(caps) = r.captures(s) { - let package = Package(caps.get(1).unwrap().as_str().to_owned()); - let version = Version(caps.get(2).unwrap().as_str().to_owned()); - let parent = Package(caps.get(3).unwrap().as_str().to_owned()); - Some(DisabledTransitively { - child: VersionedPackage { package, version }, - parent, - }) - } else { - None - } -} - -#[test] -fn test_parse_disabled_transitviely() { - let s = "- Network-NineP < 0 # tried Network-NineP-0.4.7.1, but its *library* requires the disabled package: mstate"; - assert_eq!( - parse_disabled_transitviely(s), - Some(DisabledTransitively { - child: VersionedPackage { - package: Package("Network-NineP".to_owned()), - version: Version("0.4.7.1".to_owned()) - }, - parent: Package("mstate".to_owned()), - }) - ) -} - -type M = BTreeMap, Option)>; - -pub fn disabled() { - let mut disabled_transitively: Vec = vec![]; - handle(false, |loc, lines| { - match loc { - Location::Lib => disabled_transitively.extend( - lines - .into_iter() - .map(|line| parse_disabled_transitviely(&line)) - .flatten() - .collect::>(), - ), - Location::Test | Location::Bench => (), - } - vec![] - }); - - let mut packages: BTreeSet = BTreeSet::new(); - let mut disabled: M = BTreeMap::new(); - - for DisabledTransitively { child, parent } in disabled_transitively { - packages.insert(child.package.clone()); - packages.insert(parent.clone()); - disabled - .entry(child.package.clone()) - .or_insert_with(|| (vec![], None)); - let t = disabled.entry(parent).or_insert_with(|| (vec![], None)); - t.0.push(child); - } - - let mut packages_len = packages.len(); - while packages_len > 0 { - let mut new_packages: BTreeSet = BTreeSet::new(); - for package in packages { - let (_, count) = disabled.get(&package).unwrap(); - if count.is_none() && !process(&package, &mut disabled) { - new_packages.insert(package.clone()); - } - } - packages = new_packages; - packages_len = packages.len(); - } - - let mut v: Vec<_> = disabled - .into_iter() - .map(|(package, (_, count))| (count, package)) - .collect(); - v.sort(); - for (count, package) in v { - let count = count.unwrap(); - if count != 0 { - println!("{package} is disabled with {count} dependents"); - } - } -} - -fn process(package: &Package, m: &mut M) -> bool { - let (children, count) = m.get(package).unwrap(); - assert!(count.is_none(), "{:?}", package); - let mut count = 0; - for child in children { - let (_, child_count) = m - .get(&child.package) - .unwrap_or_else(|| panic!("{}", child.package)); - match child_count { - None => return false, - Some(i) => count += 1 + i, - } - } - m.entry(package.clone()) - .and_modify(|tup| tup.1 = Some(count)) - .or_insert_with(|| panic!("{}", package)); - true -} diff --git a/etc/commenter/src/main.rs b/etc/commenter/src/main.rs deleted file mode 100644 index a9c1ea3e..00000000 --- a/etc/commenter/src/main.rs +++ /dev/null @@ -1,231 +0,0 @@ -use std::collections::HashMap; -use std::io::{self, BufRead}; - -use lazy_regex::regex; -use regex::Regex; -use structopt::StructOpt; - -type H = HashMap>; - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -enum Header { - Versioned { package: String, version: String }, - Missing { package: String }, -} - -#[derive(Debug, StructOpt)] -#[structopt( - name = "commenter", - about = "Automates generation of bounds in build-constraints.yaml" -)] -enum Opt { - Add, - Clear, - DiffSnapshot { a: String, b: String }, - Disabled, - Outdated, -} - -fn main() { - let opt = Opt::from_args(); - match opt { - Opt::Add => add(), - Opt::Clear => commenter::clear(), - Opt::DiffSnapshot { a, b } => commenter::diff_snapshot(a, b), - Opt::Disabled => commenter::disabled(), - Opt::Outdated => commenter::outdated(), - } -} - -#[test] -fn test_package_with_digit_after_dash() { - let line = "- [ ] captcha-2captcha-0.1.0.0 (==0.1.*). Edward Yang @qwbarch. @qwbarch. Used by: library"; - let p = parse_package_with_component(line).unwrap(); - assert_eq!( - p, - PackageWithComponent { - package: "captcha-2captcha", - version: "0.1.0.0", - component: "library", - } - ); -} - -#[derive(Debug, PartialEq, Eq)] -struct PackageWithComponent<'a> { - package: &'a str, - version: &'a str, - component: &'a str, -} - -fn parse_package_with_component(s: &str) -> Option { - let package = regex!( - r#"^- \[ \] (?P[0-9a-zA-z][a-zA-Z]([a-zA-z0-9.-]*?))-(?P(\d+(\.\d+)*)) \(.+?Used by: (?P.+)$"# - ); - if let Some(cap) = package.captures(s) { - let package = cap.name("package").unwrap().as_str(); - let version = cap.name("version").unwrap().as_str(); - let component = cap.name("component").unwrap().as_str(); - Some(PackageWithComponent { - package, - version, - component, - }) - } else { - None - } -} - -#[test] -fn test_parse_header_versioned() { - let s = "aeson-2.0.3.0 ([changelog](http://hackage.haskell.org/package/aeson-2.0.3.0/changelog)) (Adam Bergmark @bergmark, Stackage upper bounds) is out of bounds for:"; - let p = parse_header_versioned(s).unwrap(); - assert_eq!( - p, - Header::Versioned { - package: "aeson".to_owned(), - version: "2.0.3.0".to_owned() - } - ) -} - -fn parse_header_versioned(s: &str) -> Option

{ - let header_versioned = regex!( - r#"^(?P[\da-zA-z][a-zA-Z]([a-zA-z0-9.-]*?))-(?P(\d+(\.\d+)*)).+?is out of bounds for:$"# - ); - if let Some(cap) = header_versioned.captures(s) { - let package = cap.name("package").unwrap().as_str().to_owned(); - let version = cap.name("version").unwrap().as_str().to_owned(); - Some(Header::Versioned { package, version }) - } else { - None - } -} - -fn add() { - let mut lib_exes: H = Default::default(); - let mut tests: H = Default::default(); - let mut benches: H = Default::default(); - let mut last_header: Option
= None; - - let header_missing = - regex!(r#"^(?P[\da-zA-z][a-zA-Z]([a-zA-z0-9.-]*)).+?depended on by:$"#); - - // Ignore everything until the bounds issues show up. - let mut process_line = false; - - for line in io::stdin().lock().lines().flatten() { - if is_reg_match(&line, regex!(r#"^\s*$"#)) { - // noop - } else if line == "curator: Snapshot dependency graph contains errors:" { - process_line = true; - } else if !process_line { - println!("[INFO] {line}"); - } else if let Some(PackageWithComponent { - package, - version, - component, - }) = parse_package_with_component(&line) - { - let root = last_header.clone().unwrap(); - match component { - "library" | "executable" => { - insert(&mut lib_exes, root, package, version, component) - } - "benchmark" => insert(&mut benches, root, package, version, "benchmarks"), - "test-suite" => insert(&mut tests, root, package, version, component), - _ => panic!("Bad component: {}", component), - } - } else if let Some(header_versioned) = parse_header_versioned(&line) { - last_header = Some(header_versioned); - } else if let Some(cap) = header_missing.captures(&line) { - let package = cap.name("package").unwrap().as_str().to_owned(); - last_header = Some(Header::Missing { package }); - } else { - panic!("Unhandled: {:?}", line); - } - } - - let mut auto_lib_exes = vec![]; - let mut auto_tests = vec![]; - let mut auto_benches = vec![]; - - if !lib_exes.is_empty() { - println!("\nLIBS + EXES\n"); - } - for (header, packages) in lib_exes { - for (package, version, component) in packages { - let s = printer(" ", &package, true, &version, &component, &header); - println!("{s}"); - auto_lib_exes.push(s); - } - } - - if !tests.is_empty() { - println!("\nTESTS\n"); - } - for (header, packages) in tests { - for (package, version, component) in packages { - let s = printer(" ", &package, false, &version, &component, &header); - println!("{s}"); - auto_tests.push(s); - } - } - - if !benches.is_empty() { - println!("\nBENCHMARKS\n"); - } - for (header, packages) in benches { - for (package, version, component) in packages { - let s = printer(" ", &package, false, &version, &component, &header); - println!("{s}"); - auto_benches.push(s); - } - } - - println!(); - println!( - "Adding {lib_exes} libs, {tests} tests, {benches} benches to build-constraints.yaml", - lib_exes = auto_lib_exes.len(), - tests = auto_tests.len(), - benches = auto_benches.len() - ); - commenter::add(auto_lib_exes, auto_tests, auto_benches); -} - -fn printer( - indent: &str, - package: &str, - lt0: bool, - version: &str, - component: &str, - header: &Header, -) -> String { - let lt0 = if lt0 { " < 0" } else { "" }; - format!( - "{indent}- {package}{lt0} # tried {package}-{version}, but its *{component}* {cause}", - cause = match header { - Header::Versioned { package, version } => format!( - "does not support: {package}-{version}", - package = package, - version = version - ), - Header::Missing { package } => format!( - "requires the disabled package: {package}", - package = package - ), - }, - ) -} - -fn insert(h: &mut H, header: Header, package: &str, version: &str, component: &str) { - (*h.entry(header).or_insert_with(Vec::new)).push(( - package.to_owned(), - version.to_owned(), - component.to_owned(), - )); -} - -fn is_reg_match(s: &str, r: &Regex) -> bool { - r.captures(s).is_some() -}