Merge remote-tracking branch 'origin/master' into ghc-9.2

This commit is contained in:
Adam Bergmark 2022-03-12 23:40:13 +01:00
commit de33001399
19 changed files with 1019 additions and 2268 deletions

View File

@ -317,7 +317,7 @@ First run `build.sh` to regenerate updated `ltsXX/work/constraints.yaml` and `lt
For an LTS minor bump, you'll typically want to:
* Add constraints to package `range:` fields _under_ the `source:` field in that `constraints.yaml`, and edit `snapshot-incomplete.yaml` to change the version used for that package, if necessary.
* Add constraints to package `range:` fields _under_ the `source:` field in that `constraints.yaml` (should not be necessary normally to edit `snapshot-incomplete.yaml` to change the version used for that package).
* Add new packages to the `constraints.yaml` file
* Test, benchmark, haddock failures can also be added to package fields in the `constraints.yaml` if necessary, though it should be avoided if possible for LTS.
@ -422,20 +422,16 @@ errors for builds, tests and benchmarks.
### Large scale enabling/disabling of packages
`etc/commenter` is a binary that mostly automates the translation of
`./check` errors into lines that go into `build-constraints.yaml`. It
can only handle bounds issues, compilation issues still need to be
handled manually.
It disables all offending packages/test suites/benchmarks, so it is
only meant to be used when we close bounds issues and want to disable
packages, and when upgrading GHC.
`etc/commenter` is a binary that automates `build-constraints.yaml` workflows.
#### Setup
This is currently a rust program, You can install the rust toolchain
by using [rustup](https://rustup.rs/).
Then `cargo install --locked --path etc/commenter`
For some commands you also need etc/commenter/latest-version installed.
```
stack install --stack-yaml etc/commenter/latest-version/stack.yaml
```
#### Example usage
@ -456,7 +452,7 @@ testing-feat (GHC 9 bounds issues, Grandfathered dependencies) (not present) dep
Now run:
```
./check 2>&1 >/dev/null | commenter add
./check 2>&1 >/dev/null | ./commenter add
```
You will get this output:
@ -483,8 +479,8 @@ Re-run this command until no more packages are disabled.
We can periodically remove all packages under the bounds sections and then re-run the disabling flow above until we get a clean plan. This will automatically pick up packages that have been fixed.
```
commenter clear
./check 2>&1 >/dev/null | commenter add
./commenter clear
./check 2>&1 >/dev/null | ./commenter add
```
Repeat the second command until no updates are made to build-constraints.yaml.
@ -493,7 +489,7 @@ Repeat the second command until no updates are made to build-constraints.yaml.
Run `stack update` before doing this.
`commenter outdated` looks through all bounds issues and library
`./commenter outdated` looks through all bounds issues and library
compilation failures and compares the marked version with the latest hackage release. Example output is
```
@ -504,7 +500,7 @@ aeson mismatch, auto: 1.5.6.0, hackage: 2.0.2.0
where "manual" means the bound was added manually by a curator,
perhaps due to a compilation failure so we could try re-enabling the
package. "auto" means it's part of the sections generated by
`commenter`, to update that run the `Re-enabling` step as documented
`./commenter`, to update that run the `Re-enabling` step as documented
above.
`outdated` only finds packages that are in the auto generated
@ -520,7 +516,7 @@ To diff existing snapshots, or to evaluate changes before they end up
in a snapshot you can run:
```
commenter diff-snapshot <old-snapshot.yaml> <new-snapshot.yaml>
./commenter diff-snapshot <old-snapshot.yaml> <new-snapshot.yaml>
```
Existing snapshots can be retrieved from https://github.com/commercialhaskell/stackage-snapshots. Preliminary snapshots can be generated by running relevant parts of `automated/build.sh`, at the time of writing:
@ -533,6 +529,50 @@ TARGET=nightly-2021-01-14 \ # the date doesn't matter
curator snapshot
```
#### Pinging maintainers after disabling packages
After lifting a bound We often have to disable additional packages due
to compilation failures. `affected` figures out which packages have
been disabled and which maintainers are affected. Note that this does
not handle disabled test suites and benchmarks as the snapshots don't
contain this information.
```
./commenter affected <old-snapshot.yaml> <new-snapshot.yaml>
```
E.g.:
```
$ commenter affected ../stackage-snapshots/nightly/2022/1/2.yaml ../stackage-snapshots/nightly/2022/2/7.yaml
```
```
alg-0.2.13.1: Matthew Farkas-Dyck <strake888@gmail.com> @strake
butter-0.1.0.6: Matthew Ahrens <matt.p.ahrens@gmail.com> @mpahrens
category-0.2.5.0: Matthew Farkas-Dyck <strake888@gmail.com> @strake
constraint-0.1.4.0: Matthew Farkas-Dyck <strake888@gmail.com> @strake
dl-fedora-0.9.2: Jens Petersen <juhpetersen@gmail.com> @juhp
foldable1-0.1.0.0: Matthew Farkas-Dyck <strake888@gmail.com> @strake
gitlab-haskell-0.3.2.0: Rob Stewart <robstewart57@gmail.com> @robstewart57
hslua-module-doclayout-1.0.0: Albert Krewinkel <albert+stackage@zeitkraut.de> @tarleb
util-0.1.17.1: Matthew Farkas-Dyck <strake888@gmail.com> @strake
wai-middleware-auth-0.2.5.1: Alexey Kuleshevich <lehins@yandex.ru> @lehins
yesod-csp-0.2.5.0: Bob Long <robertjflong@gmail.com> @bobjflong
```
#### Finding disabled packages with lots of dependents
`./commenter disabled` prints the number of transitive dependents a disabled package has. Low hanging fruit to get a lot of packages included again.
Example output:
```
[...]
stringable is disabled with 10 dependents
llvm-hs is disabled with 12 dependents
th-data-compat is disabled with 12 dependents
amazonka-core is disabled with 96 dependents
gogol-core is disabled with 96 dependents
```
## Adding new curators
1. Add public ssh key to `~/.ssh/authorized_keys` on build server

View File

@ -0,0 +1,3 @@
FROM $DOCKER_REPO:lts-18.26
ARG STACK_VERSION=2.7.5
RUN wget -qO- https://github.com/commercialhaskell/stack/releases/download/v$STACK_VERSION/stack-$STACK_VERSION-linux-x86_64.tar.gz | tar xz --wildcards --strip-components=1 -C /usr/local/bin '*/stack'

View File

@ -0,0 +1,90 @@
FROM ubuntu:18.04
LABEL maintainer="manny@fpcomplete.com"
ARG GHC_VERSION=8.10.7
ARG LTS_SLUG=lts-18.9
ARG PID1_VERSION=0.1.2.0
ARG STACK_VERSION=2.7.3
ARG CUDA_VERSION=10.0
ARG JVM_PATH=/usr/lib/jvm/java-8-openjdk-amd64
ARG LLVM_PATH=/usr/lib/llvm-7
ARG BOOTSTRAP_COMMIT=b1d40e112040a7f44eff47a9fafb6937f5d02dff
ARG DEBIAN_FRONTEND=noninteractive
ARG VARIANT=build
ARG STACK_ROOT=/home/stackage/.stack
#
# Set encoding to UTF-8 and PATH to find GHC and cabal/stack-installed binaries.
#
ENV LANG=C.UTF-8 \
LC_ALL=C.UTF-8 \
PATH=/root/.local/bin:/usr/local/cuda-$CUDA_VERSION/bin:$STACK_ROOT/programs/x86_64-linux/ghc-$GHC_VERSION/bin:$PATH \
CUDA_PATH=/usr/local/cuda-$CUDA_VERSION \
CPATH=$JVM_PATH/include:$JVM_PATH/include/linux:$LLVM_PATH/include
#
# Install pre-requisites
#
RUN apt-get update && \
apt-get install -y --no-install-recommends \
wget netbase ca-certificates g++ gcc libc6-dev libffi-dev libgmp-dev \
make xz-utils zlib1g-dev git gnupg libtinfo-dev jq && \
rm -rf /var/lib/apt/lists/*
#
# Use Stackage's debian-bootstrap.sh script to install system libraries and
# tools required to build any Stackage package.
# Re-installs 'stack' *after* running debian-bootstrap.sh since that may have
# installed a different version.
# In the case of 'small' image, just install Stack and GHC.
#
RUN if [ "$VARIANT" != "small" ]; then \
wget -qO- https://raw.githubusercontent.com/fpco/stackage/$BOOTSTRAP_COMMIT/debian-bootstrap.sh | sed "s/^GHCVER=9.0.1$/GHCVER=$GHC_VERSION/" | GHCVER=$GHC_VERSION bash; \
fi && \
wget -qO- https://github.com/commercialhaskell/stack/releases/download/v$STACK_VERSION/stack-$STACK_VERSION-linux-x86_64.tar.gz | tar xz --wildcards --strip-components=1 -C /usr/bin '*/stack' && \
if [ "$VARIANT" = "small" ]; then \
stack setup --resolver ghc-$GHC_VERSION; \
fi && \
rm -rf /var/lib/apt/lists/* && \
cd $STACK_ROOT && \
find . -type f -not -path "./programs/x86_64-linux/ghc-$GHC_VERSION/*" -exec rm '{}' \; && \
find . -type d -print0 |sort -rz |xargs -0 rmdir 2>/dev/null || true
#
# Configure Stack to use the GHC installed in the Docker image rather than installing its own
#
RUN mkdir /etc/stack/ && \
echo "system-ghc: true" >/etc/stack/config.yaml
#
# Use 'stack' to install basic Haskell tools like alex, happy, and cpphs. We
# remove most of the STACK_ROOT afterward to save space, but keep the 'share'
# files that some of these tools require.
#
RUN stack --resolver=$LTS_SLUG --local-bin-path=/usr/bin install \
happy alex cpphs gtk2hs-buildtools hscolour hlint hindent && \
cd $STACK_ROOT && \
find . -type f -not -path './snapshots/*/share/*' -and -not -path "./programs/x86_64-linux/ghc-$GHC_VERSION/*" -exec rm '{}' \; && \
find . -type d -print0 |sort -rz |xargs -0 rmdir 2>/dev/null || true
#
# Install 'pid1' init daemon
#
RUN wget -O- "https://github.com/fpco/pid1/releases/download/v$PID1_VERSION/pid1-$PID1_VERSION-linux-x86_64.tar.gz" | tar xzf - -C /usr/local && \
chown root:root /usr/local/sbin && \
chown root:root /usr/local/sbin/pid1
#
# Set up pid1 entrypoint and default command
#
ENTRYPOINT ["/usr/local/sbin/pid1"]
CMD ["bash"]

File diff suppressed because it is too large Load Diff

9
commenter Executable file
View File

@ -0,0 +1,9 @@
#!/usr/bin/env bash
if ! command -v commenter &> /dev/null
then
echo "commenter is not installed, get it from https://github.com/bergmark/commenter"
exit 1
fi
commenter $@

View File

@ -1,3 +0,0 @@
/target
/comments.txt
/out.txt

365
etc/commenter/Cargo.lock generated
View File

@ -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",
]

View File

@ -1,14 +0,0 @@
[package]
name = "commenter"
version = "0.2.0"
authors = ["Adam Bergmark <adam@bergmark.nl>"]
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"

View File

@ -1,3 +0,0 @@
Helps automate mass-disabling of packages in Stackage's build-constraint.yaml.
See CURATORS.md for usage instructions.

View File

@ -1,2 +0,0 @@
#!/bin/bash
cargo run -- $@

View File

@ -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.

View File

@ -1 +0,0 @@
# latest-version

View File

@ -1,2 +0,0 @@
import Distribution.Simple
main = defaultMain

View File

@ -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

View File

@ -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
hs-source-dirs: src
main-is: Main.hs
default-language: Haskell2010
build-depends: base >= 4.7 && < 5
, pantry
, Cabal
, rio
, containers

View File

@ -1,18 +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 =
runPantryApp $
liftIO . putStrLn
. intercalate "." . map show . versionNumbers
. fst . head . Map.toDescList
=<< getHackagePackageVersions YesRequireHackageIndex IgnorePreferredVersions
. mkPackageName =<< head <$> liftIO getArgs

View File

@ -1,4 +0,0 @@
resolver:
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/18/18.yaml
packages:
- .

View File

@ -1,418 +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<String>, test: Vec<String>, bench: Vec<String>) {
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(String),
Auto(String),
}
impl VersionTag {
fn tag(&self) -> &'static str {
match self {
VersionTag::Manual(_) => "manual",
VersionTag::Auto(_) => "auto",
}
}
fn version(&self) -> &str {
match self {
VersionTag::Manual(s) => s,
VersionTag::Auto(s) => s,
}
}
}
pub fn outdated() {
let mut all: Vec<String> = vec![];
let versioned = handle(false, |_loc, lines| {
all.extend(lines);
vec![]
});
let mut map: BTreeMap<String, VersionTag> = BTreeMap::new();
for VersionedPackage { package, version } in versioned {
map.insert(package, VersionTag::Manual(version));
}
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(), VersionTag::Auto(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 is_boot(&package) {
continue;
}
if i % 100 == 0 {
println!("{:02}%", ((i as f64 / entries as f64) * 100.0).floor());
}
i += 1;
let latest = latest_version(&package);
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;
}
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 {
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::<Vec<String>>()
.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: &str) -> 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)
}
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,
}
struct VersionedPackage {
package: String,
version: String,
}
fn parse_versioned_package(s: &str) -> Option<VersionedPackage> {
if let Some(caps) = regex!(r#"- *([^ ]+) < *0 *# *([\d.]+)"#).captures(s) {
let package = caps.get(1).unwrap().as_str().to_owned();
let 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 = caps.get(1).unwrap().as_str().to_owned();
let version = caps.get(2).unwrap().as_str().to_owned();
Some(VersionedPackage { package, version })
} else {
None
}
}
fn handle<F>(write: bool, mut f: F) -> Vec<VersionedPackage>
where
F: FnMut(Location, Vec<String>) -> Vec<String>,
{
let path = "build-constraints.yaml";
let mut new_lines: Vec<String> = vec![];
let mut versioned_packages: Vec<VersionedPackage> = 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(&line) {
versioned_packages.push(versioned_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
}
enum Location {
Lib,
Test,
Bench,
}
fn read_lines<P>(filename: P) -> Lines<BufReader<File>>
where
P: AsRef<Path>,
{
let file = File::open(filename).unwrap();
BufReader::new(file).lines()
}
#[derive(Deserialize)]
struct SnapshotYaml {
// flags: BTreeMap<PackageName, BTreeMap<PackageFlag, bool>>,
// publish_time
packages: Vec<SnapshotPackage>,
// hidden
// resolver
}
#[derive(Deserialize)]
struct SnapshotPackage {
hackage: PackageWithVersionAndSha,
// pantry-tree
}
#[derive(PartialOrd, Ord, PartialEq, Eq, Clone)]
struct PackageName(String);
impl fmt::Display for PackageName {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.fmt(f)
}
}
#[derive(Clone, PartialOrd, Ord, PartialEq, Eq)]
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: PackageName,
version: Version,
}
impl<'de> serde::Deserialize<'de> for PackageWithVersionAndSha {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
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 = PackageName(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<A, P: AsRef<Path>>(path: P) -> Result<A, Box<dyn Error>>
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<PackageName, Diff<Version>>,
}
#[derive(Clone, Copy)]
enum Diff<A> {
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}");
}
}

View File

@ -1,169 +0,0 @@
use std::collections::HashMap;
use std::io::{self, BufRead};
use lazy_regex::regex;
use regex::Regex;
use structopt::StructOpt;
type H = HashMap<Header, Vec<(String, String, String)>>;
#[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 {
Clear,
Add,
Outdated,
DiffSnapshot { a: String, b: String },
}
fn main() {
let opt = Opt::from_args();
match opt {
Opt::Clear => commenter::clear(),
Opt::Add => add(),
Opt::Outdated => commenter::outdated(),
Opt::DiffSnapshot { a, b } => commenter::diff_snapshot(a, b),
}
}
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<Header> = None;
let header_versioned = regex!(
r#"^(?P<package>[a-zA-z]([a-zA-z0-9.-]*?))-(?P<version>(\d+(\.\d+)*)).+?is out of bounds for:$"#
);
let header_missing = regex!(r#"^(?P<package>[a-zA-z]([a-zA-z0-9.-]*)).+?depended on by:$"#);
let package = regex!(
r#"^- \[ \] (?P<package>[a-zA-z]([a-zA-z0-9.-]*?))-(?P<version>(\d+(\.\d+)*)).+?Used by: (?P<component>.+)$"#
);
// 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(cap) = package.captures(&line) {
let root = last_header.clone().unwrap();
let package = cap.name("package").unwrap().as_str();
let version = cap.name("version").unwrap().as_str();
let component = cap.name("component").unwrap().as_str();
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(cap) = header_versioned.captures(&line) {
let package = cap.name("package").unwrap().as_str().to_owned();
let version = cap.name("version").unwrap().as_str().to_owned();
last_header = Some(Header::Versioned { package, version });
} 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()
}