Skip to content

Commit 1acc1f8

Browse files
authoredDec 9, 2022
Build and utilize pre-compiled binaries
Making users wait for a `stack install weeder` is an unnecessary tax on every CI run that lacks a complete cache. Instead, this PR adds an "Binaries" action that builds binaries across a runner/GHC matrix and stores them on a Release for use by the action. The Binaries action is idempotent and has been run and added all the binaries already, which our own CI uses successfully. I made binaries for Linux and Mac and GHCs 8.8.1 to 9.2.5. Windows may be possible, but the `prep` step needs to be rewritten for that platform. These are all the GHC versions for which a released version of `weeder` exists, so it should cover all users. Arguably, these binaries should be released by the weeder project itself. I may open an Issue soon to see if they'd be open to upstreaming something like tooling I have here, which is pretty non-standard due to the need to version by GHC and not by weeder.
1 parent 35c5fe3 commit 1acc1f8

File tree

7 files changed

+220
-45
lines changed

7 files changed

+220
-45
lines changed
 

‎.github/bin/build-binaries-matrix

+122
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
#!/usr/bin/env ruby
2+
require "json"
3+
4+
RELEASE_NAME = "Binaries"
5+
6+
EXISTING_ASSETS = JSON.parse(`
7+
gh --repo freckle/weeder-action release view #{RELEASE_NAME} --json assets |
8+
jq '.assets | map(.name)'
9+
`)
10+
11+
GHCs = %W[
12+
9.2.5
13+
9.2.4
14+
9.2.3
15+
9.2.2
16+
9.0.2
17+
9.0.1
18+
8.10.7
19+
8.10.6
20+
8.10.5
21+
8.10.4
22+
8.10.3
23+
8.10.2
24+
8.10.1
25+
8.8.4
26+
8.8.3
27+
8.8.2
28+
8.8.1
29+
]
30+
31+
Asset = Struct.new(:ghc, :os) do
32+
def name
33+
"weeder-#{ghc}-#{os}-x64.#{os_attributes.fetch(:ext)}"
34+
end
35+
36+
def include
37+
{ asset: name, ghc: ghc, release: RELEASE_NAME }.
38+
merge(os_attributes).
39+
merge(version_attributes)
40+
end
41+
42+
def os_attributes
43+
case os
44+
when "linux"
45+
{ runner: "ubuntu-latest", exe: "./weeder", ext: "tar.gz", zip: "tar -czf" }
46+
when "darwin"
47+
{ runner: "macOS-latest", exe: "./weeder", ext: "tar.gz", zip: "tar -czf" }
48+
when "win32"
49+
{ runner: "windows-latest", exe: "./weeder.exe", ext: "zip", zip: '"C:\Program Files\7-Zip\7z.exe" a -tzip' }
50+
else
51+
raise "Unexpected OS: #{os}, must be linux|darwin|win32"
52+
end
53+
end
54+
55+
def version_attributes
56+
case ghc
57+
when /9\.2\..*/
58+
{
59+
version: "2.4.0",
60+
resolver: "lts-20.3",
61+
"extra-deps": ""
62+
}
63+
when /9\.0\..*/
64+
{
65+
version: "2.3.1",
66+
resolver: "lts-19.33",
67+
"extra-deps": ""
68+
}
69+
when /8\.10\..*/
70+
{
71+
version: "2.2.0",
72+
resolver: "lts-18.28",
73+
"extra-deps": [
74+
"dhall-1.40.2",
75+
"generic-lens-2.2.1.0",
76+
"generic-lens-core-2.2.1.0"
77+
].join(",")
78+
}
79+
when /8\.8\..*/
80+
{
81+
version: "2.2.0",
82+
resolver: "lts-16.31",
83+
"extra-deps": [
84+
"dhall-1.40.2",
85+
"generic-lens-2.2.1.0",
86+
"generic-lens-core-2.2.1.0",
87+
"base16-bytestring-1.0.2.0",
88+
"prettyprinter-1.7.1",
89+
"repline-0.4.2.0",
90+
"haskeline-0.8.2"
91+
].join(",")
92+
}
93+
end
94+
end
95+
96+
def needed?
97+
!EXISTING_ASSETS.include?(name)
98+
end
99+
end
100+
101+
def generate_matrix
102+
assets = %W[ linux darwin win32 ].
103+
flat_map { |os| GHCs.map { |ghc| Asset.new(ghc, os) } }.
104+
filter(&:needed?)
105+
106+
if assets.empty?
107+
{
108+
asset: ["none"],
109+
include: [{
110+
asset: "none",
111+
runner: "ubuntu-latest"
112+
}]
113+
}
114+
else
115+
{
116+
asset: assets.map(&:name),
117+
include: assets.map(&:include)
118+
}
119+
end
120+
end
121+
122+
puts JSON.dump(generate_matrix)

‎.github/workflows/binaries.yml

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
name: Binaries
2+
3+
on:
4+
pull_request:
5+
6+
jobs:
7+
generate:
8+
runs-on: ubuntu-latest
9+
steps:
10+
- uses: actions/checkout@v3
11+
- id: generate
12+
run: |
13+
cat >>"$GITHUB_OUTPUT" <<EOM
14+
matrix<<EOJSON
15+
$(./.github/bin/build-binaries-matrix)
16+
EOJSON
17+
EOM
18+
env:
19+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
20+
outputs:
21+
matrix: ${{ steps.generate.outputs.matrix }}
22+
23+
binaries:
24+
needs: generate
25+
26+
strategy:
27+
matrix: ${{ fromJSON(needs.generate.outputs.matrix) }}
28+
fail-fast: false
29+
30+
runs-on: ${{ matrix.runner }}
31+
steps:
32+
- if: ${{ matrix.asset != 'none' }}
33+
uses: actions/cache@v3
34+
with:
35+
path: |
36+
~/.stack
37+
./.stack-work
38+
key: ${{ runner.os }}-stack-${{ matrix.ghc }}
39+
restore-keys: |
40+
${{ runner.os }}-stack-
41+
42+
- if: ${{ matrix.asset != 'none' }}
43+
shell: bash
44+
run: |
45+
cat >stack.yaml <<'EOM'
46+
resolver: ${{ matrix.resolver }}
47+
packages: []
48+
extra-deps: [${{ matrix.extra-deps }}]
49+
EOM
50+
51+
stack install weeder-${{ matrix.version }} --local-bin-path .
52+
53+
${{ matrix.zip }} '${{ matrix.asset }}' ${{ matrix.exe }}
54+
gh --repo '${{ github.repository }}' release upload '${{ matrix.release }}' '${{ matrix.asset }}'
55+
env:
56+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

‎.github/workflows/ci.yml

+3-5
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,19 @@ jobs:
1111
steps:
1212
- uses: actions/checkout@v2
1313

14-
- uses: freckle/stack-cache-action@main
14+
- uses: freckle/stack-cache-action@v2
1515
with:
1616
working-directory: example
1717

18-
- uses: freckle/stack-action@main
18+
- uses: freckle/stack-action@v3
1919
with:
2020
working-directory: example
21-
hlint: false
22-
weeder: false
2321

2422
- id: weeder
2523
uses: ./
2624
with:
25+
ghc-version: 9.2.5
2726
working-directory: example
28-
weeder-version: 2.2.0
2927
fail: false
3028

3129
- run: |

‎README.md

+22-7
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,6 @@ See the [Weeder README][weeder] for project requirements.
1414
You will need to run this step in the same Job as you compile your project, or
1515
make the `.hie` files available some other way.
1616

17-
This Action only supports [Stack]-based projects at this time: it uses
18-
`stack install` to install `weeder` and `stack exec` to run it. PRs are very
19-
welcome to support alternatives such as Cabal or Nix.
20-
21-
[stack]: https://docs.haskellstack.org/en/stable/README/
22-
2317
## Usage
2418

2519
```yaml
@@ -32,7 +26,28 @@ steps:
3226
3327
## Inputs
3428
35-
See [`action.yml`](./action.yml) for a complete and up to date list.
29+
- **ghc-version**: You must specify the `ghc-version` your project is compiled
30+
with (to ensure `.hie` compatibility).
31+
32+
This Action maintains and installs pre-compiled `weeder` binaries for Mac and
33+
Linux across all GHC versions that `weeder` compiles on (8.8.1 to 9.2.5 at
34+
time of this writing). Please file an Issue if you're using a GHC that's not
35+
supported, but for which a released version of `weeder` does exist.
36+
37+
- **weeder-arguments**: Arguments to pass when invoking `weeder`
38+
39+
Default is `--require-hs-files`, which ensures that cached builds that have
40+
since removed files (but still have their `.hie` files present) don't generate
41+
false positives.
42+
43+
- **working-directory**: Change to this directory before running.
44+
45+
This can be necessary if in a mono-repository.
46+
47+
- **fail**: Fail if we find unused functions?
48+
49+
Default is true. This is useful if you want to not fail the step, but do
50+
something else with the weeder output yourself.
3651

3752
## Outputs
3853

‎action.yml

+12-24
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,18 @@
11
name: Weeder
22
description: Annotate unused functions in a Haskell project
33
inputs:
4-
working-directory:
5-
description: Change to this directory before operating
6-
required: true
7-
default: .
8-
stack-yaml:
9-
description: Path to stack.yaml, relative to working-directory
4+
ghc-version:
5+
description: Full version of GHC your project uses (required)
106
required: true
11-
default: stack.yaml
12-
weeder-version:
13-
description: Version of weeder to install (default latest)
14-
required: true
15-
default: ""
167
weeder-arguments:
178
description: |
189
Arguments to pass when invoking weeder (default --require-hs-files)
1910
required: true
2011
default: --require-hs-files
12+
working-directory:
13+
description: Change to this directory before operating
14+
required: true
15+
default: .
2116
fail:
2217
description: Fail the build if unused functions found? (default true)
2318
required: true
@@ -30,17 +25,11 @@ runs:
3025
using: composite
3126
steps:
3227
- name: Install weeder
33-
shell: bash
34-
run: |
35-
if [[ -n "${{ inputs.weeder-version }}" ]]; then
36-
package=weeder-${{ inputs.weeder-version }}
37-
else
38-
package=weeder
39-
fi
40-
41-
cd '${{ inputs.working-directory }}'
42-
stack --stack-yaml '${{ inputs.stack-yaml }}' install \
43-
--copy-compiler-tool "$package"
28+
uses: pbrisbin/setup-tool-action@v1.0.0
29+
with:
30+
name: weeder
31+
version: ${{ inputs.ghc-version }}
32+
url: "https://github.com/freckle/weeder-action/releases/download/Binaries/{name}-{version}-{os}-{arch}.{ext}"
4433

4534
- id: weeder
4635
name: Run weeder
@@ -54,8 +43,7 @@ runs:
5443
5544
cd '${{ inputs.working-directory }}'
5645
prefix=$(echo '${{ inputs.working-directory }}' | sed 's|/$||')/
57-
stack --stack-yaml '${{ inputs.stack-yaml }}' exec -- \
58-
weeder ${{ inputs.weeder-arguments }} |
46+
weeder ${{ inputs.weeder-arguments }} |
5947
sed "s|^|$prefix|; "'s/$/ is not used by any defined root/' |
6048
tee "$tmp" || true
6149

‎example/stack.yaml

+1-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
resolver: lts-18.16
2-
extra-deps:
3-
- dhall-1.40.1@sha256:ecc984210717ae2785a02c31c8b10c23a854761dba60c09adf533459bf5fe9b6,35396
4-
- generic-lens-2.2.0.0@sha256:4008a39f464e377130346e46062e2ac1211f9d2e256bbb1857216e889c7196be,3867
5-
- generic-lens-core-2.2.0.0@sha256:b6b69e992f15fa80001de737f41f2123059011a1163d6c8941ce2e3ab44f8c03,2913
1+
resolver: lts-20.3
62
ghc-options:
73
"$locals": -fwrite-ide-info

‎example/stack.yaml.lock

+4-4
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
packages: []
77
snapshots:
88
- completed:
9-
size: 586286
10-
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/18/16.yaml
11-
sha256: cdead65fca0323144b346c94286186f4969bf85594d649c49c7557295675d8a5
12-
original: lts-18.16
9+
sha256: 03cec7d96ed78877b03b5c2bc5e31015b47f69af2fe6a62d994a42b7a43c5805
10+
size: 648659
11+
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/20/3.yaml
12+
original: lts-20.3

0 commit comments

Comments
 (0)
Please sign in to comment.