Compare commits
500 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
c381f47a72
|
|||
|
a68355cb7d
|
|||
|
f53a10825e
|
|||
|
21bbb8be1c
|
|||
|
ab44e9d2ac
|
|||
|
32497f3a6f
|
|||
|
c06c6b6f12
|
|||
|
26335150b7
|
|||
|
5298aacac9
|
|||
|
|
7832399fb3 | ||
|
|
2b60830203 | ||
|
|
b9bf29ba2c | ||
|
00d67c270e
|
|||
|
2826fec975
|
|||
|
29a34f5edf
|
|||
|
c100daeba5
|
|||
|
ac66f6747e
|
|||
|
014f1ff125
|
|||
|
c4991425ab
|
|||
|
1c770aad58
|
|||
|
7c8912d48c
|
|||
|
67d9a0bd2c
|
|||
|
0115e2a13c
|
|||
|
e2f36611a1
|
|||
|
9143ac97c5
|
|||
|
b5b09d0ca2
|
|||
|
fa79f75072
|
|||
|
6459af419e
|
|||
|
2ff2655db0
|
|||
|
c4ab59f7bf
|
|||
|
a62365141e
|
|||
|
5ae649bccb
|
|||
|
2095b17d06
|
|||
|
336514b3e2
|
|||
|
37707e1df8
|
|||
|
57aa30c7af
|
|||
|
78c6dd5404
|
|||
|
c101c228d7
|
|||
|
0f6874bc0f
|
|||
|
399d89dae5
|
|||
|
ba6b540869
|
|||
|
249c5a5c59
|
|||
|
e2c59230b5
|
|||
|
1d1ace096e
|
|||
|
0381ccef64
|
|||
|
e5a0f836a4
|
|||
|
463915da1a
|
|||
|
ae7bc508e8
|
|||
|
d21e0473bc
|
|||
|
df05feb766
|
|||
|
e0dafa2093
|
|||
|
f1e01e8b18
|
|||
|
8a770de33e
|
|||
|
b3aeb3246f
|
|||
|
1fc3e0ee5d
|
|||
|
f2dcfbdc5f
|
|||
|
23d77ce1b4
|
|||
|
0e6688c2bc
|
|||
|
7ef1ef688f
|
|||
|
3b8f2e8307
|
|||
|
0af7aaef3c
|
|||
|
b8907335ba
|
|||
|
0073ca769b
|
|||
|
8a286156f6
|
|||
|
5a39ead523
|
|||
|
d2b4eccac2
|
|||
|
be9b3a3857
|
|||
|
a8e6fca128
|
|||
|
0483133857
|
|||
|
30d9eb5634
|
|||
|
9fe7af3335
|
|||
|
bedfb3d114
|
|||
|
c19dd5ee8b
|
|||
|
6ae3bfe395
|
|||
|
4f82e80dad
|
|||
|
8e8198546f
|
|||
|
9497e310ca
|
|||
|
02135bdbae
|
|||
|
041a341879
|
|||
|
15dd810d67
|
|||
|
7982f3aec0
|
|||
|
2fb07201c7
|
|||
|
b5ca01dc4f
|
|||
|
fa523d590e
|
|||
|
523f2f57e1
|
|||
|
d662682fb5
|
|||
|
ff2b06a5e8
|
|||
|
aece305003
|
|||
|
ef8da9bcec
|
|||
|
3cd55beab1
|
|||
|
6766501858
|
|||
|
d5b41683ca
|
|||
|
ff8dbe111d
|
|||
|
28d4071fac
|
|||
|
31a523755f
|
|||
|
3d1d8f1af7
|
|||
|
167f6d0683
|
|||
|
8580487b61
|
|||
|
a8b1c33280
|
|||
|
fca2a4134b
|
|||
|
f90741f4d3
|
|||
|
ba4b45f7fb
|
|||
|
4767f3db5b
|
|||
|
709658462c
|
|||
|
c431c0ae00
|
|||
|
6f61b5dbef
|
|||
|
c42c4b64f9
|
|||
|
d3a36c2c9a
|
|||
|
6799e9616e
|
|||
|
|
e8d962ac44 | ||
|
ac1e145028
|
|||
|
2fdf121167
|
|||
|
dcca8b0bf2
|
|||
|
b1f891b005
|
|||
|
648dcc7287
|
|||
|
2175f7dd3d
|
|||
|
aff90a52f1
|
|||
|
0f14dee72a
|
|||
|
ae2031174e
|
|||
|
c163278c64
|
|||
|
d10133f06f
|
|||
|
4377fc663e
|
|||
|
487e236882
|
|||
|
|
8fc128e89b | ||
|
|
737f72f90f | ||
|
|
c3aab65521 | ||
|
|
972474f79a | ||
| bc64d2ade0 | |||
|
|
eddda55fe6 | ||
|
|
13aca91231 | ||
|
|
6011242eae | ||
|
|
cadb5086e1 | ||
|
|
10a30bbf38 | ||
|
|
6ac7a75bab | ||
|
bbd11bfa26
|
|||
|
75548fa02d
|
|||
|
fb6956009f
|
|||
|
e029117c3e
|
|||
|
bc7c01de90
|
|||
|
cfcd8a4c20
|
|||
|
5e17eb7ca7
|
|||
|
|
756727ffe2 | ||
|
6bc602dead
|
|||
|
056c79e813
|
|||
|
68bbf31a86
|
|||
|
b58f380e75
|
|||
|
48c54bf374
|
|||
|
51da1578f4
|
|||
|
|
488f25aed6 | ||
|
|
d60f58cf43 | ||
|
|
7a6a119829 | ||
|
|
f0fb019c70 | ||
|
|
0f98ec6b78 | ||
|
|
107fed6e60 | ||
|
|
59a9a770a5 | ||
|
|
20bcb26e3d | ||
|
d355c46250
|
|||
|
787c927de6
|
|||
|
d15ff7bc67
|
|||
|
7c5c35f1b0
|
|||
|
001b090bc6
|
|||
|
db8207f8b9
|
|||
|
e5918de7af
|
|||
|
d2346a543a
|
|||
|
c057b4ae5c
|
|||
|
b962bf4af9
|
|||
|
c54dc05d92
|
|||
|
8c72bf697e
|
|||
|
cc8cf3d12a
|
|||
|
9bdf6bde17
|
|||
|
8363495843
|
|||
|
bc80b1048f
|
|||
|
d61981bc1b
|
|||
|
4ccdc5dd6c
|
|||
|
3240118226
|
|||
|
254989d63d
|
|||
|
283f2a6e46
|
|||
|
94637dfbab
|
|||
|
3e26d7057c
|
|||
|
3f710112f3
|
|||
|
34df41b44a
|
|||
|
3897434ef0
|
|||
|
375dba9dd1
|
|||
|
2edd1fb583
|
|||
|
11326060fb
|
|||
|
d343c01737
|
|||
|
3925f78721
|
|||
|
d98e54a743
|
|||
|
13143b8e4d
|
|||
|
3a7895e5ea
|
|||
|
2893b2e2d2
|
|||
|
987436fed2
|
|||
|
|
be82565775 | ||
|
|
f8d0243146 | ||
|
96ac66e909
|
|||
|
e5947f3490
|
|||
|
b35fe15703
|
|||
|
a269b60282
|
|||
|
fc6f7ffd73
|
|||
|
430dc2d20b
|
|||
|
77c464870f
|
|||
|
dda38ec52b
|
|||
|
|
f6b6b36eb7 | ||
|
|
3986677b06 | ||
|
1fb048777c
|
|||
|
e9c335eecc
|
|||
|
a7c7186aa4
|
|||
|
|
d7f82d643c | ||
|
|
15560a06b1 | ||
|
e38bd61066
|
|||
|
b086261c3c
|
|||
|
8c098d4e17
|
|||
|
e3a9c095c6
|
|||
|
678bdd7915
|
|||
|
14fc6b7281
|
|||
|
a2555cecc5
|
|||
|
9d6e469f79
|
|||
|
982c0a0fcf
|
|||
|
f8cfcd4038
|
|||
|
4d465efef1
|
|||
|
d667160027
|
|||
|
|
df55d972cf | ||
|
|
df758d828b | ||
|
7bc00c4e68
|
|||
|
bfc50e269c
|
|||
|
cea71beb4d
|
|||
|
8247c0b00b
|
|||
|
f624a83e87
|
|||
|
951e676bee
|
|||
|
281f310394
|
|||
|
|
8c486e8d46 | ||
|
c029713f23
|
|||
|
b86e2a1d5b
|
|||
|
099a6b9dcd
|
|||
|
3b13624117
|
|||
|
fad1efcefa
|
|||
|
1701b8a2f4
|
|||
|
608ee07940
|
|||
|
|
a0c2a5ccec | ||
|
cd41d3af97
|
|||
|
b5aafdee61
|
|||
|
9d9e4bb44e
|
|||
|
c708283547
|
|||
|
a4ddf95c8d
|
|||
|
ddbb396bf3
|
|||
|
e2a7c320ac
|
|||
|
06f998fa5e
|
|||
|
c48c73d34d
|
|||
|
cfb6ab31ab
|
|||
|
|
eac15541e8 | ||
|
984acebff8
|
|||
|
4cf2d125dd
|
|||
|
6701093c3b
|
|||
|
e9fdc073c6
|
|||
|
57c791106b
|
|||
|
fcba151fad
|
|||
|
3b24f503d1
|
|||
|
bd18fd9aa1
|
|||
|
|
c2c5625685 | ||
|
|
ce6fb0bb1e | ||
|
|
dcfb3afdad | ||
|
50c91345e8
|
|||
|
af3ecae792
|
|||
|
|
300cfd3ba6 | ||
|
|
bb430fa0b7 | ||
|
|
80fa7965a4 | ||
|
9975a2d4ba
|
|||
|
|
d1735bc446 | ||
|
dbf1d6f420
|
|||
|
0a0fbd0cb6
|
|||
|
f13f53b910
|
|||
|
6dfc04a9f6
|
|||
|
72133d0002
|
|||
|
6e07e9e56b
|
|||
|
e903aeb555
|
|||
|
2792f6f4b6
|
|||
|
|
80eb72ce49 | ||
|
|
2c6d0382cf | ||
|
|
e1bec789b0 | ||
|
|
5683493cae | ||
|
|
ae5e213b59 | ||
|
|
911089f334 | ||
|
|
6b89646c1e | ||
|
|
960d5ce79f | ||
|
|
90ed0895d6 | ||
|
|
7471f4f4dc | ||
|
|
781cf8eed5 | ||
|
|
236da31af6 | ||
|
|
1f760af880 | ||
|
|
62d03b776b | ||
|
|
37ea18a0d8 | ||
|
|
083dc59a8f | ||
|
|
a45d069cad | ||
|
|
fdbcd4fafd | ||
|
|
f3c1c925ed | ||
|
|
8f6a7ba39c | ||
|
|
f212eb4570 | ||
|
|
0d118e2fe1 | ||
|
|
c0f46ef81f | ||
|
|
476513b0a7 | ||
|
|
9a511669a8 | ||
|
|
a16a25a3cd | ||
|
|
8666fcd120 | ||
|
|
521ab0aedb | ||
|
|
1cfff674b7 | ||
|
88d1d19f55
|
|||
|
0fb1da5c3a
|
|||
|
b32f88e9a6
|
|||
|
9d2421fac5
|
|||
|
043e288fbf
|
|||
|
32e34876e2
|
|||
|
f12a2b3821
|
|||
|
844b4decab
|
|||
|
53ca60596d
|
|||
|
2d2894b0f4
|
|||
|
21d30cd8ce
|
|||
|
b38a569124
|
|||
|
810607e84f
|
|||
|
442ddfd4e4
|
|||
|
096103e65a
|
|||
|
60a56c337c
|
|||
|
11c1b2cc6c
|
|||
|
45db3bd913
|
|||
|
6d76561340
|
|||
|
00caeba067
|
|||
|
5a34191b88
|
|||
|
85003900d7
|
|||
|
0c666a6bbe
|
|||
|
e4e52ebf6b
|
|||
|
4512468108
|
|||
|
d3e3ebd63f
|
|||
|
ce616d3eb3
|
|||
|
5837e04e6e
|
|||
|
95ca79f3f8
|
|||
|
706fe1ffcc
|
|||
|
2774f026e8
|
|||
|
07604a2eb5
|
|||
|
|
03d77f5006 | ||
|
fdf45e0fe6
|
|||
|
1dc9ad7a57
|
|||
|
cc51d7b454
|
|||
|
c439693a8f
|
|||
|
af8c097092
|
|||
|
|
71e6dbfdca | ||
|
|
692cd1616b | ||
|
|
4e3dbea5d0 | ||
|
|
fd2add78bd | ||
|
|
e9da8ab439 | ||
|
|
9c22ba9d45 | ||
|
|
e5d3080b54 | ||
|
|
5995a8b592 | ||
|
|
bc6d006c57 | ||
|
|
b148d8e2e7 | ||
|
|
4f7d41a8cc | ||
|
|
5efe2e5f7a | ||
|
|
338f5f309d | ||
|
9639e695e2
|
|||
|
d2a2bde321
|
|||
|
c85ff686b6
|
|||
|
48d3b3bc3e
|
|||
|
94bd01aaca
|
|||
|
|
ba51cbad6f | ||
|
|
511272e86d | ||
|
|
873f75da9f | ||
|
|
42d4a66493 | ||
|
|
9a79af6fd2 | ||
|
|
63f10a1871 | ||
|
|
9686ee9826 | ||
|
|
4729364e99 | ||
|
|
91d982c7b2 | ||
|
|
8b7c22440e | ||
|
|
761b8cc750 | ||
|
3bdc82c99b
|
|||
|
|
9b3d55a095 | ||
|
db4e9fa432
|
|||
|
530c25c6a1
|
|||
|
1c2cf98850
|
|||
|
b35dbca22e
|
|||
|
a4a7f73fb7
|
|||
|
fd0ea3d858
|
|||
|
bbbe52f453
|
|||
|
|
e2daf5381c | ||
|
9e181b8820
|
|||
|
a6108f8319
|
|||
|
7a2570019a
|
|||
|
c5b4e82b48
|
|||
|
4ed72fb517
|
|||
|
5217aa0a1d
|
|||
|
3caf91c640
|
|||
|
eb26a5133f
|
|||
|
9e9402a3a2
|
|||
|
bc13a4555d
|
|||
|
eaad2caf25
|
|||
|
6143cdf2e0
|
|||
|
2c7176d998
|
|||
|
327b80cf56
|
|||
|
005c9fbb83
|
|||
|
42134fd2a5
|
|||
|
bc85a7d9c3
|
|||
|
7e14fd4a08
|
|||
|
bf74d1e828
|
|||
|
f04708e8ae
|
|||
|
80e1924e5f
|
|||
|
c7393bd7c5
|
|||
|
664713bb13
|
|||
|
01715fdefc
|
|||
|
ab9b24e109
|
|||
|
34ecb1a56e
|
|||
|
e3aef38f75
|
|||
|
ead2b76050
|
|||
|
2f35513f6e
|
|||
|
8573c99088
|
|||
|
dfe63332b2
|
|||
|
767ae48c7b
|
|||
|
f4160464c0
|
|||
|
a572b1d5f0
|
|||
|
82587d26b5
|
|||
|
ec98826e6d
|
|||
|
b4fcd05e8f
|
|||
|
1345ec938b
|
|||
|
227f3acaa5
|
|||
|
c20636f597
|
|||
|
c2d437150a
|
|||
|
9ff1467612
|
|||
|
9218efd71a
|
|||
|
bcd244a92a
|
|||
|
7de552ed82
|
|||
|
5cf297a4d2
|
|||
|
d86f84eef4
|
|||
|
83458c6c1e
|
|||
|
b862ca52a9
|
|||
|
928f4a97de
|
|||
|
e8d79c9d38
|
|||
|
59e1eee8ce
|
|||
|
57c8ffda35
|
|||
|
abbe51614d
|
|||
|
171ebd213d
|
|||
|
2a240cbd09
|
|||
|
068fa3454c
|
|||
|
6b2bcbf2ce
|
|||
|
19e46dac18
|
|||
|
e96c863120
|
|||
|
a30b3c84d7
|
|||
|
0ad5dc4583
|
|||
|
7189998f3b
|
|||
|
b6b24b8e0b
|
|||
|
8e820c6e89
|
|||
|
c74784a37c
|
|||
|
3d940cffcf
|
|||
|
0df044b284
|
|||
|
f576b9fb20
|
|||
|
5e00264119
|
|||
|
|
05eeba32fa | ||
|
|
61019ecd49 | ||
|
|
bed06d1334 | ||
|
|
f09f4bd1b7 | ||
|
|
a3b11f21bb | ||
|
|
69a461d9c3 | ||
|
|
1dfe5cfecf | ||
|
|
8e4550657e | ||
|
|
aee7fa52c3 | ||
|
|
d166cc84a1 | ||
|
|
bb7229d224 | ||
|
|
708cd5ead9 | ||
|
|
f7986cb4da | ||
|
|
395aeb415d | ||
|
|
830fb70492 | ||
|
|
6379a26afb | ||
|
|
2277013c76 | ||
|
|
8934e0e6bd | ||
|
|
59519febbc | ||
|
|
46fcdd356c | ||
|
|
9f343c45e8 | ||
|
|
931904f388 | ||
|
|
a40d0cbb5c | ||
|
|
9f5df9db10 | ||
|
|
d26ddf7015 | ||
|
|
9515065407 | ||
|
|
82a8c61cf6 | ||
|
|
3fae516ce4 | ||
|
|
33eaa765d7 | ||
|
|
3b3dde8413 | ||
|
|
118a2744fe | ||
|
|
2e3dceecf8 | ||
|
|
07fb04bb74 | ||
|
|
8a1dbe9dbb | ||
|
|
4ef3622616 | ||
|
|
82a704ab44 | ||
|
|
0cb22945fe | ||
|
|
d09adf9159 | ||
|
|
0b959c56fb | ||
|
|
ec29332657 | ||
|
|
0f6381e67b | ||
|
|
877b55e21d | ||
|
|
fa11ca665f | ||
|
d9d196439f
|
|||
|
a34fc4ad4f
|
|||
|
b4d52b88c1
|
|||
|
3fc3d27361
|
|||
|
56b86add38
|
109
.github/release.yaml
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
name: Create Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
jobs:
|
||||
draft_release:
|
||||
name: Create Release
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
|
||||
steps:
|
||||
- name: Create Release
|
||||
id: create_release
|
||||
uses: actions/create-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ github.ref }}
|
||||
release_name: Release ${{ github.ref }}
|
||||
body: |
|
||||
Changes in this Release
|
||||
- First Change
|
||||
- Second Change
|
||||
draft: true
|
||||
prerelease: false
|
||||
|
||||
release-mac:
|
||||
name: Create Release for macOS
|
||||
needs: draft_release
|
||||
runs-on: ${{ matrix.os }}
|
||||
env:
|
||||
MACOSX_DEPLOYMENT_TARGET: 10.13
|
||||
strategy:
|
||||
matrix:
|
||||
os:
|
||||
- macOS-10.15
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- uses: haskell/actions/setup@v1.2
|
||||
with:
|
||||
ghc-version: 8.10.4
|
||||
cabal-version: 3.4.0.0
|
||||
|
||||
- name: create ~/.local/bin
|
||||
run: mkdir -p "$HOME/.local/bin"
|
||||
shell: bash
|
||||
|
||||
- name: Add ~/.local/bin to PATH
|
||||
run: echo "$HOME/.local/bin" >> $GITHUB_PATH
|
||||
shell: bash
|
||||
|
||||
- name: Update cabal cache
|
||||
run: cabal update
|
||||
shell: bash
|
||||
|
||||
- name: Install cabal dependencies
|
||||
run: cabal build --only-dependencies
|
||||
shell: bash
|
||||
|
||||
- name: Build
|
||||
run: cabal build -w ghc-${GHC_VERSION} --constraint="zlib +bundled-c-zlib" --constraint="lzma +static" -ftui
|
||||
shell: bash
|
||||
|
||||
- name: Install
|
||||
run: cp "$(cabal list-bin exe:ghcup)" ~/.local/bin/ghcup
|
||||
shell: bash
|
||||
|
||||
- name: Strip
|
||||
run: strip ~/.local/bin/ghcup
|
||||
shell: bash
|
||||
|
||||
- name: Run tests
|
||||
run: cabal test --constraint="zlib +bundled-c-zlib" --constraint="lzma +static" all
|
||||
shell: bash
|
||||
|
||||
- name: Install git
|
||||
run: brew install git
|
||||
|
||||
- name: set HOME
|
||||
run: echo "HOME=$HOME" >> $GITHUB_ENV
|
||||
shell: bash
|
||||
|
||||
- name: Set ASSET_PATH
|
||||
run: echo "ASSET_PATH=$HOME/.local/bin/ghcup" >> $GITHUB_ENV
|
||||
shell: bash
|
||||
|
||||
- name: Upload Release Asset
|
||||
id: upload-release-asset
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ needs.draft_release.outputs.upload_url }}
|
||||
asset_path: ${{ env.ASSET_PATH }}
|
||||
asset_name: ghcup-${{ matrix.os }}
|
||||
asset_content_type: application/octet-stream
|
||||
|
||||
- if: always()
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: plan.json
|
||||
path: ./dist-newstyle/cache/plan.json
|
||||
|
||||
109
.github/workflows/release.yaml
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
name: Create Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
jobs:
|
||||
draft_release:
|
||||
name: Draft Release
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
|
||||
steps:
|
||||
- name: Create Release
|
||||
id: create_release
|
||||
uses: actions/create-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ github.ref }}
|
||||
release_name: Release ${{ github.ref }}
|
||||
body: |
|
||||
Changes in this Release
|
||||
- First Change
|
||||
- Second Change
|
||||
draft: true
|
||||
prerelease: false
|
||||
|
||||
release-mac:
|
||||
name: Create Release
|
||||
needs: draft_release
|
||||
runs-on: ${{ matrix.os }}
|
||||
env:
|
||||
MACOSX_DEPLOYMENT_TARGET: 10.13
|
||||
strategy:
|
||||
matrix:
|
||||
os:
|
||||
- macOS-10.15
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- uses: haskell/actions/setup@v1.2
|
||||
with:
|
||||
ghc-version: 8.10.4
|
||||
cabal-version: 3.4.0.0
|
||||
|
||||
- name: create ~/.local/bin
|
||||
run: mkdir -p "$HOME/.local/bin"
|
||||
shell: bash
|
||||
|
||||
- name: Add ~/.local/bin to PATH
|
||||
run: echo "$HOME/.local/bin" >> $GITHUB_PATH
|
||||
shell: bash
|
||||
|
||||
- name: Update cabal cache
|
||||
run: cabal update
|
||||
shell: bash
|
||||
|
||||
- name: Install cabal dependencies
|
||||
run: cabal build --only-dependencies --constraint="zlib +bundled-c-zlib" --constraint="lzma +static" -ftui
|
||||
shell: bash
|
||||
|
||||
- name: Build
|
||||
run: cabal build --constraint="zlib +bundled-c-zlib" --constraint="lzma +static" -ftui
|
||||
shell: bash
|
||||
|
||||
- name: Install
|
||||
run: cp "$(cabal list-bin exe:ghcup)" ~/.local/bin/ghcup
|
||||
shell: bash
|
||||
|
||||
- name: Strip
|
||||
run: strip ~/.local/bin/ghcup
|
||||
shell: bash
|
||||
|
||||
- name: Run tests
|
||||
run: cabal test --constraint="zlib +bundled-c-zlib" --constraint="lzma +static" all
|
||||
shell: bash
|
||||
|
||||
- name: Install git
|
||||
run: brew install git
|
||||
|
||||
- name: set HOME
|
||||
run: echo "HOME=$HOME" >> $GITHUB_ENV
|
||||
shell: bash
|
||||
|
||||
- name: Set ASSET_PATH
|
||||
run: echo "ASSET_PATH=$HOME/.local/bin/ghcup" >> $GITHUB_ENV
|
||||
shell: bash
|
||||
|
||||
- name: Upload Release Asset
|
||||
id: upload-release-asset
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ needs.draft_release.outputs.upload_url }}
|
||||
asset_path: ${{ env.ASSET_PATH }}
|
||||
asset_name: ghcup-${{ matrix.os }}
|
||||
asset_content_type: application/octet-stream
|
||||
|
||||
- if: always()
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: plan.json
|
||||
path: ./dist-newstyle/cache/plan.json
|
||||
|
||||
29
.github/workflows/shimgen.yaml
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
name: Shimgen CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
build-shimgen:
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [windows-latest]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: ilammy/msvc-dev-cmd@v1
|
||||
|
||||
- name: compile
|
||||
run: cl /O1 scoop-better-shimexe/shim.c
|
||||
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: shim.exe
|
||||
path: shim.exe
|
||||
|
||||
389
.gitlab-ci.yml
@@ -1,26 +1,29 @@
|
||||
stages:
|
||||
- hlint
|
||||
- checks
|
||||
- quick-test
|
||||
- test
|
||||
- expensive-test
|
||||
- release
|
||||
|
||||
variables:
|
||||
GIT_SSL_NO_VERIFY: "1"
|
||||
|
||||
# Commit of ghc/ci-images repository from which to pull Docker images
|
||||
DOCKER_REV: 1ac7f435c9312f10422a82d304194778378e2a1a
|
||||
DOCKER_REV: 8d0224e6b2a08157649651e69302380b2bd24e11
|
||||
|
||||
############################################################
|
||||
# CI Step
|
||||
############################################################
|
||||
|
||||
.debian:
|
||||
image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb9:$DOCKER_REV"
|
||||
image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb10:$DOCKER_REV"
|
||||
tags:
|
||||
- x86_64-linux
|
||||
variables:
|
||||
OS: "LINUX"
|
||||
ARCH: "64"
|
||||
CABAL_DIR: "$CI_PROJECT_DIR/cabal"
|
||||
CROSS: ""
|
||||
|
||||
.alpine:64bit:
|
||||
image: "alpine:3.12"
|
||||
@@ -41,16 +44,17 @@ variables:
|
||||
CABAL_DIR: "$CI_PROJECT_DIR/cabal"
|
||||
|
||||
.linux:armv7:
|
||||
image: "arm32v7/fedora"
|
||||
image: "registry.gitlab.haskell.org/ghc/ci-images/armv7-linux-deb10:$DOCKER_REV"
|
||||
tags:
|
||||
- armv7-linux
|
||||
variables:
|
||||
OS: "LINUX"
|
||||
ARCH: "ARM"
|
||||
CABAL_DIR: "$CI_PROJECT_DIR/cabal"
|
||||
retry: 2
|
||||
|
||||
.linux:aarch64:
|
||||
image: "arm64v8/fedora"
|
||||
image: "registry.gitlab.haskell.org/ghc/ci-images/aarch64-linux-deb10:$DOCKER_REV"
|
||||
tags:
|
||||
- aarch64-linux
|
||||
variables:
|
||||
@@ -74,9 +78,17 @@ variables:
|
||||
ARCH: "ARM64"
|
||||
CABAL_DIR: "$CI_PROJECT_DIR/cabal"
|
||||
|
||||
.freebsd:
|
||||
.freebsd13:
|
||||
tags:
|
||||
- x86_64-freebsd
|
||||
- x86_64-freebsd13
|
||||
variables:
|
||||
OS: "FREEBSD"
|
||||
ARCH: "64"
|
||||
CABAL_DIR: "$CI_PROJECT_DIR/cabal"
|
||||
|
||||
.freebsd12:
|
||||
tags:
|
||||
- x86_64-freebsd12
|
||||
variables:
|
||||
OS: "FREEBSD"
|
||||
ARCH: "64"
|
||||
@@ -89,6 +101,7 @@ variables:
|
||||
OS: "WINDOWS"
|
||||
ARCH: "64"
|
||||
CABAL_DIR: "$CI_PROJECT_DIR/cabal"
|
||||
retry: 2
|
||||
|
||||
.root_cleanup:
|
||||
after_script:
|
||||
@@ -98,13 +111,18 @@ variables:
|
||||
script:
|
||||
- bash ./.gitlab/script/ghcup_version.sh
|
||||
variables:
|
||||
JSON_VERSION: "0.0.5"
|
||||
JSON_VERSION: "0.0.6"
|
||||
artifacts:
|
||||
expire_in: 2 week
|
||||
paths:
|
||||
- golden
|
||||
- test/golden
|
||||
- dist-newstyle/cache/
|
||||
when: on_failure
|
||||
|
||||
# .test_ghcup_scoop:
|
||||
# script:
|
||||
# - cl /O1 scoop-better-shimexe/shim.c
|
||||
|
||||
.test_ghcup_version:linux:
|
||||
extends:
|
||||
- .test_ghcup_version
|
||||
@@ -124,14 +142,14 @@ variables:
|
||||
- .test_ghcup_version
|
||||
- .linux:armv7
|
||||
before_script:
|
||||
- ./.gitlab/before_script/linux/install_deps_manual.sh
|
||||
- ./.gitlab/before_script/linux/install_deps.sh
|
||||
|
||||
.test_ghcup_version:aarch64:
|
||||
extends:
|
||||
- .test_ghcup_version
|
||||
- .linux:aarch64
|
||||
before_script:
|
||||
- ./.gitlab/before_script/linux/install_deps_manual.sh
|
||||
- ./.gitlab/before_script/linux/install_deps.sh
|
||||
|
||||
.test_ghcup_version:darwin:
|
||||
extends:
|
||||
@@ -149,26 +167,36 @@ variables:
|
||||
script: |
|
||||
set -Eeuo pipefail
|
||||
function runInNixShell() {
|
||||
time nix-shell .gitlab/shell.nix \
|
||||
time nix-shell $CI_PROJECT_DIR/.gitlab/shell.nix \
|
||||
-I nixpkgs=https://github.com/angerman/nixpkgs/archive/75f7281738b.tar.gz \
|
||||
--argstr system "x86_64-darwin" \
|
||||
--argstr system "aarch64-darwin" \
|
||||
--pure \
|
||||
--keep GHC_VERSION --keep CABAL_INSTALL_VERSION --keep BUILD_FLAVOUR \
|
||||
--keep BIN_DIST_PREP_TAR_COMP --keep CPUS --keep PROJECT_DIR \
|
||||
--keep CI_PROJECT_DIR --keep MAKE_ARGS --keep HADRIAN_ARGS --keep CABAL_CACHE \
|
||||
--keep LANG --keep CONFIGURE_ARGS --keep TEST_ENV --keep BIN_DIST_NAME \
|
||||
--keep MACOSX_DEPLOYMENT_TARGET --keep ac_cv_func_clock_gettime --keep HACKAGE_INDEX_STATE \
|
||||
--keep CABAL_DIR --keep ARCH --keep OS --keep CABAL_VERSION --keep GHC_VERSION \
|
||||
--keep JSON_VERSION --ARTIFACT \
|
||||
--keep CI_PROJECT_DIR \
|
||||
--keep MACOSX_DEPLOYMENT_TARGET \
|
||||
--keep JSON_VERSION \
|
||||
--keep ARTIFACT \
|
||||
--keep OS \
|
||||
--keep ARCH \
|
||||
--keep CABAL_DIR \
|
||||
--keep GHC_VERSION \
|
||||
--keep CABAL_VERSION \
|
||||
--run "$1" 2>&1
|
||||
}
|
||||
runInNixShell ./.gitlab/before_script/darwin/install_deps.sh 2>&1
|
||||
runInNixShell ./.gitlab/script/ghcup_version.sh 2>&1
|
||||
|
||||
.test_ghcup_version:freebsd:
|
||||
.test_ghcup_version:freebsd12:
|
||||
extends:
|
||||
- .test_ghcup_version
|
||||
- .freebsd
|
||||
- .freebsd12
|
||||
- .root_cleanup
|
||||
before_script:
|
||||
- ./.gitlab/before_script/freebsd/install_deps.sh
|
||||
|
||||
.test_ghcup_version:freebsd13:
|
||||
extends:
|
||||
- .test_ghcup_version
|
||||
- .freebsd13
|
||||
- .root_cleanup
|
||||
before_script:
|
||||
- ./.gitlab/before_script/freebsd/install_deps.sh
|
||||
@@ -182,6 +210,12 @@ variables:
|
||||
- set CABAL_DIR="$CI_PROJECT_DIR/cabal"
|
||||
- bash ./.gitlab/before_script/windows/install_deps.sh
|
||||
|
||||
# .test_ghcup_scoop:windows:
|
||||
# extends:
|
||||
# - .windows
|
||||
# - .test_ghcup_scoop
|
||||
# - .root_cleanup
|
||||
|
||||
.release_ghcup:
|
||||
script:
|
||||
- bash ./.gitlab/script/ghcup_release.sh
|
||||
@@ -189,10 +223,11 @@ variables:
|
||||
expire_in: 2 week
|
||||
paths:
|
||||
- out
|
||||
- dist-newstyle/cache/
|
||||
only:
|
||||
- tags
|
||||
variables:
|
||||
JSON_VERSION: "0.0.5"
|
||||
JSON_VERSION: "0.0.6"
|
||||
|
||||
######## stack test ########
|
||||
|
||||
@@ -209,121 +244,194 @@ test:linux:stack:
|
||||
######## bootstrap test ########
|
||||
|
||||
test:linux:bootstrap_script:
|
||||
stage: test
|
||||
stage: quick-test
|
||||
before_script:
|
||||
- ./.gitlab/before_script/linux/install_deps_minimal.sh
|
||||
script:
|
||||
- ./.gitlab/script/ghcup_bootstrap.sh
|
||||
variables:
|
||||
GHC_VERSION: "8.10.5"
|
||||
CABAL_VERSION: "3.4.0.0"
|
||||
GHC_VERSION: "8.10.7"
|
||||
CABAL_VERSION: "3.6.2.0"
|
||||
extends:
|
||||
- .debian
|
||||
- .root_cleanup
|
||||
needs: []
|
||||
|
||||
test:windows:bootstrap_powershell_script:
|
||||
stage: quick-test
|
||||
script:
|
||||
- ./scripts/bootstrap/bootstrap-haskell.ps1 -InstallDir $CI_PROJECT_DIR -BootstrapUrl $CI_PROJECT_DIR/bootstrap-haskell -InBash
|
||||
after_script:
|
||||
- "[Environment]::SetEnvironmentVariable('GHCUP_INSTALL_BASE_PREFIX', $null, [System.EnvironmentVariableTarget]::User)"
|
||||
- "[Environment]::SetEnvironmentVariable('GHCUP_MSYS2', $null, [System.EnvironmentVariableTarget]::User)"
|
||||
- "[Environment]::SetEnvironmentVariable('CABAL_DIR', $null, [System.EnvironmentVariableTarget]::User)"
|
||||
- bash ./.gitlab/after_script.sh
|
||||
variables:
|
||||
GHC_VERSION: "8.10.7"
|
||||
CABAL_VERSION: "3.6.2.0"
|
||||
extends:
|
||||
- .windows
|
||||
needs: []
|
||||
|
||||
######## linux test ########
|
||||
|
||||
test:linux:recommended:
|
||||
test:linux:
|
||||
stage: test
|
||||
extends: .test_ghcup_version:linux
|
||||
variables:
|
||||
GHC_VERSION: "8.10.5"
|
||||
CABAL_VERSION: "3.4.0.0"
|
||||
GHC_VERSION: "8.10.7"
|
||||
CABAL_VERSION: "3.6.2.0"
|
||||
needs: []
|
||||
|
||||
test:linux:latest:
|
||||
stage: test
|
||||
extends: .test_ghcup_version:linux
|
||||
test:linux:hls:
|
||||
stage: expensive-test
|
||||
extends:
|
||||
- .test_ghcup_version
|
||||
- .debian
|
||||
variables:
|
||||
GHC_VERSION: "9.0.1"
|
||||
CABAL_VERSION: "3.4.0.0"
|
||||
GHC_VERSION: "8.10.7"
|
||||
HLS_TARGET_VERSION: "1.4.0"
|
||||
CABAL_VERSION: "3.6.2.0"
|
||||
needs: []
|
||||
when: manual
|
||||
allow_failure: true
|
||||
before_script:
|
||||
- ./.gitlab/before_script/linux/install_deps.sh
|
||||
script:
|
||||
- ./.gitlab/script/ghcup_hls.sh
|
||||
|
||||
test:linux:cross-armv7:
|
||||
stage: expensive-test
|
||||
extends:
|
||||
- .test_ghcup_version
|
||||
- .debian
|
||||
variables:
|
||||
GHC_VERSION: "8.10.6"
|
||||
GHC_TARGET_VERSION: "8.10.7"
|
||||
CABAL_VERSION: "3.6.2.0"
|
||||
CROSS: "arm-linux-gnueabihf"
|
||||
needs: []
|
||||
when: manual
|
||||
allow_failure: true
|
||||
before_script:
|
||||
- ./.gitlab/before_script/linux/install_deps.sh
|
||||
script:
|
||||
- ./.gitlab/script/ghcup_cross.sh
|
||||
|
||||
test:linux:git:hadrian:
|
||||
stage: expensive-test
|
||||
extends:
|
||||
- .test_ghcup_version
|
||||
- .debian
|
||||
variables:
|
||||
GHC_VERSION: "8.10.7"
|
||||
GHC_GIT_TAG: "ghc-9.0.1-release"
|
||||
GHC_GIT_VERSION: "9.0.1"
|
||||
CABAL_VERSION: "3.6.2.0"
|
||||
CROSS: ""
|
||||
needs: []
|
||||
when: manual
|
||||
allow_failure: true
|
||||
before_script:
|
||||
- ./.gitlab/before_script/linux/install_deps.sh
|
||||
script:
|
||||
- ./.gitlab/script/ghcup_git.sh
|
||||
|
||||
|
||||
######## linux 32bit test ########
|
||||
|
||||
test:linux:recommended:32bit:
|
||||
test:linux:32bit:
|
||||
stage: test
|
||||
extends: .test_ghcup_version:linux32
|
||||
variables:
|
||||
GHC_VERSION: "8.10.5"
|
||||
CABAL_VERSION: "3.2.0.0"
|
||||
GHC_VERSION: "8.10.7"
|
||||
CABAL_VERSION: "3.6.2.0"
|
||||
needs: []
|
||||
|
||||
######## arm tests ########
|
||||
|
||||
test:linux:recommended:armv7:
|
||||
test:linux:armv7:
|
||||
stage: test
|
||||
extends: .test_ghcup_version:armv7
|
||||
variables:
|
||||
GHC_VERSION: "8.10.4"
|
||||
CABAL_VERSION: "3.4.0.0"
|
||||
GHC_VERSION: "8.10.7"
|
||||
CABAL_VERSION: "3.6.2.0"
|
||||
CROSS: ""
|
||||
when: manual
|
||||
needs: []
|
||||
|
||||
test:linux:recommended:aarch64:
|
||||
test:linux:aarch64:
|
||||
stage: test
|
||||
extends: .test_ghcup_version:aarch64
|
||||
variables:
|
||||
GHC_VERSION: "8.10.4"
|
||||
CABAL_VERSION: "3.4.0.0"
|
||||
GHC_VERSION: "8.10.7"
|
||||
CABAL_VERSION: "3.6.2.0"
|
||||
CROSS: ""
|
||||
when: manual
|
||||
needs: []
|
||||
|
||||
######## darwin test ########
|
||||
|
||||
test:mac:recommended:
|
||||
test:mac:
|
||||
stage: test
|
||||
extends: .test_ghcup_version:darwin
|
||||
variables:
|
||||
GHC_VERSION: "8.10.4"
|
||||
CABAL_VERSION: "3.4.0.0"
|
||||
GHC_VERSION: "8.10.7"
|
||||
CABAL_VERSION: "3.6.2.0"
|
||||
needs: []
|
||||
|
||||
test:mac:latest:
|
||||
stage: test
|
||||
extends: .test_ghcup_version:darwin
|
||||
variables:
|
||||
GHC_VERSION: "9.0.1"
|
||||
CABAL_VERSION: "3.4.0.0"
|
||||
needs: []
|
||||
|
||||
test:mac:recommended:aarch64:
|
||||
test:mac:aarch64:
|
||||
stage: test
|
||||
extends: .test_ghcup_version:darwin:aarch64
|
||||
variables:
|
||||
GHC_VERSION: "8.10.5"
|
||||
CABAL_VERSION: "3.4.0.0"
|
||||
GHC_VERSION: "8.10.7"
|
||||
CABAL_VERSION: "3.6.2.0"
|
||||
needs: []
|
||||
allow_failure: true
|
||||
|
||||
|
||||
######## freebsd test ########
|
||||
|
||||
test:freebsd:recommended:
|
||||
test:freebsd12:
|
||||
stage: test
|
||||
extends: .test_ghcup_version:freebsd
|
||||
extends: .test_ghcup_version:freebsd12
|
||||
variables:
|
||||
GHC_VERSION: "8.10.4"
|
||||
CABAL_VERSION: "3.4.0.0"
|
||||
GHC_VERSION: "8.10.7"
|
||||
CABAL_VERSION: "3.6.2.0"
|
||||
allow_failure: true # freebsd runners are unreliable
|
||||
when: manual
|
||||
needs: []
|
||||
|
||||
test:freebsd13:
|
||||
stage: test
|
||||
extends: .test_ghcup_version:freebsd13
|
||||
variables:
|
||||
GHC_VERSION: "8.10.7"
|
||||
CABAL_VERSION: "3.6.2.0"
|
||||
allow_failure: true # freebsd runners are unreliable
|
||||
when: manual
|
||||
needs: []
|
||||
|
||||
######## windows test ########
|
||||
|
||||
test:windows:recommended:
|
||||
test:windows:
|
||||
stage: test
|
||||
extends: .test_ghcup_version:windows
|
||||
variables:
|
||||
GHC_VERSION: "8.10.5"
|
||||
CABAL_VERSION: "3.4.0.0"
|
||||
GHC_VERSION: "8.10.7"
|
||||
CABAL_VERSION: "3.6.2.0"
|
||||
needs: []
|
||||
|
||||
# test:windows:scoop:
|
||||
# stage: test
|
||||
# extends: .test_ghcup_scoop:windows
|
||||
# needs: []
|
||||
|
||||
######## linux release ########
|
||||
|
||||
release:linux:64bit:
|
||||
stage: release
|
||||
needs: ["test:linux:recommended", "test:linux:latest"]
|
||||
needs: ["test:linux"]
|
||||
extends:
|
||||
- .alpine:64bit
|
||||
- .release_ghcup
|
||||
@@ -331,13 +439,13 @@ release:linux:64bit:
|
||||
- ./.gitlab/before_script/linux/alpine/install_deps.sh
|
||||
variables:
|
||||
ARTIFACT: "x86_64-linux-ghcup"
|
||||
GHC_VERSION: "8.10.5"
|
||||
CABAL_VERSION: "3.4.0.0"
|
||||
GHC_VERSION: "8.10.7"
|
||||
CABAL_VERSION: "3.6.2.0"
|
||||
|
||||
|
||||
release:linux:32bit:
|
||||
stage: release
|
||||
needs: ["test:linux:recommended:32bit"]
|
||||
needs: ["test:linux:32bit"]
|
||||
extends:
|
||||
- .alpine:32bit
|
||||
- .release_ghcup
|
||||
@@ -345,40 +453,42 @@ release:linux:32bit:
|
||||
- ./.gitlab/before_script/linux/alpine/install_deps.sh
|
||||
variables:
|
||||
ARTIFACT: "i386-linux-ghcup"
|
||||
GHC_VERSION: "8.10.5"
|
||||
CABAL_VERSION: "3.2.0.0"
|
||||
GHC_VERSION: "8.10.7"
|
||||
CABAL_VERSION: "3.6.2.0"
|
||||
|
||||
release:linux:armv7:
|
||||
stage: release
|
||||
needs: ["test:linux:recommended:armv7"]
|
||||
needs: ["test:linux:armv7"]
|
||||
extends:
|
||||
- .linux:armv7
|
||||
- .release_ghcup
|
||||
before_script:
|
||||
- ./.gitlab/before_script/linux/install_deps_manual.sh
|
||||
- ./.gitlab/before_script/linux/install_deps.sh
|
||||
variables:
|
||||
ARTIFACT: "armv7-linux-ghcup"
|
||||
GHC_VERSION: "8.10.4"
|
||||
CABAL_VERSION: "3.4.0.0"
|
||||
GHC_VERSION: "8.10.7"
|
||||
CABAL_VERSION: "3.6.2.0"
|
||||
CROSS: ""
|
||||
|
||||
release:linux:aarch64:
|
||||
stage: release
|
||||
needs: ["test:linux:recommended:aarch64"]
|
||||
needs: ["test:linux:aarch64"]
|
||||
extends:
|
||||
- .linux:aarch64
|
||||
- .release_ghcup
|
||||
before_script:
|
||||
- ./.gitlab/before_script/linux/install_deps_manual.sh
|
||||
- ./.gitlab/before_script/linux/install_deps.sh
|
||||
variables:
|
||||
ARTIFACT: "aarch64-linux-ghcup"
|
||||
GHC_VERSION: "8.10.4"
|
||||
CABAL_VERSION: "3.4.0.0"
|
||||
GHC_VERSION: "8.10.7"
|
||||
CABAL_VERSION: "3.6.2.0"
|
||||
CROSS: ""
|
||||
|
||||
######## darwin release ########
|
||||
|
||||
release:darwin:
|
||||
stage: release
|
||||
needs: ["test:mac:recommended", "test:mac:latest"]
|
||||
needs: ["test:mac"]
|
||||
extends:
|
||||
- .darwin
|
||||
- .release_ghcup
|
||||
@@ -387,65 +497,82 @@ release:darwin:
|
||||
- ./.gitlab/before_script/darwin/install_deps.sh
|
||||
variables:
|
||||
ARTIFACT: "x86_64-apple-darwin-ghcup"
|
||||
GHC_VERSION: "8.10.5"
|
||||
CABAL_VERSION: "3.4.0.0"
|
||||
GHC_VERSION: "8.10.7"
|
||||
CABAL_VERSION: "3.6.2.0"
|
||||
MACOSX_DEPLOYMENT_TARGET: "10.7"
|
||||
|
||||
release:darwin:aarch64:
|
||||
stage: release
|
||||
needs: ["test:mac:recommended:aarch64"]
|
||||
needs: ["test:mac:aarch64"]
|
||||
extends:
|
||||
- .darwin:aarch64
|
||||
- .release_ghcup
|
||||
- .root_cleanup
|
||||
before_script:
|
||||
- ./.gitlab/before_script/darwin/install_deps.sh
|
||||
script: |
|
||||
set -Eeuo pipefail
|
||||
function runInNixShell() {
|
||||
time nix-shell $CI_PROJECT_DIR/.gitlab/shell.nix \
|
||||
-I nixpkgs=https://github.com/angerman/nixpkgs/archive/75f7281738b.tar.gz \
|
||||
--argstr system "aarch64-darwin" \
|
||||
--pure \
|
||||
--keep CI_PROJECT_DIR \
|
||||
--keep MACOSX_DEPLOYMENT_TARGET \
|
||||
--keep JSON_VERSION \
|
||||
--keep ARTIFACT \
|
||||
--keep OS \
|
||||
--keep ARCH \
|
||||
--keep CABAL_DIR \
|
||||
--keep GHC_VERSION \
|
||||
--keep CABAL_VERSION \
|
||||
--run "$1" 2>&1
|
||||
}
|
||||
runInNixShell ./.gitlab/before_script/darwin/install_deps.sh 2>&1
|
||||
runInNixShell ./.gitlab/script/ghcup_release.sh 2>&1
|
||||
variables:
|
||||
ARTIFACT: "aarch64-apple-darwin-ghcup"
|
||||
GHC_VERSION: "8.10.5"
|
||||
CABAL_VERSION: "3.4.0.0"
|
||||
GHC_VERSION: "8.10.7"
|
||||
CABAL_VERSION: "3.6.2.0"
|
||||
MACOSX_DEPLOYMENT_TARGET: "10.7"
|
||||
allow_failure: true
|
||||
|
||||
|
||||
######## freebsd release ########
|
||||
|
||||
release:freebsd:
|
||||
release:freebsd12:
|
||||
stage: release
|
||||
needs: ["test:freebsd:recommended"]
|
||||
needs: ["test:freebsd12"]
|
||||
extends:
|
||||
- .freebsd
|
||||
- .freebsd12
|
||||
- .release_ghcup
|
||||
- .root_cleanup
|
||||
script: |
|
||||
set -Eeuo pipefail
|
||||
function runInNixShell() {
|
||||
time nix-shell .gitlab/shell.nix \
|
||||
-I nixpkgs=https://github.com/angerman/nixpkgs/archive/75f7281738b.tar.gz \
|
||||
--argstr system "x86_64-darwin" \
|
||||
--pure \
|
||||
--keep GHC_VERSION --keep CABAL_INSTALL_VERSION --keep BUILD_FLAVOUR \
|
||||
--keep BIN_DIST_PREP_TAR_COMP --keep CPUS --keep PROJECT_DIR \
|
||||
--keep CI_PROJECT_DIR --keep MAKE_ARGS --keep HADRIAN_ARGS --keep CABAL_CACHE \
|
||||
--keep LANG --keep CONFIGURE_ARGS --keep TEST_ENV --keep BIN_DIST_NAME \
|
||||
--keep MACOSX_DEPLOYMENT_TARGET --keep ac_cv_func_clock_gettime --keep HACKAGE_INDEX_STATE \
|
||||
--keep CABAL_DIR --keep ARCH --keep OS --keep CABAL_VERSION --keep GHC_VERSION \
|
||||
--keep JSON_VERSION --ARTIFACT \
|
||||
--run "$1" 2>&1
|
||||
}
|
||||
runInNixShell ./.gitlab/before_script/freebsd/install_deps.sh 2>&1
|
||||
runInNixShell ./.gitlab/script/ghcup_release.sh 2>&1
|
||||
before_script:
|
||||
- ./.gitlab/before_script/freebsd/install_deps.sh
|
||||
variables:
|
||||
ARTIFACT: "x86_64-portbld-freebsd-ghcup"
|
||||
GHC_VERSION: "8.10.5"
|
||||
CABAL_VERSION: "3.4.0.0"
|
||||
GHC_VERSION: "8.10.7"
|
||||
CABAL_VERSION: "3.6.2.0"
|
||||
allow_failure: true
|
||||
|
||||
release:freebsd13:
|
||||
stage: release
|
||||
needs: ["test:freebsd13"]
|
||||
extends:
|
||||
- .freebsd13
|
||||
- .release_ghcup
|
||||
- .root_cleanup
|
||||
before_script:
|
||||
- ./.gitlab/before_script/freebsd/install_deps.sh
|
||||
variables:
|
||||
ARTIFACT: "x86_64-portbld-freebsd-ghcup"
|
||||
GHC_VERSION: "8.10.7"
|
||||
CABAL_VERSION: "3.6.2.0"
|
||||
allow_failure: true
|
||||
|
||||
######## windows release ########
|
||||
|
||||
release:windows:
|
||||
stage: release
|
||||
needs: ["test:windows:recommended"]
|
||||
needs: ["test:windows"]
|
||||
extends:
|
||||
- .windows
|
||||
- .release_ghcup
|
||||
@@ -454,26 +581,46 @@ release:windows:
|
||||
- bash ./.gitlab/before_script/windows/install_deps.sh
|
||||
variables:
|
||||
ARTIFACT: "x86_64-mingw64-ghcup"
|
||||
GHC_VERSION: "8.10.5"
|
||||
CABAL_VERSION: "3.4.0.0"
|
||||
GHC_VERSION: "8.10.7"
|
||||
CABAL_VERSION: "3.6.2.0"
|
||||
|
||||
######## hlint ########
|
||||
|
||||
hlint:
|
||||
stage: hlint
|
||||
stage: checks
|
||||
extends:
|
||||
- .alpine:64bit
|
||||
before_script:
|
||||
- ./.gitlab/before_script/linux/alpine/install_deps.sh
|
||||
- .debian
|
||||
script:
|
||||
- ./.gitlab/script/hlint.sh
|
||||
variables:
|
||||
GHC_VERSION: "8.10.5"
|
||||
CABAL_VERSION: "3.4.0.0"
|
||||
JSON_VERSION: "0.0.4"
|
||||
- curl -sSL https://raw.github.com/ndmitchell/hlint/master/misc/run.sh | sh -s -- -r lib/ test/
|
||||
allow_failure: true
|
||||
artifacts:
|
||||
expire_in: 2 week
|
||||
paths:
|
||||
- report.html
|
||||
when: on_failure
|
||||
|
||||
######## mkdocs ########
|
||||
|
||||
mkdocs:
|
||||
stage: checks
|
||||
extends:
|
||||
- .debian
|
||||
before_script:
|
||||
- sudo apt-get update -y
|
||||
- sudo apt-get install -y python3-pip
|
||||
- pip3 install mkdocs
|
||||
script:
|
||||
- ~/.local/bin/mkdocs build
|
||||
allow_failure: true
|
||||
|
||||
######## shellcheck ########
|
||||
|
||||
shellcheck:
|
||||
image: "koalaman/shellcheck-alpine"
|
||||
tags:
|
||||
- x86_64-linux
|
||||
stage: checks
|
||||
script:
|
||||
- shellcheck scripts/bootstrap/bootstrap-haskell
|
||||
allow_failure: true
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ set -eux
|
||||
mkdir -p "${TMPDIR}"
|
||||
|
||||
if [ $ARCH = 'ARM64' ] ; then
|
||||
curl -sSfL https://downloads.haskell.org/~ghcup/0.1.15.1/aarch64-apple-darwin-ghcup-0.1.15.1 > ./ghcup-bin
|
||||
curl -sSfL https://downloads.haskell.org/~ghcup/aarch64-apple-darwin-ghcup > ./ghcup-bin
|
||||
chmod +x ghcup-bin
|
||||
else
|
||||
curl -sSfL https://downloads.haskell.org/~ghcup/x86_64-apple-darwin-ghcup > ./ghcup-bin
|
||||
@@ -19,4 +19,14 @@ fi
|
||||
./ghcup-bin set ${GHC_VERSION}
|
||||
./ghcup-bin install-cabal ${CABAL_VERSION}
|
||||
|
||||
if [ $ARCH = 'ARM64' ] ; then
|
||||
cabal update
|
||||
mkdir vendored
|
||||
cd vendored
|
||||
cabal unpack network-3.1.2.1
|
||||
cd network*
|
||||
autoreconf -fi
|
||||
cd ../..
|
||||
fi
|
||||
|
||||
exit 0
|
||||
|
||||
@@ -11,9 +11,9 @@ mkdir -p "${TMPDIR}"
|
||||
curl -sSfL https://downloads.haskell.org/~ghcup/x86_64-portbld-freebsd-ghcup > ./ghcup-bin
|
||||
chmod +x ghcup-bin
|
||||
|
||||
./ghcup-bin upgrade -i -f
|
||||
./ghcup-bin install ${GHC_VERSION}
|
||||
./ghcup-bin set ${GHC_VERSION}
|
||||
./ghcup-bin install-cabal ${CABAL_VERSION}
|
||||
./ghcup-bin -v upgrade -i -f
|
||||
./ghcup-bin -v install ${GHC_VERSION}
|
||||
./ghcup-bin -v set ${GHC_VERSION}
|
||||
./ghcup-bin -v install-cabal ${CABAL_VERSION}
|
||||
|
||||
exit 0
|
||||
|
||||
@@ -52,3 +52,7 @@ apk add --no-cache \
|
||||
xz-dev \
|
||||
ncurses-static
|
||||
|
||||
if [ "${ARCH}" = "32" ] ; then
|
||||
apk add --no-cache \
|
||||
bsd-compat-headers
|
||||
fi
|
||||
|
||||
@@ -7,13 +7,21 @@ set -eux
|
||||
mkdir -p "${TMPDIR}"
|
||||
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y libnuma-dev zlib1g-dev libgmp-dev libgmp10 libssl-dev liblzma-dev libbz2-dev git wget
|
||||
sudo apt-get install -y libnuma-dev zlib1g-dev libgmp-dev libgmp10 libssl-dev liblzma-dev libbz2-dev git wget lsb-release software-properties-common gnupg2 apt-transport-https gcc autoconf automake build-essential
|
||||
|
||||
curl -sSfL https://downloads.haskell.org/~ghcup/x86_64-linux-ghcup > ./ghcup-bin
|
||||
chmod +x ghcup-bin
|
||||
if [ "${CROSS}" = "arm-linux-gnueabihf" ] ; then
|
||||
sudo apt-get install -y gcc-arm-linux-gnueabihf
|
||||
sudo dpkg --add-architecture armhf
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y libncurses-dev:armhf
|
||||
fi
|
||||
|
||||
./ghcup-bin upgrade -i -f
|
||||
./ghcup-bin install ${GHC_VERSION}
|
||||
./ghcup-bin set ${GHC_VERSION}
|
||||
./ghcup-bin install-cabal ${CABAL_VERSION}
|
||||
export BOOTSTRAP_HASKELL_NONINTERACTIVE=1
|
||||
export BOOTSTRAP_HASKELL_GHC_VERSION=$GHC_VERSION
|
||||
export BOOTSTRAP_HASKELL_CABAL_VERSION=$CABAL_VERSION
|
||||
export BOOTSTRAP_HASKELL_VERBOSE=1
|
||||
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh
|
||||
|
||||
rm "${GHCUP_INSTALL_BASE_PREFIX}"/.ghcup/bin/ghcup
|
||||
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eux
|
||||
|
||||
. "$( cd "$(dirname "$0")" ; pwd -P )/../../ghcup_env"
|
||||
|
||||
mkdir -p "${TMPDIR}"
|
||||
|
||||
ednf() {
|
||||
case "${ARCH}" in
|
||||
"ARM")
|
||||
sudo dnf -y --forcearch armv7hl "$@"
|
||||
;;
|
||||
"ARM64")
|
||||
sudo dnf -y --forcearch aarch64 "$@"
|
||||
;;
|
||||
*) exit 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
ednf update
|
||||
ednf install gcc gcc-c++ gmp gmp-devel make ncurses ncurses-devel xz xz-devel perl zlib zlib-devel openssl-devel openssl-libs openssl libffi libffi-devel lbzip2 lbzip2-utils bzip2-devel
|
||||
if [ "${ARCH}" = "ARM64" ] ; then
|
||||
ednf install numactl numactl-libs numactl-devel
|
||||
fi
|
||||
ednf install bash wget curl git tar
|
||||
ednf install llvm9.0 llvm9.0-devel llvm9.0-libs llvm9.0-static
|
||||
|
||||
case "${ARCH}" in
|
||||
"ARM")
|
||||
ghc_url=https://downloads.haskell.org/~ghc/${GHC_VERSION}/ghc-${GHC_VERSION}-armv7-deb10-linux.tar.xz
|
||||
cabal_url=home.smart-cactus.org/~ben/cabal-install-${CABAL_VERSION}-armv7-linux-bootstrapped.tar.xz
|
||||
;;
|
||||
"ARM64")
|
||||
ghc_url=https://downloads.haskell.org/~ghc/${GHC_VERSION}/ghc-${GHC_VERSION}-aarch64-deb10-linux.tar.xz
|
||||
cabal_url=https://downloads.haskell.org/~cabal/cabal-install-${CABAL_VERSION}/cabal-install-${CABAL_VERSION}-aarch64-ubuntu-18.04.tar.xz
|
||||
;;
|
||||
*) exit 1 ;;
|
||||
esac
|
||||
|
||||
mkdir -p "${GHCUP_INSTALL_BASE_PREFIX}"/.ghcup/bin
|
||||
|
||||
curl -O "${ghc_url}"
|
||||
tar -xf ghc-*.tar.*
|
||||
cd ghc-${GHC_VERSION}
|
||||
./configure --prefix="${GHCUP_INSTALL_BASE_PREFIX}"/.ghcup/ghc/${GHC_VERSION}
|
||||
make install
|
||||
for i in "${GHCUP_INSTALL_BASE_PREFIX}"/.ghcup/ghc/${GHC_VERSION}/bin/*-${GHC_VERSION} ; do
|
||||
ln -s "${i}" "${GHCUP_INSTALL_BASE_PREFIX}"/.ghcup/bin/${i##*/}
|
||||
done
|
||||
for x in "${GHCUP_INSTALL_BASE_PREFIX}"/.ghcup/bin/*-${GHC_VERSION} ; do
|
||||
ln -s ${x##*/} ${x%-${GHC_VERSION}}
|
||||
done
|
||||
cd ..
|
||||
rm -rf ghc-${GHC_VERSION} ghc-*.tar.*
|
||||
unset x i
|
||||
|
||||
mkdir cabal-install
|
||||
cd cabal-install
|
||||
curl -O "${cabal_url}"
|
||||
tar -xf cabal-install-*
|
||||
mv cabal "${GHCUP_INSTALL_BASE_PREFIX}"/.ghcup/bin/cabal
|
||||
cd ..
|
||||
rm -rf cabal-install
|
||||
@@ -9,7 +9,7 @@ mkdir -p "${TMPDIR}" "${CABAL_DIR}"
|
||||
mkdir -p "$GHCUP_INSTALL_BASE_PREFIX/ghcup/bin"
|
||||
|
||||
CI_PROJECT_DIR=$(pwd)
|
||||
curl -o ghcup.exe https://downloads.haskell.org/~ghcup/0.1.15.1/x86_64-mingw64-ghcup-0.1.15.1.exe
|
||||
curl -o ghcup.exe https://downloads.haskell.org/~ghcup/x86_64-mingw64-ghcup.exe
|
||||
chmod +x ghcup.exe
|
||||
|
||||
./ghcup.exe install ${GHC_VERSION}
|
||||
|
||||
8734
.gitlab/ghc-8.10.3-linux.files
Normal file
10321
.gitlab/ghc-8.10.3-windows.files
Normal file
@@ -1,9 +1,11 @@
|
||||
if [ "${OS}" = "WINDOWS" ] ; then
|
||||
export GHCUP_INSTALL_BASE_PREFIX="$CI_PROJECT_DIR"
|
||||
export PATH="$GHCUP_INSTALL_BASE_PREFIX/ghcup/bin:$CI_PROJECT_DIR/.local/bin:$PATH"
|
||||
export GHCUP_BIN="$CI_PROJECT_DIR/ghcup/bin"
|
||||
export PATH="$GHCUP_BIN:$CI_PROJECT_DIR/.local/bin:$PATH"
|
||||
export TMPDIR="$CI_PROJECT_DIR/tmp"
|
||||
else
|
||||
export GHCUP_INSTALL_BASE_PREFIX="$CI_PROJECT_DIR"
|
||||
export PATH="$CI_PROJECT_DIR/.ghcup/bin:$CI_PROJECT_DIR/.local/bin:$PATH"
|
||||
export GHCUP_BIN="$CI_PROJECT_DIR/.ghcup/bin"
|
||||
export PATH="$GHCUP_BIN:$CI_PROJECT_DIR/.local/bin:/opt/llvm/bin:$PATH"
|
||||
export TMPDIR="$CI_PROJECT_DIR/tmp"
|
||||
fi
|
||||
|
||||
@@ -24,7 +24,7 @@ export BOOTSTRAP_HASKELL_NONINTERACTIVE=yes
|
||||
export BOOTSTRAP_HASKELL_GHC_VERSION=$GHC_VERSION
|
||||
export BOOTSTRAP_HASKELL_CABAL_VERSION=$CABAL_VERSION
|
||||
|
||||
./bootstrap-haskell
|
||||
./scripts/bootstrap/bootstrap-haskell
|
||||
|
||||
[ "$(ghc --numeric-version)" = "${GHC_VERSION}" ]
|
||||
|
||||
|
||||
52
.gitlab/script/ghcup_cross.sh
Executable file
@@ -0,0 +1,52 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eux
|
||||
|
||||
. "$( cd "$(dirname "$0")" ; pwd -P )/../ghcup_env"
|
||||
|
||||
mkdir -p "$CI_PROJECT_DIR"/.local/bin
|
||||
|
||||
CI_PROJECT_DIR=$(pwd)
|
||||
|
||||
ecabal() {
|
||||
cabal "$@"
|
||||
}
|
||||
|
||||
eghcup() {
|
||||
ghcup -v -c -s file://$CI_PROJECT_DIR/data/metadata/ghcup-${JSON_VERSION}.yaml "$@"
|
||||
}
|
||||
|
||||
git describe --always
|
||||
|
||||
### build
|
||||
|
||||
ecabal update
|
||||
|
||||
ecabal build -w ghc-${GHC_VERSION}
|
||||
cp "$(ecabal new-exec -w ghc-${GHC_VERSION} --verbose=0 --offline sh -- -c 'command -v ghcup')" "$CI_PROJECT_DIR"/.local/bin/ghcup
|
||||
|
||||
### cleanup
|
||||
|
||||
rm -rf "${GHCUP_INSTALL_BASE_PREFIX}"/.ghcup
|
||||
|
||||
### manual cli based testing
|
||||
|
||||
eghcup --numeric-version
|
||||
|
||||
eghcup install ghc ${GHC_VERSION}
|
||||
eghcup set ghc ${GHC_VERSION}
|
||||
eghcup install cabal ${CABAL_VERSION}
|
||||
|
||||
cabal --version
|
||||
|
||||
eghcup debug-info
|
||||
|
||||
eghcup compile ghc -j $(nproc) -v ${GHC_TARGET_VERSION} -b ${GHC_VERSION} -x ${CROSS} -- --enable-unregisterised
|
||||
eghcup set ghc ${CROSS}-${GHC_TARGET_VERSION}
|
||||
|
||||
[ `$(eghcup whereis ghc ${CROSS}-${GHC_TARGET_VERSION}) --numeric-version` = "${GHC_TARGET_VERSION}" ]
|
||||
|
||||
# nuke
|
||||
eghcup nuke
|
||||
[ ! -e "${GHCUP_INSTALL_BASE_PREFIX}/.ghcup" ]
|
||||
|
||||
52
.gitlab/script/ghcup_git.sh
Executable file
@@ -0,0 +1,52 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eux
|
||||
|
||||
. "$( cd "$(dirname "$0")" ; pwd -P )/../ghcup_env"
|
||||
|
||||
mkdir -p "$CI_PROJECT_DIR"/.local/bin
|
||||
|
||||
CI_PROJECT_DIR=$(pwd)
|
||||
|
||||
ecabal() {
|
||||
cabal "$@"
|
||||
}
|
||||
|
||||
eghcup() {
|
||||
ghcup -v -c -s file://$CI_PROJECT_DIR/data/metadata/ghcup-${JSON_VERSION}.yaml "$@"
|
||||
}
|
||||
|
||||
git describe --always
|
||||
|
||||
### build
|
||||
|
||||
ecabal update
|
||||
|
||||
ecabal build -w ghc-${GHC_VERSION}
|
||||
cp "$(ecabal new-exec -w ghc-${GHC_VERSION} --verbose=0 --offline sh -- -c 'command -v ghcup')" "$CI_PROJECT_DIR"/.local/bin/ghcup
|
||||
|
||||
### cleanup
|
||||
|
||||
rm -rf "${GHCUP_INSTALL_BASE_PREFIX}"/.ghcup
|
||||
|
||||
### manual cli based testing
|
||||
|
||||
eghcup --numeric-version
|
||||
|
||||
eghcup install ghc ${GHC_VERSION}
|
||||
eghcup set ghc ${GHC_VERSION}
|
||||
eghcup install cabal ${CABAL_VERSION}
|
||||
|
||||
cabal --version
|
||||
|
||||
eghcup debug-info
|
||||
|
||||
eghcup compile ghc -j $(nproc) -g ${GHC_GIT_TAG} -b ${GHC_VERSION} -- --enable-unregisterised
|
||||
eghcup set ghc ${GHC_GIT_VERSION}
|
||||
|
||||
[ `$(eghcup whereis ghc ${GHC_GIT_VERSION}) --numeric-version` = "${GHC_GIT_VERSION}" ]
|
||||
|
||||
# nuke
|
||||
eghcup nuke
|
||||
[ ! -e "${GHCUP_INSTALL_BASE_PREFIX}/.ghcup" ]
|
||||
|
||||
51
.gitlab/script/ghcup_hls.sh
Executable file
@@ -0,0 +1,51 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eux
|
||||
|
||||
. "$( cd "$(dirname "$0")" ; pwd -P )/../ghcup_env"
|
||||
|
||||
mkdir -p "$CI_PROJECT_DIR"/.local/bin
|
||||
|
||||
CI_PROJECT_DIR=$(pwd)
|
||||
|
||||
ecabal() {
|
||||
cabal "$@"
|
||||
}
|
||||
|
||||
eghcup() {
|
||||
ghcup -v -c -s file://$CI_PROJECT_DIR/data/metadata/ghcup-${JSON_VERSION}.yaml "$@"
|
||||
}
|
||||
|
||||
git describe --always
|
||||
|
||||
### build
|
||||
|
||||
ecabal update
|
||||
|
||||
ecabal build -w ghc-${GHC_VERSION}
|
||||
cp "$(ecabal new-exec -w ghc-${GHC_VERSION} --verbose=0 --offline sh -- -c 'command -v ghcup')" "$CI_PROJECT_DIR"/.local/bin/ghcup
|
||||
|
||||
### cleanup
|
||||
|
||||
rm -rf "${GHCUP_INSTALL_BASE_PREFIX}"/.ghcup
|
||||
|
||||
### manual cli based testing
|
||||
|
||||
eghcup --numeric-version
|
||||
|
||||
eghcup install ghc ${GHC_VERSION}
|
||||
eghcup set ghc ${GHC_VERSION}
|
||||
eghcup install cabal ${CABAL_VERSION}
|
||||
|
||||
cabal --version
|
||||
|
||||
eghcup debug-info
|
||||
|
||||
eghcup compile hls -j $(nproc) -v ${HLS_TARGET_VERSION} ${GHC_VERSION}
|
||||
|
||||
[ `$(eghcup whereis hls ${HLS_TARGET_VERSION}) --numeric-version` = "${HLS_TARGET_VERSION}" ] || [ `$(eghcup whereis hls ${HLS_TARGET_VERSION}) --numeric-version | sed 's/.0$//'` = "${HLS_TARGET_VERSION}" ]
|
||||
|
||||
# nuke
|
||||
eghcup nuke
|
||||
[ ! -e "${GHCUP_INSTALL_BASE_PREFIX}/.ghcup" ]
|
||||
|
||||
@@ -15,14 +15,10 @@ git describe
|
||||
# build
|
||||
ecabal update
|
||||
|
||||
(
|
||||
cd /tmp
|
||||
ecabal install -w ghc-${GHC_VERSION} --installdir="$CI_PROJECT_DIR"/.local/bin hspec-discover
|
||||
)
|
||||
|
||||
if [ "${OS}" = "LINUX" ] ; then
|
||||
if [ "${ARCH}" = "32" ] ; then
|
||||
ecabal build -w ghc-${GHC_VERSION} --ghc-options='-split-sections -optl-static' -ftui -ftar
|
||||
ecabal build -w ghc-${GHC_VERSION} --ghc-options='-split-sections -optl-static' -ftui
|
||||
elif [ "${ARCH}" = "64" ] ; then
|
||||
ecabal build -w ghc-${GHC_VERSION} --ghc-options='-split-sections -optl-static' -ftui
|
||||
else
|
||||
|
||||
@@ -12,38 +12,55 @@ ecabal() {
|
||||
cabal "$@"
|
||||
}
|
||||
|
||||
raw_eghcup() {
|
||||
ghcup -v -c "$@"
|
||||
}
|
||||
|
||||
eghcup() {
|
||||
if [ "${OS}" = "WINDOWS" ] ; then
|
||||
ghcup -v -c -s file:/$CI_PROJECT_DIR/ghcup-${JSON_VERSION}.yaml "$@"
|
||||
ghcup -v -c -s file:/$CI_PROJECT_DIR/data/metadata/ghcup-${JSON_VERSION}.yaml "$@"
|
||||
else
|
||||
ghcup -v -c -s file://$CI_PROJECT_DIR/ghcup-${JSON_VERSION}.yaml "$@"
|
||||
ghcup -v -c -s file://$CI_PROJECT_DIR/data/metadata/ghcup-${JSON_VERSION}.yaml "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
if [ "${OS}" = "WINDOWS" ] ; then
|
||||
GHCUP_DIR="${GHCUP_INSTALL_BASE_PREFIX}"/ghcup
|
||||
else
|
||||
GHCUP_DIR="${GHCUP_INSTALL_BASE_PREFIX}"/.ghcup
|
||||
fi
|
||||
|
||||
git describe --always
|
||||
|
||||
### build
|
||||
|
||||
ecabal update
|
||||
|
||||
(
|
||||
cd /tmp
|
||||
ecabal install -w ghc-${GHC_VERSION} --installdir="$CI_PROJECT_DIR"/.local/bin hspec-discover
|
||||
)
|
||||
|
||||
if [ "${OS}" = "DARWIN" ] ; then
|
||||
ecabal build -w ghc-${GHC_VERSION} -ftui
|
||||
ecabal test -w ghc-${GHC_VERSION} -ftui ghcup-test
|
||||
ecabal haddock -w ghc-${GHC_VERSION} -ftui
|
||||
elif [ "${OS}" = "LINUX" ] ; then
|
||||
if [ "${ARCH}" = "32" ] ; then
|
||||
ecabal build -w ghc-${GHC_VERSION} -finternal-downloader -ftui -ftar
|
||||
ecabal test -w ghc-${GHC_VERSION} -finternal-downloader -ftui -ftar ghcup-test
|
||||
ecabal haddock -w ghc-${GHC_VERSION} -finternal-downloader -ftui -ftar
|
||||
ecabal build -w ghc-${GHC_VERSION} -finternal-downloader -ftui
|
||||
ecabal test -w ghc-${GHC_VERSION} -finternal-downloader -ftui ghcup-test
|
||||
ecabal haddock -w ghc-${GHC_VERSION} -finternal-downloader -ftui
|
||||
else
|
||||
ecabal build -w ghc-${GHC_VERSION} -finternal-downloader -ftui
|
||||
ecabal test -w ghc-${GHC_VERSION} -finternal-downloader -ftui ghcup-test
|
||||
ecabal haddock -w ghc-${GHC_VERSION} -finternal-downloader -ftui
|
||||
|
||||
if [ "${ARCH}" = "64" ] ; then
|
||||
# doctest
|
||||
curl -sL https://downloads.haskell.org/~ghcup/unofficial-bindists/cabal-docspec/cabal-docspec-0.0.0.20210228_p1.tar.bz2 > cabal-docspec.tar.bz2
|
||||
echo '3a10f6fec16dbd18efdd331b1cef5d2d342082da42f5b520726d1fa6a3990d12 cabal-docspec.tar.bz2' | sha256sum -c -
|
||||
tar -xjf cabal-docspec.tar.bz2 cabal-docspec
|
||||
mv cabal-docspec "$CI_PROJECT_DIR"/.local/bin/cabal-docspec
|
||||
rm -f cabal-docspec.tar.bz2
|
||||
chmod a+x "$CI_PROJECT_DIR"/.local/bin/cabal-docspec
|
||||
|
||||
cabal-docspec -XCPP -XTypeSynonymInstances -XOverloadedStrings -XPackageImports --check-properties
|
||||
fi
|
||||
fi
|
||||
elif [ "${OS}" = "FREEBSD" ] ; then
|
||||
ecabal build -w ghc-${GHC_VERSION} -finternal-downloader -ftui --constraint="zip +disable-zstd"
|
||||
@@ -70,27 +87,30 @@ fi
|
||||
|
||||
### cleanup
|
||||
|
||||
if [ "${OS}" = "WINDOWS" ] ; then
|
||||
rm -rf "${GHCUP_INSTALL_BASE_PREFIX}"/ghcup
|
||||
else
|
||||
rm -rf "${GHCUP_INSTALL_BASE_PREFIX}"/.ghcup
|
||||
fi
|
||||
rm -rf "${GHCUP_DIR}"
|
||||
|
||||
### manual cli based testing
|
||||
|
||||
|
||||
ghcup-gen check -f ghcup-${JSON_VERSION}.yaml
|
||||
ghcup-gen check -f data/metadata/ghcup-${JSON_VERSION}.yaml
|
||||
|
||||
eghcup --numeric-version
|
||||
|
||||
eghcup install ${GHC_VERSION}
|
||||
eghcup set ${GHC_VERSION}
|
||||
eghcup install-cabal ${CABAL_VERSION}
|
||||
eghcup install ghc ${GHC_VERSION}
|
||||
[ `$(eghcup whereis ghc ${GHC_VERSION}) --numeric-version` = "${GHC_VERSION}" ]
|
||||
eghcup set ghc ${GHC_VERSION}
|
||||
eghcup install cabal ${CABAL_VERSION}
|
||||
[ `$(eghcup whereis cabal ${CABAL_VERSION}) --numeric-version` = "${CABAL_VERSION}" ]
|
||||
eghcup unset cabal
|
||||
"$GHCUP_BIN"/cabal --version && exit || echo yes
|
||||
eghcup set cabal ${CABAL_VERSION}
|
||||
[ `$(eghcup whereis cabal ${CABAL_VERSION}) --numeric-version` = "${CABAL_VERSION}" ]
|
||||
|
||||
cabal --version
|
||||
|
||||
eghcup debug-info
|
||||
|
||||
# also test etags
|
||||
eghcup list
|
||||
eghcup list -t ghc
|
||||
eghcup list -t cabal
|
||||
@@ -104,38 +124,70 @@ if [ "${OS}" != "WINDOWS" ] ; then
|
||||
fi
|
||||
|
||||
|
||||
# test installing new ghc doesn't mess with currently set GHC
|
||||
# https://gitlab.haskell.org/haskell/ghcup-hs/issues/7
|
||||
if [ "${OS}" = "LINUX" ] ; then
|
||||
eghcup --downloader=wget install 8.10.3
|
||||
else # test wget a bit
|
||||
eghcup install 8.10.3
|
||||
fi
|
||||
[ "$(ghc --numeric-version)" = "${ghc_ver}" ]
|
||||
eghcup set 8.10.3
|
||||
eghcup set 8.10.3
|
||||
[ "$(ghc --numeric-version)" = "8.10.3" ]
|
||||
eghcup set ${GHC_VERSION}
|
||||
[ "$(ghc --numeric-version)" = "${ghc_ver}" ]
|
||||
eghcup rm 8.10.3
|
||||
[ "$(ghc --numeric-version)" = "${ghc_ver}" ]
|
||||
if [ "${OS}" = "DARWIN" ] && [ "${ARCH}" = "ARM64" ] ; then
|
||||
echo
|
||||
else
|
||||
# test installing new ghc doesn't mess with currently set GHC
|
||||
# https://gitlab.haskell.org/haskell/ghcup-hs/issues/7
|
||||
if [ "${OS}" = "LINUX" ] ; then
|
||||
eghcup --downloader=wget prefetch ghc 8.10.3
|
||||
eghcup --offline install ghc 8.10.3
|
||||
if [ "${ARCH}" = "64" ] ; then
|
||||
expected=$(cat "$( cd "$(dirname "$0")" ; pwd -P )/../ghc-8.10.3-linux.files" | sort)
|
||||
actual=$(cd "${GHCUP_DIR}/ghc/8.10.3/" && find | sort)
|
||||
[ "${actual}" = "${expected}" ]
|
||||
unset actual expected
|
||||
fi
|
||||
elif [ "${OS}" = "WINDOWS" ] ; then
|
||||
eghcup prefetch ghc 8.10.3
|
||||
eghcup --offline install ghc 8.10.3
|
||||
expected=$(cat "$( cd "$(dirname "$0")" ; pwd -P )/../ghc-8.10.3-windows.files" | sort)
|
||||
actual=$(cd "${GHCUP_DIR}/ghc/8.10.3/" && find | sort)
|
||||
[ "${actual}" = "${expected}" ]
|
||||
unset actual expected
|
||||
else
|
||||
eghcup prefetch ghc 8.10.3
|
||||
eghcup --offline install ghc 8.10.3
|
||||
fi
|
||||
[ "$(ghc --numeric-version)" = "${ghc_ver}" ]
|
||||
eghcup --offline set 8.10.3
|
||||
eghcup set 8.10.3
|
||||
[ "$(ghc --numeric-version)" = "8.10.3" ]
|
||||
eghcup set ${GHC_VERSION}
|
||||
[ "$(ghc --numeric-version)" = "${ghc_ver}" ]
|
||||
eghcup unset ghc
|
||||
"$GHCUP_BIN"/ghc --numeric-version && exit || echo yes
|
||||
eghcup set ${GHC_VERSION}
|
||||
eghcup --offline rm 8.10.3
|
||||
[ "$(ghc --numeric-version)" = "${ghc_ver}" ]
|
||||
|
||||
if [ "${OS}" = "DARWIN" ] ; then
|
||||
eghcup install hls
|
||||
haskell-language-server-wrapper --version
|
||||
|
||||
eghcup install stack
|
||||
stack --version
|
||||
elif [ "${OS}" = "LINUX" ] ; then
|
||||
if [ "${ARCH}" = "64" ] ; then
|
||||
if [ "${OS}" = "DARWIN" ] ; then
|
||||
eghcup install hls
|
||||
haskell-language-server-wrapper --version
|
||||
$(eghcup whereis hls) --version
|
||||
|
||||
eghcup install stack
|
||||
stack --version
|
||||
$(eghcup whereis stack) --version
|
||||
elif [ "${OS}" = "LINUX" ] ; then
|
||||
if [ "${ARCH}" = "64" ] ; then
|
||||
eghcup install hls
|
||||
haskell-language-server-wrapper --version
|
||||
eghcup unset hls
|
||||
"$GHCUP_BIN"/haskell-language-server-wrapper --version && exit || echo yes
|
||||
|
||||
eghcup install stack
|
||||
stack --version
|
||||
eghcup unset hls
|
||||
"$GHCUP_BIN"/stack --version && exit || echo yes
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# check that lazy loading works for 'whereis'
|
||||
cp "$CI_PROJECT_DIR/data/metadata/ghcup-${JSON_VERSION}.yaml" "$CI_PROJECT_DIR/data/metadata/ghcup-${JSON_VERSION}.yaml.bak"
|
||||
echo '**' > "$CI_PROJECT_DIR/data/metadata/ghcup-${JSON_VERSION}.yaml"
|
||||
eghcup whereis ghc $(ghc --numeric-version)
|
||||
mv -f "$CI_PROJECT_DIR/data/metadata/ghcup-${JSON_VERSION}.yaml.bak" "$CI_PROJECT_DIR/data/metadata/ghcup-${JSON_VERSION}.yaml"
|
||||
|
||||
eghcup rm $(ghc --numeric-version)
|
||||
|
||||
@@ -147,6 +199,60 @@ if [ "${OS}" = "LINUX" ] ; then
|
||||
fi
|
||||
fi
|
||||
|
||||
sha_sum() {
|
||||
if [ "${OS}" = "FREEBSD" ] ; then
|
||||
sha256 "$@"
|
||||
else
|
||||
sha256sum "$@"
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
# test etags
|
||||
rm -f "${GHCUP_DIR}/cache/ghcup-${JSON_VERSION}.yaml"
|
||||
raw_eghcup -s https://www.haskell.org/ghcup/data/ghcup-${JSON_VERSION}.yaml list
|
||||
# snapshot yaml and etags file
|
||||
etag=$(cat "${GHCUP_DIR}/cache/ghcup-${JSON_VERSION}.yaml.etags")
|
||||
sha=$(sha_sum "${GHCUP_DIR}/cache/ghcup-${JSON_VERSION}.yaml")
|
||||
# invalidate access time timer, which is 5minutes, so we re-download
|
||||
touch -a -m -t '199901010101' "${GHCUP_DIR}/cache/ghcup-${JSON_VERSION}.yaml"
|
||||
# redownload same file with some newlines added
|
||||
raw_eghcup -s https://www.haskell.org/ghcup/exp/ghcup-${JSON_VERSION}.yaml list
|
||||
# snapshot new yaml and etags file
|
||||
etag2=$(cat "${GHCUP_DIR}/cache/ghcup-${JSON_VERSION}.yaml.etags")
|
||||
sha2=$(sha_sum "${GHCUP_DIR}/cache/ghcup-${JSON_VERSION}.yaml")
|
||||
# compare
|
||||
[ "${etag}" != "${etag2}" ]
|
||||
[ "${sha}" != "${sha2}" ]
|
||||
# invalidate access time timer, which is 5minutes, but don't expect a re-download
|
||||
touch -a -m -t '199901010101' "${GHCUP_DIR}/cache/ghcup-${JSON_VERSION}.yaml"
|
||||
# this time, we expect the same hash and etag
|
||||
raw_eghcup -s https://www.haskell.org/ghcup/exp/ghcup-${JSON_VERSION}.yaml list
|
||||
etag3=$(cat "${GHCUP_DIR}/cache/ghcup-${JSON_VERSION}.yaml.etags")
|
||||
sha3=$(sha_sum "${GHCUP_DIR}/cache/ghcup-${JSON_VERSION}.yaml")
|
||||
[ "${etag2}" = "${etag3}" ]
|
||||
[ "${sha2}" = "${sha3}" ]
|
||||
|
||||
# test isolated installs
|
||||
eghcup install ghc -i "$(pwd)/isolated" 8.10.5
|
||||
[ "$(isolated/bin/ghc --numeric-version)" = "8.10.5" ]
|
||||
! eghcup install ghc -i "$(pwd)/isolated" 8.10.5
|
||||
if [ "${ARCH}" = "64" ] ; then
|
||||
if [ "${OS}" = "LINUX" ] || [ "${OS}" = "WINDOWS" ] ; then
|
||||
eghcup install cabal -i "$(pwd)/isolated" 3.4.0.0
|
||||
[ "$(isolated/cabal --numeric-version)" = "3.4.0.0" ]
|
||||
eghcup install stack -i "$(pwd)/isolated" 2.7.3
|
||||
[ "$(isolated/stack --numeric-version)" = "2.7.3" ]
|
||||
eghcup install hls -i "$(pwd)/isolated" 1.3.0
|
||||
[ "$(isolated/haskell-language-server-wrapper --numeric-version)" = "1.3.0" ] ||
|
||||
[ "$(isolated/haskell-language-server-wrapper --numeric-version)" = "1.3.0.0" ]
|
||||
fi
|
||||
fi
|
||||
|
||||
eghcup upgrade
|
||||
eghcup upgrade -f
|
||||
|
||||
|
||||
# nuke
|
||||
eghcup nuke
|
||||
[ ! -e "${GHCUP_DIR}" ]
|
||||
|
||||
@@ -43,10 +43,8 @@
|
||||
|
||||
# unconditionally add the MacOSX.sdk and TargetConditional.h
|
||||
export NIX_CFLAGS_COMPILE+=" -isystem /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include"
|
||||
export NIX_LDFLAGS="-L/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib $NIX_LDFLAGS"
|
||||
|
||||
# Use an architecture specific home, so cabal for different architectures don't confuse each other.
|
||||
export HOME="$HOME/$(uname -m)-home"
|
||||
mkdir -p $HOME
|
||||
'';
|
||||
|
||||
nativeBuildInputs = (with pkgs; [
|
||||
@@ -81,6 +79,7 @@
|
||||
|
||||
which
|
||||
wget
|
||||
curl
|
||||
file
|
||||
|
||||
xz
|
||||
|
||||
16
.travis.yml
@@ -1,10 +1,5 @@
|
||||
jobs:
|
||||
include:
|
||||
- os: osx
|
||||
osx_image: xcode8
|
||||
language: generic
|
||||
env: ARTIFACT=x86_64-apple-darwin-10.11-ghcup
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode10.1
|
||||
language: generic
|
||||
@@ -15,23 +10,16 @@ jobs:
|
||||
language: generic
|
||||
env: ARTIFACT=x86_64-apple-darwin-10.14-ghcup
|
||||
|
||||
allow_failures:
|
||||
- os: osx
|
||||
osx_image: xcode8
|
||||
language: generic
|
||||
env: ARTIFACT=x86_64-apple-darwin-10.11-ghcup
|
||||
|
||||
|
||||
script: ".travis/build.sh"
|
||||
|
||||
deploy:
|
||||
provider: releases
|
||||
api_key:
|
||||
secure: GQESg4TcYf3PQJRRaZV/kWS0hsF+OFnH2+EcwpgnIcfx4+aogMyprdh745KtBXe1FlFN1luKHksFjqceqhcg/xcNyeCJiSnLWMn4D/i4WUperEHseRBi5yZZCB1AvOjIlHrE4DS3a8pyEm1GV3G7CKY5Fu8jBjof2SnyENfd7fofhjtNHWmeFS+jBn8HRDf1YaSRYxzTw6uHLrPLsybfgQZVl7babMu/38Ghin0f5pz5OlNokzDxaubIYQHOZ7st7YndHJtBWWql/KualBWbMILy88dUVQBnbqQLP2P8d1ME8ILUjJVqz33HiRU0JzlEJyWfbvEjcJ6iD8M6n4nXTaxfu3i2UhhGsQ6SSBNKssMP4tji8nkNpMqG59wLQ/zhcetEm71fKkgJNrIMNllkqlWSo5K74IqqP9kiLg/qm8ipOJjui0gPk8tZXKcV+ztX1d1OVCapoLfiDM5l/0LLQXaTOXOV1x3e5LLQ/w2doNiH3eh5CV4II9dRu7owpaiiMBHMssmT0pH99jEeF6giHLKtt3y7l2GWoRLPdhsZZ54gxsaBxZt9GuypmkbNcr97CEnAVaWij5v0CF3w4rAWqy/tAxQpIDJOIOQBgmwG5WrBAKyKrFvEpBL5a8BPcRWJDvqKC83QeWpvPrEVdgJevC6ZN1MKzrb2SiPOwC2Kerc=
|
||||
secure: "hT2od8Iy04tdFVuonPSWv0NX5hZDmv4al8Q0GbIWmviUetROuM7c6/MCHUcgyiw6H2L3pmH4F24GBYWpKBT3ZMbxrKXhZOZ3KPLXzlnuRlm1qymKqqwsJs3466bMftaiBr16rx1VpAuditN4A32oSmTFcQAJc84Bxn2WZ4t8hk9muS8YPyLhqg3/NxT6ob8dzNp9eS2cA0WODMb/fMzaMruRtepSK8JvuXb/SnTvaDcl9plmPzEa+eW54jwVsDps8ZpQMQlTtGIjYHIwTQ36/iLH4LoAvD7OEnB7qf753LOzmI/bvlB75xYGsLxe1qgpzPMjuG3AK0jb2KGSZCzyAyrbBFSQMIyC1gNKMtab3CohnA9WdQqAT1xrzPzA9zNw516G5Fn/z+t9Ek1f6L2OYO2hJfweNhWh+ChAIsOags2QBpqc0qjkwUS4wqxCWBdyVfgPTUoGelvjCfjQgypgIyLEHFvXt9rlj+kd97FY7nG3vxZrsvWTKKKT551OqUYX5zWTyvGR71jKyNst/p93Pg3DkRy31gHrGnG9zfNgN5tWxJqDd/suR/BAFTp0VtkFb8fR3ct7WMVeJXtE2+bKqxO5Fnocs1VjEm8pKPk7glnp0muu08kaO0h54wiSOCbk1RvO1KZtHue4wKWrHcI18dwW2WtzoBQ4P1lOSkS81UY="
|
||||
file: $ARTIFACT
|
||||
on:
|
||||
repo: haskell/ghcup-hs
|
||||
repo: hasufell/ghcup-hs
|
||||
tags: true
|
||||
skip_cleanup: true
|
||||
draft: true
|
||||
|
||||
|
||||
@@ -18,8 +18,8 @@ ghcup set 8.10.4
|
||||
cabal update
|
||||
|
||||
(
|
||||
cd /tmp
|
||||
cabal install --installdir="$HOME"/.ghcup/bin hspec-discover
|
||||
cd /tmp
|
||||
cabal install --installdir="$HOME"/.ghcup/bin hspec-discover
|
||||
)
|
||||
|
||||
cabal build --constraint="zlib +static" --constraint="lzma +static" -ftui
|
||||
|
||||
58
CHANGELOG.md
@@ -1,5 +1,63 @@
|
||||
# Revision history for ghcup
|
||||
|
||||
## 0.1.17.2 -- 2021-09-30
|
||||
|
||||
* Honour GHC bootstrap compiler during git clone stages wrt [#250](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/250)
|
||||
* Speed up `unset` command
|
||||
* Fix `--overwrite-version` for `ghcup compile ghc` wrt [#253](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/253)
|
||||
* Apply patches before bootstrap
|
||||
|
||||
## 0.1.17.1 -- 2021-09-26
|
||||
|
||||
* Fix `NO_COLOR`
|
||||
* Fix `ghcup list -t` for hls/stack, wrt [#244](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/244)
|
||||
* Get rid of concurrent-output
|
||||
* Improve cli interface with partial versions (e.g. `ghcup install ghc 8`)
|
||||
* Fix HLS compilation builds
|
||||
* Implement `ghcup gc` (garbage collection) command
|
||||
|
||||
## 0.1.17 -- 2021-09-20
|
||||
|
||||
* Add `--force` option to install/compile wrt [#210](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/210) by Arjun Kathuria
|
||||
* Implement compiling HLS from source wrt [#201](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/201)
|
||||
* Implement experimental GPG verification of the metadata file (see README) wrt [#263](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/236)
|
||||
* Add `ghcup unset` command wrt [#145](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/145)
|
||||
* Add `ghcup whereis bindir` etc wrt [#221](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/221)
|
||||
* Greatly reduce dependency footprint wrt [#212](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/212)
|
||||
* Add `ghcup --plan-json`
|
||||
* Improve `--patchdir` option for GHC compilation wrt [#226](https://gitlab.haskell.org/haskell/ghcup-hs/-/merge_requests/226)
|
||||
* Try to improve logging and failure modes, especially during downloads
|
||||
* Add descriptive warnings when HLS and GHC versions are incompatible
|
||||
* Improve curl header parsing wrt [#213](https://gitlab.haskell.org/haskell/ghcup-hs/-/merge_requests/213)
|
||||
|
||||
## 0.1.16.2 -- 2021-08-12
|
||||
|
||||
* Add isolated installations wrt [#141](https://gitlab.haskell.org/haskell/ghcup-hs/-/merge_requests/141) by Arjun Kathuria
|
||||
* Implement config cli MVP wrt [#134](https://gitlab.haskell.org/haskell/ghcup-hs/-/merge_requests/134) by Oleksii Dorozhkin
|
||||
* Fix `ghcup compile ghc --flavor`
|
||||
* Fix minor installation bug causing increased disk space wrt [#139](https://gitlab.haskell.org/haskell/ghcup-hs/-/merge_requests/139)
|
||||
* Improved error handling wrt [#136](https://gitlab.haskell.org/haskell/ghcup-hs/-/merge_requests/136)
|
||||
* Various improvements to metadata download when using `file://` and `--offline` wrt [#137](https://gitlab.haskell.org/haskell/ghcup-hs/-/merge_requests/137)
|
||||
|
||||
## 0.1.16.1 -- 2021-07-29
|
||||
|
||||
* Add 'nuke' subcommand wrt [#135](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/135), implemented by Arjun Kathuria
|
||||
* Add uninstallation powershell script on windows wrt [#150](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/150)
|
||||
* Improve logging
|
||||
* Fix building GHC cross compiler wrt [#180](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/180)
|
||||
* Allow to use hadrian as build system (for git based versions only) wrt [#35](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/35)
|
||||
* Allow passing `--flavor` to `ghcup compile ghc`
|
||||
* Support new GHC `bin/` directory format wrt [ghc/ghc#20074](https://gitlab.haskell.org/ghc/ghc/-/issues/20074#note_363720)
|
||||
* Implement `whereis` subcommand wrt [#173](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/173)
|
||||
* Add `--offline` switch and `prefetch` subcommand wrt [#186](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/186)
|
||||
* Implement ETAGs hashing for metadata downloads to speed up `ghcup list` wrt [#193](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/193)
|
||||
* Avoid unnecessary fetching of ghcup metadata in some commands
|
||||
* Avoid unnecessary update checks for some commands
|
||||
* Preserve mtimes on unpacked GHC tarballs on windows wrt [#187](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/187), fixing issues with `ghc-pkg`
|
||||
* Fix lesser bug in `ghcup list` for stray stack versions wrt [#183](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/183)
|
||||
* Major redo on how file removal on windows works, avoiding partial removals etc, wrt [#165](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/165)
|
||||
* Improve ghcup tui for screen readers wrt [github/#4](https://github.com/haskell/ghcup-hs/pull/4), thanks to Mario Lang
|
||||
|
||||
## 0.1.15.2 -- 2021-06-13
|
||||
|
||||
* Remove legacy handling of cabal binary and be more graceful about binaries not installed by ghcup (e.g. stack)
|
||||
|
||||
71
HACKING.md
@@ -1,71 +0,0 @@
|
||||
# HACKING
|
||||
|
||||
## Design decisions
|
||||
|
||||
### Using [Excepts](https://hackage.haskell.org/package/haskus-utils-variant-3.0/docs/Haskus-Utils-Variant-Excepts.html) as a beefed up ExceptT
|
||||
|
||||
This is an open variant, similar to [plucky](https://hackage.haskell.org/package/plucky) or [oops](https://github.com/i-am-tom/oops) and allows us to combine different error types. Maybe it is too much and it's a little bit [unergonomic](https://github.com/haskus/packages/issues/32) at times. If it really hurts maintenance, it will be removed. It was more of an experiment.
|
||||
|
||||
### No use of haskell-TLS
|
||||
|
||||
I consider haskell-TLS an interesting experiment, but not a battle-tested and peer-reviewed crypto implementation. There is little to no research about what the intricacies of using haskell for low-level crypto are and how vulnerable such binaries are. Instead, we use either curl the binary (for FreeBSD and mac) or http-io-streams, which works with OpenSSL bindings.
|
||||
|
||||
### Optics instead of lens
|
||||
|
||||
They're a little safer (less Monoid weirdness with view) and have better error messages. Consider the following wit lens
|
||||
|
||||
```
|
||||
> view (_Just . to (++ "abc")) Nothing
|
||||
""
|
||||
```
|
||||
|
||||
vs optics
|
||||
|
||||
```
|
||||
> view (_Just % to (++ "abc")) Nothing
|
||||
|
||||
<interactive>:2:1: error:
|
||||
• An_AffineFold cannot be used as A_Getter
|
||||
• In the expression: view (_Just % to (++ "abc")) Nothing
|
||||
In an equation for ‘it’: it = view (_Just % to (++ "abc")) Nothing
|
||||
```
|
||||
|
||||
### Strict and StrictData on by default
|
||||
|
||||
Kazu Yamamoto [explained it in his PR](https://github.com/yesodweb/wai/pull/752#issuecomment-501531386) very well. I like to agree with him. The instances where we need non-strict behavior, we annotate it.
|
||||
|
||||
## Code style and formatting
|
||||
|
||||
1. Brittany
|
||||
2. mtl-style preferred
|
||||
3. no overly pointfree style
|
||||
|
||||
## Code structure
|
||||
|
||||
Main functionality is in `GHCup` module. Utility functions are
|
||||
organised tree-ish in `GHCup.Utils` and `GHCup.Utils.*`.
|
||||
|
||||
Anything dealing with ghcup specific directories is in
|
||||
`GHCup.Utils.Dirs`.
|
||||
|
||||
Download information on where to fetch bindists from is in the appropriate
|
||||
yaml files: `ghcup-<yaml-ver>.yaml`.
|
||||
|
||||
## Common Tasks
|
||||
|
||||
### Adding a new GHC version
|
||||
|
||||
1. open the latest `ghcup-<yaml-ver>.yaml`
|
||||
2. find the latest ghc version (in yaml tree e.g. `ghcupDownloads -> GHC -> 8.10.3`)
|
||||
3. copy-paste it
|
||||
4. adjust the version, tags, changelog, source url
|
||||
5. adjust the various bindist urls (make sure to also change the yaml anchors)
|
||||
6. run `cabal run exe:ghcup-gen -- check-tarballs -f ghcup-<yaml-ver>.yaml -u 'ghc-8\.10\.4'`
|
||||
|
||||
## Major refactors
|
||||
|
||||
1. First major refactor included adding cross support. This added
|
||||
`GHCTargetVersion`, which includes the target in addition to the version.
|
||||
Most of the `Version` parameters to functions had to be replaced with
|
||||
that and ensured the logic is consistent for cross and non-cross
|
||||
installs.
|
||||
250
README.md
@@ -1,245 +1,11 @@
|
||||
`ghcup` makes it easy to install specific versions of `ghc` on GNU/Linux,
|
||||
macOS (aka Darwin) and FreeBSD and can also bootstrap a fresh Haskell developer environment from scratch.
|
||||
It follows the unix UNIX philosophy of [do one thing and do it well](https://en.wikipedia.org/wiki/Unix_philosophy#Do_One_Thing_and_Do_It_Well).
|
||||
## The GHCup Haskell installer
|
||||
|
||||
Similar in scope to [rustup](https://github.com/rust-lang-nursery/rustup.rs), [pyenv](https://github.com/pyenv/pyenv) and [jenv](http://www.jenv.be).
|
||||
[](https://kiwiirc.com/nextclient/irc.libera.chat/?nick=Guest%7C?#haskell,#haskell-ghcup)
|
||||
[](https://app.element.io/#/room/#haskell-tooling:matrix.org)
|
||||
[](https://discord.gg/pKYf3zDQU7)
|
||||
[](https://gitter.im/haskell/ghcup?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
<a href="https://opencollective.com/ghcup#category-CONTRIBUTE"><img src="https://opencollective.com/webpack/donate/button@2x.png?color=blue" alt="Donate" width="150"></a>
|
||||
|
||||
## Table of Contents
|
||||
GHCup is an installer for the general purpose language [Haskell](https://www.haskell.org/).
|
||||
|
||||
* [Installation](#installation)
|
||||
* [Simple bootstrap](#simple-bootstrap)
|
||||
* [Manual install](#manual-install)
|
||||
* [Vim integration](#vim-integration)
|
||||
* [Usage](#usage)
|
||||
* [Configuration](#configuration)
|
||||
* [Manpages](#manpages)
|
||||
* [Shell-completion](#shell-completion)
|
||||
* [Cross support](#cross-support)
|
||||
* [XDG support](#xdg-support)
|
||||
* [Env variables](#env-variables)
|
||||
* [Installing custom bindists](#installing-custom-bindists)
|
||||
* [Design goals](#design-goals)
|
||||
* [How](#how)
|
||||
* [Known users](#known-users)
|
||||
* [Known problems](#known-problems)
|
||||
* [FAQ](#faq)
|
||||
|
||||
## Installation
|
||||
|
||||
### Simple bootstrap
|
||||
|
||||
Follow the instructions at [https://www.haskell.org/ghcup/](https://www.haskell.org/ghcup/)
|
||||
|
||||
### Manual install
|
||||
|
||||
Download the binary for your platform at [https://downloads.haskell.org/~ghcup/](https://downloads.haskell.org/~ghcup/)
|
||||
and place it into your `PATH` anywhere.
|
||||
|
||||
Then adjust your `PATH` in `~/.bashrc` (or similar, depending on your shell) like so:
|
||||
|
||||
```sh
|
||||
export PATH="$HOME/.cabal/bin:$HOME/.ghcup/bin:$PATH"
|
||||
```
|
||||
|
||||
### Vim integration
|
||||
|
||||
See [ghcup.vim](https://github.com/hasufell/ghcup.vim).
|
||||
|
||||
## Usage
|
||||
|
||||
See `ghcup --help`.
|
||||
|
||||
For the simple interactive TUI, run:
|
||||
|
||||
```sh
|
||||
ghcup tui
|
||||
```
|
||||
|
||||
For the full functionality via cli:
|
||||
|
||||
```sh
|
||||
# list available ghc/cabal versions
|
||||
ghcup list
|
||||
|
||||
# install the recommended GHC version
|
||||
ghcup install ghc
|
||||
|
||||
# install a specific GHC version
|
||||
ghcup install ghc 8.2.2
|
||||
|
||||
# set the currently "active" GHC version
|
||||
ghcup set ghc 8.4.4
|
||||
|
||||
# install cabal-install
|
||||
ghcup install cabal
|
||||
|
||||
# update ghcup itself
|
||||
ghcup upgrade
|
||||
```
|
||||
|
||||
GHCup works very well with [`cabal-install`](https://hackage.haskell.org/package/cabal-install), which
|
||||
handles your haskell packages and can demand that [a specific version](https://cabal.readthedocs.io/en/latest/nix-local-build.html#cfg-flag---with-compiler) of `ghc` is available, which `ghcup` can do.
|
||||
|
||||
### Configuration
|
||||
|
||||
A configuration file can be put in `~/.ghcup/config.yaml`. The default config file
|
||||
explaining all possible configurations can be found in this repo: [config.yaml](./config.yaml).
|
||||
|
||||
Partial configuration is fine. Command line options always overwrite the config file settings.
|
||||
|
||||
### Manpages
|
||||
|
||||
For man pages to work you need [man-db](http://man-db.nongnu.org/) as your `man` provider, then issue `man ghc`. Manpages only work for the currently set ghc.
|
||||
`MANPATH` may be required to be unset.
|
||||
|
||||
### Shell-completion
|
||||
|
||||
Shell completions are in `shell-completions`.
|
||||
|
||||
For bash: install `shell-completions/bash`
|
||||
as e.g. `/etc/bash_completion.d/ghcup` (depending on distro)
|
||||
and make sure your bashrc sources the startup script
|
||||
(`/usr/share/bash-completion/bash_completion` on some distros).
|
||||
|
||||
### Cross support
|
||||
|
||||
ghcup can compile and install a cross GHC for any target. However, this
|
||||
requires that the build host has a complete cross toolchain and various
|
||||
libraries installed for the target platform.
|
||||
|
||||
Consult the GHC documentation on the [prerequisites](https://gitlab.haskell.org/ghc/ghc/-/wikis/building/cross-compiling#tools-to-install).
|
||||
For distributions with non-standard locations of cross toolchain and
|
||||
libraries, this may need some tweaking of `build.mk` or configure args.
|
||||
See `ghcup compile ghc --help` for further information.
|
||||
|
||||
### XDG support
|
||||
|
||||
To enable XDG style directories, set the environment variable `GHCUP_USE_XDG_DIRS` to anything.
|
||||
|
||||
Then you can control the locations via XDG environment variables as such:
|
||||
|
||||
* `XDG_DATA_HOME`: GHCs will be unpacked in `ghcup/ghc` subdir (default: `~/.local/share`)
|
||||
* `XDG_CACHE_HOME`: logs and download files will be stored in `ghcup` subdir (default: `~/.cache`)
|
||||
* `XDG_BIN_HOME`: binaries end up here (default: `~/.local/bin`)
|
||||
* `XDG_CONFIG_HOME`: the config file is stored in `ghcup` subdir as `config.yaml` (default: `~/.config`)
|
||||
|
||||
**Note that `ghcup` makes some assumptions about structure of files in `XDG_BIN_HOME`. So if you have other tools
|
||||
installing e.g. stack/cabal/ghc into it, this will likely clash. In that case consider disabling XDG support.**
|
||||
|
||||
### Env variables
|
||||
|
||||
This is the complete list of env variables that change GHCup behavior:
|
||||
|
||||
* `GHCUP_USE_XDG_DIRS`: see [XDG support](#xdg-support) above
|
||||
* `TMPDIR`: where ghcup does the work (unpacking, building, ...)
|
||||
* `GHCUP_INSTALL_BASE_PREFIX`: the base of ghcup (default: `$HOME`)
|
||||
* `GHCUP_CURL_OPTS`: additional options that can be passed to curl
|
||||
* `GHCUP_WGET_OPTS`: additional options that can be passed to wget
|
||||
* `GHCUP_SKIP_UPDATE_CHECK`: Skip the (possibly annoying) update check when you run a command
|
||||
* `CC`/`LD` etc.: full environment is passed to the build system when compiling GHC via GHCup
|
||||
|
||||
### Installing custom bindists
|
||||
|
||||
There are a couple of good use cases to install custom bindists:
|
||||
|
||||
1. manually built bindists (e.g. with patches)
|
||||
- example: `ghcup install ghc -u 'file:///home/mearwald/tmp/ghc-eff-patches/ghc-8.10.2-x86_64-deb10-linux.tar.xz' 8.10.2-eff`
|
||||
2. GHC head CI bindists
|
||||
- example: `ghcup install ghc -u 'https://gitlab.haskell.org/api/v4/projects/1/jobs/artifacts/master/raw/ghc-x86_64-fedora27-linux.tar.xz?job=validate-x86_64-linux-fedora27' head`
|
||||
3. DWARF bindists
|
||||
- example: `ghcup install ghc -u 'https://downloads.haskell.org/~ghc/8.10.2/ghc-8.10.2-x86_64-deb10-linux-dwarf.tar.xz' 8.10.2-dwarf`
|
||||
|
||||
Since the version parser is pretty lax, `8.10.2-eff` and `head` are both valid versions
|
||||
and produce the binaries `ghc-8.10.2-eff` and `ghc-head` respectively.
|
||||
GHCup always needs to know which version the bindist corresponds to (this is not automatically
|
||||
detected).
|
||||
|
||||
## Design goals
|
||||
|
||||
1. simplicity
|
||||
2. non-interactive
|
||||
3. portable (eh)
|
||||
4. do one thing and do it well (UNIX philosophy)
|
||||
|
||||
### Non-goals
|
||||
|
||||
1. invoking `sudo`, `apt-get` or *any* package manager
|
||||
2. handling system packages
|
||||
3. handling cabal projects
|
||||
4. being a stack alternative
|
||||
|
||||
## How
|
||||
|
||||
Installs a specified GHC version into `~/.ghcup/ghc/<ver>`, and places `ghc-<ver>` symlinks in `~/.ghcup/bin/`.
|
||||
|
||||
Optionally, an unversioned `ghc` link can point to a default version of your choice.
|
||||
|
||||
This uses precompiled GHC binaries that have been compiled on fedora/debian by [upstream GHC](https://www.haskell.org/ghc/download_ghc_8_6_1.html#binaries).
|
||||
|
||||
Alternatively, you can also tell it to compile from source (note that this might fail due to missing requirements).
|
||||
|
||||
In addition this script can also install `cabal-install`.
|
||||
|
||||
## Known users
|
||||
|
||||
* Github action [haskell/actions/setup](https://github.com/haskell/actions/tree/main/setup)
|
||||
* [vabal](https://github.com/Franciman/vabal)
|
||||
|
||||
## Known problems
|
||||
|
||||
### Custom ghc version names
|
||||
|
||||
When installing ghc bindists with custom version names as outlined in
|
||||
[installing custom bindists](#installing-custom-bindists), then cabal might
|
||||
be unable to find the correct `ghc-pkg` (also see [#73](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/73))
|
||||
if you use `cabal build --with-compiler=ghc-foo`. Instead, point it to the full path, such as:
|
||||
`cabal build --with-compiler=$HOME/.ghcup/ghc/<version-name>/bin/ghc` or set that GHC version
|
||||
as the current one via: `ghcup set ghc <version-name>`.
|
||||
|
||||
This problem doesn't exist for regularly installed GHC versions.
|
||||
|
||||
### Limited distributions supported
|
||||
|
||||
Currently only GNU/Linux distributions compatible with the [upstream GHC](https://www.haskell.org/ghc/download_ghc_8_6_1.html#binaries) binaries are supported.
|
||||
|
||||
### Precompiled binaries
|
||||
|
||||
Since this uses precompiled binaries you may run into
|
||||
several problems.
|
||||
|
||||
#### Missing libtinfo (ncurses)
|
||||
|
||||
You may run into problems with *ncurses* and **missing libtinfo**, in case
|
||||
your distribution doesn't use the legacy way of building
|
||||
ncurses and has no compatibility symlinks in place.
|
||||
|
||||
Ask your distributor on how to solve this or
|
||||
try to compile from source via `ghcup compile <version>`.
|
||||
|
||||
#### Libnuma required
|
||||
|
||||
This was a [bug](https://ghc.haskell.org/trac/ghc/ticket/15688) in the build system of some GHC versions that lead to
|
||||
unconditionally enabled libnuma support. To mitigate this you might have to install the libnuma
|
||||
package of your distribution. See [here](https://gitlab.haskell.org/haskell/ghcup/issues/58) for a discussion.
|
||||
|
||||
### Compilation
|
||||
|
||||
Although this script can compile GHC for you, it's just a very thin
|
||||
wrapper around the build system. It makes no effort in trying
|
||||
to figure out whether you have the correct toolchain and
|
||||
the correct dependencies. Refer to [the official docs](https://ghc.haskell.org/trac/ghc/wiki/Building/Preparation/Linux)
|
||||
on how to prepare your environment for building GHC.
|
||||
|
||||
## FAQ
|
||||
|
||||
1. Why reimplement stack?
|
||||
|
||||
ghcup is not a reimplementation of stack. The only common part is automatic installation of GHC, but even that differs in scope and design.
|
||||
|
||||
2. Why not support windows?
|
||||
|
||||
We do.
|
||||
|
||||
3. Why the haskell reimplementation?
|
||||
|
||||
:-)
|
||||
Visit the [documentation](https://www.haskell.org/ghcup/) for installation instructions.
|
||||
|
||||
19
RELEASING.md
@@ -1,19 +0,0 @@
|
||||
# RELEASING
|
||||
|
||||
1. update `GHCup.Version` module. `ghcupURL` must only be updated if we change the `_toolRequirements` type or the YAML representation of it. The version of the YAML represents the change increments. `ghcUpVer` is the current application version.
|
||||
|
||||
2. Update version in ghcup.cabal
|
||||
|
||||
3. Add ChangeLog entry
|
||||
|
||||
4. Add/fix downloads in `ghcup-<ver>.yaml`, then verify with `ghcup-gen check -f ghcup-<ver>.yaml`
|
||||
|
||||
5. Commit and git push with tag. Wait for tests to succeed and release artifacts to build.
|
||||
|
||||
6. Download release artifacts and upload them `downloads.haskell.org/ghcup`
|
||||
|
||||
7. Add release artifacts to yaml file (see point 4.)
|
||||
|
||||
8. Upload the final `ghcup-<ver>.yaml` to `webhost.haskell.org/ghcup/data/`.
|
||||
|
||||
9. Update bootstrap-haskell and symlinks on `downloads.haskell.org/ghcup`
|
||||
@@ -11,22 +11,33 @@
|
||||
module Main where
|
||||
|
||||
import GHCup.Types
|
||||
import GHCup.Types.JSON ( )
|
||||
import GHCup.Errors
|
||||
import GHCup.Platform
|
||||
import GHCup.Utils.Dirs
|
||||
import GHCup.Utils.Logger
|
||||
import GHCup.Types.JSON ( )
|
||||
|
||||
import Control.Monad.Trans.Reader ( runReaderT )
|
||||
import Control.Monad.IO.Class
|
||||
import Data.Char ( toLower )
|
||||
import Data.Maybe
|
||||
#if !MIN_VERSION_base(4,13,0)
|
||||
import Data.Semigroup ( (<>) )
|
||||
#endif
|
||||
import Options.Applicative hiding ( style )
|
||||
import Haskus.Utils.Variant.Excepts
|
||||
import System.Console.Pretty
|
||||
import System.Environment
|
||||
import System.Exit
|
||||
import System.IO ( stdout )
|
||||
import System.IO ( stderr )
|
||||
import Text.Regex.Posix
|
||||
import Validate
|
||||
import Text.PrettyPrint.HughesPJClass ( prettyShow )
|
||||
|
||||
import qualified Data.Text.IO as T
|
||||
import qualified Data.Text as T
|
||||
import qualified Data.ByteString as B
|
||||
import qualified Data.Yaml as Y
|
||||
import qualified Data.YAML.Aeson as Y
|
||||
|
||||
|
||||
data Options = Options
|
||||
@@ -105,10 +116,29 @@ com = subparser
|
||||
|
||||
main :: IO ()
|
||||
main = do
|
||||
no_color <- isJust <$> lookupEnv "NO_COLOR"
|
||||
let loggerConfig = LoggerConfig { lcPrintDebug = True
|
||||
, consoleOutter = T.hPutStr stderr
|
||||
, fileOutter = \_ -> pure ()
|
||||
, fancyColors = not no_color
|
||||
}
|
||||
dirs <- liftIO getAllDirs
|
||||
let leanAppstate = LeanAppState (Settings True False Never Curl True GHCupURL False GPGNone False) dirs defaultKeyBindings loggerConfig
|
||||
|
||||
pfreq <- (
|
||||
flip runReaderT leanAppstate . runE @'[NoCompatiblePlatform, NoCompatibleArch, DistroNotFound] $ platformRequest
|
||||
) >>= \case
|
||||
VRight r -> pure r
|
||||
VLeft e -> do
|
||||
flip runReaderT leanAppstate $ logError $ T.pack $ prettyShow e
|
||||
liftIO $ exitWith (ExitFailure 2)
|
||||
|
||||
let appstate = AppState (Settings True False Never Curl True GHCupURL False GPGNone False) dirs defaultKeyBindings (GHCupInfo mempty mempty mempty) pfreq loggerConfig
|
||||
|
||||
_ <- customExecParser (prefs showHelpOnError) (info (opts <**> helper) idm)
|
||||
>>= \Options {..} -> case optCommand of
|
||||
ValidateYAML vopts -> withValidateYamlOpts vopts validate
|
||||
ValidateTarballs vopts tarballFilter -> withValidateYamlOpts vopts (validateTarballs tarballFilter)
|
||||
ValidateYAML vopts -> withValidateYamlOpts vopts (\dl m -> flip runReaderT appstate $ validate dl m)
|
||||
ValidateTarballs vopts tarballFilter -> withValidateYamlOpts vopts (\dl m -> flip runReaderT appstate $ validateTarballs tarballFilter dl m)
|
||||
pure ()
|
||||
|
||||
where
|
||||
@@ -120,8 +150,8 @@ main = do
|
||||
ValidateYAMLOpts { vInput = Just (FileInput file) } ->
|
||||
B.readFile file >>= valAndExit f
|
||||
valAndExit f contents = do
|
||||
(GHCupInfo _ av gt) <- case Y.decodeEither' contents of
|
||||
(GHCupInfo _ av gt) <- case Y.decode1Strict contents of
|
||||
Right r -> pure r
|
||||
Left e -> die (color Red $ show e)
|
||||
myLoggerT (LoggerConfig True (B.hPut stdout) (\_ -> pure ())) (f av gt)
|
||||
Left (_, e) -> die (color Red $ show e)
|
||||
f av gt
|
||||
>>= exitWith
|
||||
|
||||
@@ -5,29 +5,24 @@
|
||||
{-# LANGUAGE TemplateHaskell #-}
|
||||
{-# LANGUAGE TypeApplications #-}
|
||||
{-# LANGUAGE ViewPatterns #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
|
||||
module Validate where
|
||||
|
||||
import GHCup
|
||||
import GHCup.Download
|
||||
import GHCup.Errors
|
||||
import GHCup.Platform
|
||||
import GHCup.Types
|
||||
import GHCup.Types.Optics
|
||||
import GHCup.Utils
|
||||
import GHCup.Utils.Logger
|
||||
import GHCup.Utils.Version.QQ
|
||||
|
||||
#if defined(TAR)
|
||||
import qualified Codec.Archive.Tar as Tar
|
||||
#else
|
||||
import Codec.Archive
|
||||
#endif
|
||||
import Control.Applicative
|
||||
import Control.Exception.Safe
|
||||
import Control.Monad
|
||||
import Control.Monad.IO.Class
|
||||
import Control.Monad.Logger
|
||||
import Control.Monad.Reader.Class
|
||||
import Control.Monad.Trans.Class ( lift )
|
||||
import Control.Monad.Trans.Reader ( runReaderT )
|
||||
@@ -37,18 +32,15 @@ import Control.Monad.Trans.Resource ( runResourceT
|
||||
import Data.Containers.ListUtils ( nubOrd )
|
||||
import Data.IORef
|
||||
import Data.List
|
||||
import Data.String.Interpolate
|
||||
import Data.Versions
|
||||
import Haskus.Utils.Variant.Excepts
|
||||
import Optics
|
||||
import System.FilePath
|
||||
import System.Exit
|
||||
import System.IO
|
||||
import Text.ParserCombinators.ReadP
|
||||
import Text.PrettyPrint.HughesPJClass ( prettyShow )
|
||||
import Text.Regex.Posix
|
||||
|
||||
import qualified Data.ByteString as B
|
||||
import qualified Data.Map.Strict as M
|
||||
import qualified Data.Text as T
|
||||
import qualified Data.Version as V
|
||||
@@ -66,7 +58,7 @@ addError = do
|
||||
liftIO $ modifyIORef ref (+ 1)
|
||||
|
||||
|
||||
validate :: (Monad m, MonadLogger m, MonadThrow m, MonadIO m, MonadUnliftIO m)
|
||||
validate :: (Monad m, MonadReader env m, HasLog env, MonadThrow m, MonadIO m, MonadUnliftIO m)
|
||||
=> GHCupDownloads
|
||||
-> M.Map GlobalTool DownloadInfo
|
||||
-> m ExitCode
|
||||
@@ -93,24 +85,23 @@ validate dls _ = do
|
||||
if e > 0
|
||||
then pure $ ExitFailure e
|
||||
else do
|
||||
lift $ $(logInfo) [i|All good|]
|
||||
lift $ logInfo "All good"
|
||||
pure ExitSuccess
|
||||
where
|
||||
checkHasRequiredPlatforms t v tags arch pspecs = do
|
||||
let v' = prettyVer v
|
||||
arch' = prettyShow arch
|
||||
when (notElem (Linux UnknownLinux) pspecs) $ do
|
||||
lift $ $(logError)
|
||||
[i|Linux UnknownLinux missing for for #{t} #{v'} #{arch'}|]
|
||||
lift $ logError $
|
||||
"Linux UnknownLinux missing for for " <> T.pack (prettyShow t) <> " " <> v' <> " " <> T.pack arch'
|
||||
addError
|
||||
when ((notElem Darwin pspecs) && arch == A_64) $ do
|
||||
lift $ $(logError) [i|Darwin missing for #{t} #{v'} #{arch'}|]
|
||||
lift $ logError $ "Darwin missing for for " <> T.pack (prettyShow t) <> " " <> v' <> " " <> T.pack arch'
|
||||
addError
|
||||
when ((notElem FreeBSD pspecs) && arch == A_64) $ lift $ $(logWarn)
|
||||
[i|FreeBSD missing for #{t} #{v'} #{arch'}|]
|
||||
when ((notElem FreeBSD pspecs) && arch == A_64) $ lift $ logWarn $
|
||||
"FreeBSD missing for for " <> T.pack (prettyShow t) <> " " <> v' <> " " <> T.pack arch'
|
||||
when (notElem Windows pspecs && arch == A_64) $ do
|
||||
lift $ $(logError)
|
||||
[i|Windows missing for for #{t} #{v'} #{arch'}|]
|
||||
lift $ logError $ "Windows missing for for " <> T.pack (prettyShow t) <> " " <> v' <> " " <> T.pack arch'
|
||||
addError
|
||||
|
||||
-- alpine needs to be set explicitly, because
|
||||
@@ -118,15 +109,15 @@ validate dls _ = do
|
||||
-- (although it could be static)
|
||||
when (notElem (Linux Alpine) pspecs) $
|
||||
case t of
|
||||
GHCup | arch `elem` [A_64, A_32] -> lift ($(logError) [i|Linux Alpine missing for #{t} #{v'} #{arch}|]) >> addError
|
||||
GHCup | arch `elem` [A_64, A_32] -> lift (logError $ "Linux Alpine missing for " <> T.pack (prettyShow t) <> " " <> v' <> " " <> T.pack (prettyShow arch)) >> addError
|
||||
Cabal | v > [vver|2.4.1.0|]
|
||||
, arch `elem` [A_64, A_32] -> lift ($(logError) [i|Linux Alpine missing for #{t} #{v'} #{arch'}|]) >> addError
|
||||
, arch `elem` [A_64, A_32] -> lift (logError $ "Linux Alpine missing for " <> T.pack (prettyShow t) <> " " <> v' <> " " <> T.pack (prettyShow arch)) >> addError
|
||||
GHC | Latest `elem` tags || Recommended `elem` tags
|
||||
, arch `elem` [A_64, A_32] -> lift ($(logError) [i|Linux Alpine missing for #{t} #{v'} #{arch'}|])
|
||||
_ -> lift $ $(logWarn) [i|Linux Alpine missing for #{t} #{v'} #{arch'}|]
|
||||
, arch `elem` [A_64, A_32] -> lift (logError $ "Linux Alpine missing for " <> T.pack (prettyShow t) <> " " <> v' <> " " <> T.pack (prettyShow arch))
|
||||
_ -> lift $ logWarn $ "Linux Alpine missing for " <> T.pack (prettyShow t) <> " " <> v' <> " " <> T.pack (prettyShow arch)
|
||||
|
||||
checkUniqueTags tool = do
|
||||
let allTags = join $ M.elems $ availableToolVersions dls tool
|
||||
let allTags = join $ fmap _viTags $ M.elems $ availableToolVersions dls tool
|
||||
let nonUnique =
|
||||
fmap fst
|
||||
. filter (\(_, b) -> not b)
|
||||
@@ -143,7 +134,7 @@ validate dls _ = do
|
||||
case join nonUnique of
|
||||
[] -> pure ()
|
||||
xs -> do
|
||||
lift $ $(logError) [i|Tags not unique for #{tool}: #{xs}|]
|
||||
lift $ logError $ "Tags not unique for " <> T.pack (prettyShow tool) <> ": " <> T.pack (prettyShow xs)
|
||||
addError
|
||||
where
|
||||
isUniqueTag Latest = True
|
||||
@@ -159,24 +150,24 @@ validate dls _ = do
|
||||
case [ x | (x,"") <- readP_to_S V.parseVersion (T.unpack . prettyVer $ v) ] of
|
||||
[_] -> pure ()
|
||||
_ -> do
|
||||
lift $ $(logError) [i|GHC version #{v} is not valid |]
|
||||
lift $ logError $ "GHC version " <> prettyVer v <> " is not valid"
|
||||
addError
|
||||
|
||||
-- a tool must have at least one of each mandatory tags
|
||||
checkMandatoryTags tool = do
|
||||
let allTags = join $ M.elems $ availableToolVersions dls tool
|
||||
let allTags = join $ fmap _viTags $ M.elems $ availableToolVersions dls tool
|
||||
forM_ [Latest, Recommended] $ \t -> case elem t allTags of
|
||||
False -> do
|
||||
lift $ $(logError) [i|Tag #{t} missing from #{tool}|]
|
||||
lift $ logError $ "Tag " <> T.pack (prettyShow t) <> " missing from " <> T.pack (prettyShow tool)
|
||||
addError
|
||||
True -> pure ()
|
||||
|
||||
-- all GHC versions must have a base tag
|
||||
checkGHCHasBaseVersion = do
|
||||
let allTags = M.toList $ availableToolVersions dls GHC
|
||||
forM allTags $ \(ver, tags) -> case any isBase tags of
|
||||
forM allTags $ \(ver, _viTags -> tags) -> case any isBase tags of
|
||||
False -> do
|
||||
lift $ $(logError) [i|Base tag missing from GHC ver #{ver}|]
|
||||
lift $ logError $ "Base tag missing from GHC ver " <> prettyVer ver
|
||||
addError
|
||||
True -> pure ()
|
||||
|
||||
@@ -189,7 +180,10 @@ data TarballFilter = TarballFilter
|
||||
}
|
||||
|
||||
validateTarballs :: ( Monad m
|
||||
, MonadLogger m
|
||||
, MonadReader env m
|
||||
, HasLog env
|
||||
, HasDirs env
|
||||
, HasSettings env
|
||||
, MonadThrow m
|
||||
, MonadIO m
|
||||
, MonadUnliftIO m
|
||||
@@ -204,94 +198,83 @@ validateTarballs :: ( Monad m
|
||||
validateTarballs (TarballFilter etool versionRegex) dls gt = do
|
||||
ref <- liftIO $ newIORef 0
|
||||
|
||||
flip runReaderT ref $ do
|
||||
-- download/verify all tarballs
|
||||
let dlis = either (const []) (\tool -> nubOrd $ dls ^.. each %& indices (maybe (const True) (==) tool) %> each %& indices (matchTest versionRegex . T.unpack . prettyVer) % (viSourceDL % _Just `summing` viArch % each % each % each)) etool
|
||||
let gdlis = nubOrd $ gt ^.. each
|
||||
let allDls = either (const gdlis) (const dlis) etool
|
||||
when (null allDls) $ $(logError) [i|no tarballs selected by filter|] *> addError
|
||||
forM_ allDls downloadAll
|
||||
-- download/verify all tarballs
|
||||
let dlis = either (const []) (\tool -> nubOrd $ dls ^.. each %& indices (maybe (const True) (==) tool) %> each %& indices (matchTest versionRegex . T.unpack . prettyVer) % (viSourceDL % _Just `summing` viArch % each % each % each)) etool
|
||||
let gdlis = nubOrd $ gt ^.. each
|
||||
let allDls = either (const gdlis) (const dlis) etool
|
||||
when (null allDls) $ logError "no tarballs selected by filter" *> (flip runReaderT ref addError)
|
||||
forM_ allDls (downloadAll ref)
|
||||
|
||||
-- exit
|
||||
e <- liftIO $ readIORef ref
|
||||
if e > 0
|
||||
then pure $ ExitFailure e
|
||||
else do
|
||||
lift $ $(logInfo) [i|All good|]
|
||||
pure ExitSuccess
|
||||
-- exit
|
||||
e <- liftIO $ readIORef ref
|
||||
if e > 0
|
||||
then pure $ ExitFailure e
|
||||
else do
|
||||
logInfo "All good"
|
||||
pure ExitSuccess
|
||||
|
||||
where
|
||||
runLogger = myLoggerT LoggerConfig { lcPrintDebug = True
|
||||
, colorOutter = B.hPut stderr
|
||||
, rawOutter = \_ -> pure ()
|
||||
}
|
||||
downloadAll dli = do
|
||||
dirs <- liftIO getDirs
|
||||
|
||||
pfreq <- (
|
||||
runLogger . runE @'[NoCompatiblePlatform, NoCompatibleArch, DistroNotFound] . liftE $ platformRequest
|
||||
) >>= \case
|
||||
VRight r -> pure r
|
||||
VLeft e -> do
|
||||
lift $ runLogger
|
||||
($(logError) $ T.pack $ prettyShow e)
|
||||
liftIO $ exitWith (ExitFailure 2)
|
||||
|
||||
let appstate = AppState (Settings True False Never Curl False GHCupURL) dirs defaultKeyBindings (GHCupInfo mempty mempty mempty) pfreq
|
||||
|
||||
r <-
|
||||
runLogger
|
||||
. flip runReaderT appstate
|
||||
. runResourceT
|
||||
downloadAll :: ( MonadUnliftIO m
|
||||
, MonadIO m
|
||||
, MonadReader env m
|
||||
, HasLog env
|
||||
, HasDirs env
|
||||
, HasSettings env
|
||||
, MonadCatch m
|
||||
, MonadMask m
|
||||
, MonadThrow m
|
||||
)
|
||||
=> IORef Int
|
||||
-> DownloadInfo
|
||||
-> m ()
|
||||
downloadAll ref dli = do
|
||||
r <- runResourceT
|
||||
. runE @'[DigestError
|
||||
, GPGError
|
||||
, DownloadFailed
|
||||
, UnknownArchive
|
||||
#if defined(TAR)
|
||||
, Tar.FormatError
|
||||
#else
|
||||
, ArchiveResult
|
||||
#endif
|
||||
]
|
||||
$ do
|
||||
case etool of
|
||||
Right (Just GHCup) -> do
|
||||
tmpUnpack <- lift mkGhcupTmpDir
|
||||
_ <- liftE $ download (settings appstate) dli tmpUnpack Nothing
|
||||
_ <- liftE $ download (_dlUri dli) Nothing (Just (_dlHash dli)) tmpUnpack Nothing False
|
||||
pure Nothing
|
||||
Right _ -> do
|
||||
p <- liftE $ downloadCached (settings appstate) dirs dli Nothing
|
||||
p <- liftE $ downloadCached dli Nothing
|
||||
fmap (Just . head . splitDirectories . head)
|
||||
. liftE
|
||||
. getArchiveFiles
|
||||
$ p
|
||||
Left ShimGen -> do
|
||||
tmpUnpack <- lift mkGhcupTmpDir
|
||||
_ <- liftE $ download (settings appstate) dli tmpUnpack Nothing
|
||||
_ <- liftE $ download (_dlUri dli) Nothing (Just (_dlHash dli)) tmpUnpack Nothing False
|
||||
pure Nothing
|
||||
case r of
|
||||
VRight (Just basePath) -> do
|
||||
case _dlSubdir dli of
|
||||
Just (RealDir prel) -> do
|
||||
lift $ $(logInfo)
|
||||
[i|verifying subdir: #{prel}|]
|
||||
logInfo
|
||||
$ " verifying subdir: " <> T.pack prel
|
||||
when (basePath /= prel) $ do
|
||||
lift $ $(logError)
|
||||
[i|Subdir doesn't match: expected "#{prel}", got "#{basePath}"|]
|
||||
addError
|
||||
logError $
|
||||
"Subdir doesn't match: expected " <> T.pack prel <> ", got " <> T.pack basePath
|
||||
(flip runReaderT ref addError)
|
||||
Just (RegexDir regexString) -> do
|
||||
lift $ $(logInfo)
|
||||
[i|verifying subdir (regex): #{regexString}|]
|
||||
logInfo $
|
||||
"verifying subdir (regex): " <> T.pack regexString
|
||||
let regex = makeRegexOpts
|
||||
compIgnoreCase
|
||||
execBlank
|
||||
regexString
|
||||
when (not (match regex basePath)) $ do
|
||||
lift $ $(logError)
|
||||
[i|Subdir doesn't match: expected regex "#{regexString}", got "#{basePath}"|]
|
||||
addError
|
||||
logError $
|
||||
"Subdir doesn't match: expected regex " <> T.pack regexString <> ", got " <> T.pack basePath
|
||||
(flip runReaderT ref addError)
|
||||
Nothing -> pure ()
|
||||
VRight Nothing -> pure ()
|
||||
VLeft e -> do
|
||||
lift $ $(logError)
|
||||
[i|Could not download (or verify hash) of #{dli}, Error was: #{prettyShow e}|]
|
||||
addError
|
||||
logError $
|
||||
"Could not download (or verify hash) of " <> T.pack (show dli) <> ", Error was: " <> T.pack (prettyShow e)
|
||||
(flip runReaderT ref addError)
|
||||
|
||||
@@ -13,11 +13,11 @@ module BrickMain where
|
||||
import GHCup
|
||||
import GHCup.Download
|
||||
import GHCup.Errors
|
||||
import GHCup.Types
|
||||
import GHCup.Types hiding ( LeanAppState(..) )
|
||||
import GHCup.Utils
|
||||
import GHCup.Utils.Logger
|
||||
import GHCup.Utils.Prelude ( decUTF8Safe )
|
||||
import GHCup.Utils.File
|
||||
import GHCup.Utils.Logger
|
||||
|
||||
import Brick
|
||||
import Brick.Widgets.Border
|
||||
@@ -27,11 +27,8 @@ import Brick.Widgets.List ( listSelectedFocusedAttr
|
||||
, listSelectedAttr
|
||||
, listAttr
|
||||
)
|
||||
#if !defined(TAR)
|
||||
import Codec.Archive
|
||||
#endif
|
||||
import Control.Exception.Safe
|
||||
import Control.Monad.Logger
|
||||
import Control.Monad.Reader
|
||||
import Control.Monad.Trans.Except
|
||||
import Control.Monad.Trans.Resource
|
||||
@@ -40,28 +37,24 @@ import Data.Functor
|
||||
import Data.List
|
||||
import Data.Maybe
|
||||
import Data.IORef
|
||||
import Data.String.Interpolate
|
||||
import Data.Vector ( Vector
|
||||
, (!?)
|
||||
)
|
||||
import Data.Versions hiding ( str )
|
||||
import Haskus.Utils.Variant.Excepts
|
||||
import Prelude hiding ( appendFile )
|
||||
import System.Environment
|
||||
import System.Exit
|
||||
import System.IO.Unsafe
|
||||
import Text.PrettyPrint.HughesPJClass ( prettyShow )
|
||||
import URI.ByteString
|
||||
|
||||
import qualified GHCup.Types as GT
|
||||
|
||||
import qualified Data.Text as T
|
||||
import qualified Graphics.Vty as Vty
|
||||
import qualified Data.Vector as V
|
||||
|
||||
|
||||
hiddenTools :: [Tool]
|
||||
hiddenTools = [Stack]
|
||||
hiddenTools = []
|
||||
|
||||
|
||||
data BrickData = BrickData
|
||||
@@ -171,7 +164,7 @@ ui dimAttrs BrickState{ appSettings = as@BrickSettings{}, ..}
|
||||
| elem Latest lTag && not lInstalled =
|
||||
withAttr "hooray"
|
||||
| otherwise = id
|
||||
active = if b then forceAttr "active" else id
|
||||
active = if b then putCursor "GHCup" (Location (0,0)) . forceAttr "active" else id
|
||||
in hooray $ active $ dim
|
||||
( marks
|
||||
<+> padLeft (Pad 2)
|
||||
@@ -259,7 +252,7 @@ app attrs dimAttrs =
|
||||
, appHandleEvent = eventHandler
|
||||
, appStartEvent = return
|
||||
, appAttrMap = const attrs
|
||||
, appChooseCursor = neverShowCursor
|
||||
, appChooseCursor = showFirstCursor
|
||||
}
|
||||
|
||||
defaultAttributes :: Bool -> AttrMap
|
||||
@@ -422,17 +415,11 @@ install' :: (MonadReader AppState m, MonadIO m, MonadThrow m, MonadFail m, Monad
|
||||
install' _ (_, ListResult {..}) = do
|
||||
AppState { ghcupInfo = GHCupInfo { _ghcupDownloads = dls }} <- ask
|
||||
|
||||
l <- liftIO $ readIORef logger'
|
||||
let runLogger = myLoggerT l
|
||||
|
||||
let run =
|
||||
runLogger
|
||||
. runResourceT
|
||||
runResourceT
|
||||
. runE
|
||||
@'[ AlreadyInstalled
|
||||
#if !defined(TAR)
|
||||
, ArchiveResult
|
||||
#endif
|
||||
, UnknownArchive
|
||||
, FileDoesNotExistError
|
||||
, CopyError
|
||||
@@ -441,49 +428,49 @@ install' _ (_, ListResult {..}) = do
|
||||
, BuildFailed
|
||||
, TagNotFound
|
||||
, DigestError
|
||||
, GPGError
|
||||
, DownloadFailed
|
||||
, DirNotEmpty
|
||||
, NoUpdate
|
||||
, TarDirDoesNotExist
|
||||
, FileAlreadyExistsError
|
||||
]
|
||||
|
||||
run (do
|
||||
case lTool of
|
||||
GHC -> do
|
||||
let vi = getVersionInfo lVer GHC dls
|
||||
liftE $ installGHCBin lVer $> vi
|
||||
liftE $ installGHCBin lVer Nothing False $> vi
|
||||
Cabal -> do
|
||||
let vi = getVersionInfo lVer Cabal dls
|
||||
liftE $ installCabalBin lVer $> vi
|
||||
liftE $ installCabalBin lVer Nothing False $> vi
|
||||
GHCup -> do
|
||||
let vi = snd <$> getLatest dls GHCup
|
||||
liftE $ upgradeGHCup Nothing False $> vi
|
||||
HLS -> do
|
||||
let vi = getVersionInfo lVer HLS dls
|
||||
liftE $ installHLSBin lVer $> vi
|
||||
liftE $ installHLSBin lVer Nothing False $> vi
|
||||
Stack -> do
|
||||
let vi = getVersionInfo lVer Stack dls
|
||||
liftE $ installStackBin lVer $> vi
|
||||
liftE $ installStackBin lVer Nothing False $> vi
|
||||
)
|
||||
>>= \case
|
||||
VRight vi -> do
|
||||
forM_ (_viPostInstall =<< vi) $ \msg ->
|
||||
myLoggerT l $ $(logInfo) msg
|
||||
logInfo msg
|
||||
pure $ Right ()
|
||||
VLeft (V (AlreadyInstalled _ _)) -> pure $ Right ()
|
||||
VLeft (V NoUpdate) -> pure $ Right ()
|
||||
VLeft e -> pure $ Left [i|#{prettyShow e}
|
||||
Also check the logs in ~/.ghcup/logs|]
|
||||
VLeft e -> pure $ Left $ prettyShow e <> "\n"
|
||||
<> "Also check the logs in ~/.ghcup/logs"
|
||||
|
||||
|
||||
set' :: BrickState -> (Int, ListResult) -> IO (Either String ())
|
||||
set' _ (_, ListResult {..}) = do
|
||||
settings <- readIORef settings'
|
||||
l <- readIORef logger'
|
||||
let runLogger = myLoggerT l
|
||||
|
||||
let run =
|
||||
runLogger
|
||||
. flip runReaderT settings
|
||||
flip runReaderT settings
|
||||
. runE @'[FileDoesNotExistError , NotInstalled , TagNotFound]
|
||||
|
||||
run (do
|
||||
@@ -506,9 +493,7 @@ del' :: (MonadReader AppState m, MonadIO m, MonadFail m, MonadMask m, MonadUnlif
|
||||
del' _ (_, ListResult {..}) = do
|
||||
AppState { ghcupInfo = GHCupInfo { _ghcupDownloads = dls }} <- ask
|
||||
|
||||
l <- liftIO $ readIORef logger'
|
||||
let runLogger = myLoggerT l
|
||||
let run = myLoggerT l . runE @'[NotInstalled]
|
||||
let run = runE @'[NotInstalled]
|
||||
|
||||
run (do
|
||||
let vi = getVersionInfo lVer lTool dls
|
||||
@@ -522,7 +507,7 @@ del' _ (_, ListResult {..}) = do
|
||||
>>= \case
|
||||
VRight vi -> do
|
||||
forM_ (join $ fmap _viPostRemove vi) $ \msg ->
|
||||
runLogger $ $(logInfo) msg
|
||||
logInfo msg
|
||||
pure $ Right ()
|
||||
VLeft e -> pure $ Left (prettyShow e)
|
||||
|
||||
@@ -534,8 +519,8 @@ changelog' :: (MonadReader AppState m, MonadIO m)
|
||||
changelog' _ (_, ListResult {..}) = do
|
||||
AppState { pfreq, ghcupInfo = GHCupInfo { _ghcupDownloads = dls }} <- ask
|
||||
case getChangeLog dls lTool (Left lVer) of
|
||||
Nothing -> pure $ Left
|
||||
[i|Could not find ChangeLog for #{lTool}, version #{prettyVer lVer}|]
|
||||
Nothing -> pure $ Left $
|
||||
"Could not find ChangeLog for " <> prettyShow lTool <> ", version " <> T.unpack (prettyVer lVer)
|
||||
Just uri -> do
|
||||
let cmd = case _rPlatform pfreq of
|
||||
Darwin -> "open"
|
||||
@@ -550,58 +535,50 @@ changelog' _ (_, ListResult {..}) = do
|
||||
settings' :: IORef AppState
|
||||
{-# NOINLINE settings' #-}
|
||||
settings' = unsafePerformIO $ do
|
||||
dirs <- getDirs
|
||||
dirs <- getAllDirs
|
||||
let loggerConfig = LoggerConfig { lcPrintDebug = False
|
||||
, consoleOutter = \_ -> pure ()
|
||||
, fileOutter = \_ -> pure ()
|
||||
, fancyColors = True
|
||||
}
|
||||
newIORef $ AppState (Settings { cache = True
|
||||
, noVerify = False
|
||||
, keepDirs = Never
|
||||
, downloader = Curl
|
||||
, verbose = False
|
||||
, urlSource = GHCupURL
|
||||
, noNetwork = False
|
||||
, gpgSetting = GPGNone
|
||||
, noColor = False
|
||||
, ..
|
||||
})
|
||||
dirs
|
||||
defaultKeyBindings
|
||||
(GHCupInfo mempty mempty mempty)
|
||||
(PlatformRequest A_64 Darwin Nothing)
|
||||
loggerConfig
|
||||
|
||||
|
||||
|
||||
logger' :: IORef LoggerConfig
|
||||
{-# NOINLINE logger' #-}
|
||||
logger' = unsafePerformIO
|
||||
(newIORef $ LoggerConfig { lcPrintDebug = False
|
||||
, colorOutter = \_ -> pure ()
|
||||
, rawOutter = \_ -> pure ()
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
brickMain :: AppState
|
||||
-> LoggerConfig
|
||||
-> GHCupInfo
|
||||
-> IO ()
|
||||
brickMain s l gi = do
|
||||
brickMain s = do
|
||||
writeIORef settings' s
|
||||
-- logger interpreter
|
||||
writeIORef logger' l
|
||||
let runLogger = myLoggerT l
|
||||
|
||||
no_color <- isJust <$> lookupEnv "NO_COLOR"
|
||||
|
||||
eAppData <- getAppData (Just gi)
|
||||
eAppData <- getAppData (Just $ ghcupInfo s)
|
||||
case eAppData of
|
||||
Right ad ->
|
||||
defaultMain
|
||||
(app (defaultAttributes no_color) (dimAttributes no_color))
|
||||
(app (defaultAttributes (noColor $ settings s)) (dimAttributes (noColor $ settings s)))
|
||||
(BrickState ad
|
||||
defaultAppSettings
|
||||
(constructList ad defaultAppSettings Nothing)
|
||||
(keyBindings s)
|
||||
(keyBindings (s :: AppState))
|
||||
|
||||
)
|
||||
$> ()
|
||||
Left e -> do
|
||||
runLogger ($(logError) [i|Error building app state: #{show e}|])
|
||||
flip runReaderT s $ logError $ "Error building app state: " <> T.pack (show e)
|
||||
exitWith $ ExitFailure 2
|
||||
|
||||
|
||||
@@ -612,15 +589,12 @@ defaultAppSettings = BrickSettings { showAllVersions = False, showAllTools = Fal
|
||||
getGHCupInfo :: IO (Either String GHCupInfo)
|
||||
getGHCupInfo = do
|
||||
settings <- readIORef settings'
|
||||
l <- readIORef logger'
|
||||
let runLogger = myLoggerT l
|
||||
|
||||
r <-
|
||||
runLogger
|
||||
. flip runReaderT settings
|
||||
. runE @'[JSONError , DownloadFailed , FileDoesNotExistError]
|
||||
flip runReaderT settings
|
||||
. runE @'[DigestError, GPGError, JSONError , DownloadFailed , FileDoesNotExistError]
|
||||
$ liftE
|
||||
$ getDownloadsF (GT.settings settings) (GT.dirs settings)
|
||||
$ getDownloadsF
|
||||
|
||||
case r of
|
||||
VRight a -> pure $ Right a
|
||||
@@ -630,14 +604,11 @@ getGHCupInfo = do
|
||||
getAppData :: Maybe GHCupInfo
|
||||
-> IO (Either String BrickData)
|
||||
getAppData mgi = runExceptT $ do
|
||||
l <- liftIO $ readIORef logger'
|
||||
let runLogger = myLoggerT l
|
||||
|
||||
r <- ExceptT $ maybe getGHCupInfo (pure . Right) mgi
|
||||
liftIO $ modifyIORef settings' (\s -> s { ghcupInfo = r })
|
||||
settings <- liftIO $ readIORef settings'
|
||||
|
||||
runLogger . flip runReaderT settings $ do
|
||||
flip runReaderT settings $ do
|
||||
lV <- listVersions Nothing Nothing
|
||||
pure $ BrickData (reverse lV)
|
||||
|
||||
|
||||
1769
app/ghcup/Main.hs
@@ -1,464 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Main settings:
|
||||
# * BOOTSTRAP_HASKELL_NONINTERACTIVE - any nonzero value for noninteractive installation
|
||||
# * BOOTSTRAP_HASKELL_NO_UPGRADE - any nonzero value to not trigger the upgrade
|
||||
# * GHCUP_USE_XDG_DIRS - any nonzero value to respect The XDG Base Directory Specification
|
||||
# * BOOTSTRAP_HASKELL_VERBOSE - any nonzero value for more verbose installation
|
||||
# * BOOTSTRAP_HASKELL_GHC_VERSION
|
||||
# * BOOTSTRAP_HASKELL_CABAL_VERSION
|
||||
|
||||
# License: LGPL-3.0
|
||||
|
||||
|
||||
# safety subshell to avoid executing anything in case this script is not downloaded properly
|
||||
(
|
||||
|
||||
plat="$(uname -s)"
|
||||
arch=$(uname -m)
|
||||
ghver="0.1.15.1"
|
||||
base_url="https://downloads.haskell.org/~ghcup"
|
||||
|
||||
case "${plat}" in
|
||||
MSYS*|MINGW*)
|
||||
: "${GHCUP_INSTALL_BASE_PREFIX:=/c}"
|
||||
GHCUP_DIR=$(cygpath -u "${GHCUP_INSTALL_BASE_PREFIX}/ghcup")
|
||||
GHCUP_BIN=$(cygpath -u "${GHCUP_INSTALL_BASE_PREFIX}/ghcup/bin")
|
||||
: "${GHCUP_MSYS2:=${GHCUP_DIR}/msys64}"
|
||||
;;
|
||||
*)
|
||||
: "${GHCUP_INSTALL_BASE_PREFIX:=$HOME}"
|
||||
export GHCUP_USE_XDG_DIRS
|
||||
|
||||
if [ -n "${GHCUP_USE_XDG_DIRS}" ] ; then
|
||||
GHCUP_DIR=${XDG_DATA_HOME:=$HOME/.local/share}/ghcup
|
||||
GHCUP_BIN=${XDG_BIN_HOME:=$HOME/.local/bin}
|
||||
else
|
||||
GHCUP_DIR=${GHCUP_INSTALL_BASE_PREFIX}/.ghcup
|
||||
GHCUP_BIN=${GHCUP_INSTALL_BASE_PREFIX}/.ghcup/bin
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
: "${BOOTSTRAP_HASKELL_GHC_VERSION:=recommended}"
|
||||
: "${BOOTSTRAP_HASKELL_CABAL_VERSION:=recommended}"
|
||||
|
||||
|
||||
die() {
|
||||
(>&2 printf "\\033[0;31m%s\\033[0m\\n" "$1")
|
||||
exit 2
|
||||
}
|
||||
|
||||
warn() {
|
||||
case "${plat}" in
|
||||
MSYS*|MINGW*)
|
||||
echo -e "\\033[0;35m$1\\033[0m"
|
||||
;;
|
||||
*)
|
||||
printf "\\033[0;35m%s\\033[0m\\n" "$1"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
edo() {
|
||||
"$@" || die "\"$*\" failed!"
|
||||
}
|
||||
|
||||
eghcup() {
|
||||
edo _eghcup "$@"
|
||||
}
|
||||
|
||||
_eghcup() {
|
||||
if [ -n "${BOOTSTRAP_HASKELL_YAML}" ] ; then
|
||||
args="-s ${BOOTSTRAP_HASKELL_YAML}"
|
||||
fi
|
||||
if [ -z "${BOOTSTRAP_HASKELL_VERBOSE}" ] ; then
|
||||
"${GHCUP_BIN}/ghcup" ${args} "$@"
|
||||
else
|
||||
"${GHCUP_BIN}/ghcup" ${args} --verbose "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
_done() {
|
||||
case "${plat}" in
|
||||
MSYS*|MINGW*)
|
||||
echo
|
||||
echo "All done!"
|
||||
echo
|
||||
echo "In a new powershell or cmd.exe session, now you can..."
|
||||
echo
|
||||
echo "Start a simple repl via:"
|
||||
echo " ghci"
|
||||
echo
|
||||
echo "Start a new haskell project in the current directory via:"
|
||||
echo " cabal init --interactive"
|
||||
echo
|
||||
echo "Install other GHC versions and tools via:"
|
||||
echo " ghcup list"
|
||||
echo " ghcup install <tool> <version>"
|
||||
echo
|
||||
echo "To install system libraries and update msys2/mingw64,"
|
||||
echo "open the \"Mingw haskell shell\""
|
||||
echo "and the \"Mingw package management docs\""
|
||||
echo "desktop shortcuts."
|
||||
;;
|
||||
*)
|
||||
echo
|
||||
echo "All done!"
|
||||
echo
|
||||
echo "To start a simple repl, run:"
|
||||
echo " ghci"
|
||||
echo
|
||||
echo "To start a new haskell project in the current directory, run:"
|
||||
echo " cabal init --interactive"
|
||||
echo
|
||||
echo "To install other GHC versions and tools, run:"
|
||||
echo " ghcup tui"
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
|
||||
exit 0
|
||||
}
|
||||
|
||||
download_ghcup() {
|
||||
|
||||
case "${plat}" in
|
||||
"linux"|"Linux")
|
||||
case "${arch}" in
|
||||
x86_64|amd64)
|
||||
# we could be in a 32bit docker container, in which
|
||||
# case uname doesn't give us what we want
|
||||
if [ "$(getconf LONG_BIT)" = "32" ] ; then
|
||||
_url=${base_url}/${ghver}/i386-linux-ghcup-${ghver}
|
||||
elif [ "$(getconf LONG_BIT)" = "64" ] ; then
|
||||
_url=${base_url}/${ghver}/x86_64-linux-ghcup-${ghver}
|
||||
else
|
||||
die "Unknown long bit size: $(getconf LONG_BIT)"
|
||||
fi
|
||||
;;
|
||||
i*86)
|
||||
_url=${base_url}/${ghver}/i386-linux-ghcup-${ghver}
|
||||
;;
|
||||
armv7*)
|
||||
_url=${base_url}/${ghver}/armv7-linux-ghcup-${ghver}
|
||||
;;
|
||||
aarch64|arm64|armv8l)
|
||||
_url=${base_url}/${ghver}/aarch64-linux-ghcup-${ghver}
|
||||
;;
|
||||
*) die "Unknown architecture: ${arch}"
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
"FreeBSD"|"freebsd")
|
||||
case "${arch}" in
|
||||
x86_64|amd64)
|
||||
;;
|
||||
i*86)
|
||||
die "i386 currently not supported!"
|
||||
;;
|
||||
*) die "Unknown architecture: ${arch}"
|
||||
;;
|
||||
esac
|
||||
_url=${base_url}/${ghver}/x86_64-portbld-freebsd-ghcup-${ghver}
|
||||
;;
|
||||
"Darwin"|"darwin")
|
||||
case "${arch}" in
|
||||
x86_64|amd64)
|
||||
_url=${base_url}/${ghver}/x86_64-apple-darwin-ghcup-${ghver}
|
||||
;;
|
||||
aarch64|arm64|armv8l)
|
||||
_url=${base_url}/${ghver}/aarch64-apple-darwin-ghcup-${ghver}
|
||||
;;
|
||||
i*86)
|
||||
die "i386 currently not supported!"
|
||||
;;
|
||||
*) die "Unknown architecture: ${arch}"
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
MSYS*|MINGW*)
|
||||
case "${arch}" in
|
||||
x86_64|amd64)
|
||||
_url=${base_url}/${ghver}/x86_64-mingw64-ghcup-${ghver}.exe
|
||||
;;
|
||||
*) die "Unknown architecture: ${arch}"
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
*) die "Unknown platform: ${plat}"
|
||||
;;
|
||||
esac
|
||||
case "${plat}" in
|
||||
MSYS*|MINGW*)
|
||||
edo curl -Lf "${_url}" > "${GHCUP_BIN}"/ghcup.exe
|
||||
edo chmod +x "${GHCUP_BIN}"/ghcup.exe
|
||||
;;
|
||||
*)
|
||||
edo curl -Lf "${_url}" > "${GHCUP_BIN}"/ghcup
|
||||
edo chmod +x "${GHCUP_BIN}"/ghcup
|
||||
;;
|
||||
esac
|
||||
|
||||
edo mkdir -p "${GHCUP_DIR}"
|
||||
cat <<-EOF > "${GHCUP_DIR}"/env || die "Failed to create env file"
|
||||
export PATH="\$HOME/.cabal/bin:${GHCUP_BIN}:\$PATH"
|
||||
EOF
|
||||
# shellcheck disable=SC1090
|
||||
edo . "${GHCUP_DIR}"/env
|
||||
eghcup upgrade
|
||||
}
|
||||
|
||||
|
||||
echo
|
||||
echo "Welcome to Haskell!"
|
||||
echo
|
||||
echo "This script will download and install the following binaries:"
|
||||
echo " * ghcup - The Haskell toolchain installer"
|
||||
echo " * ghc - The Glasgow Haskell Compiler"
|
||||
echo " * cabal - The Cabal build tool for managing Haskell software"
|
||||
echo " * stack - (optional) A cross-platform program for developing Haskell projects"
|
||||
echo " * hls - (optional) A language server for developers to integrate with their editor/IDE"
|
||||
echo
|
||||
if [ -z "${GHCUP_USE_XDG_DIRS}" ] ; then
|
||||
echo "ghcup installs only into the following directory,"
|
||||
echo "which can be removed anytime:"
|
||||
case "${plat}" in
|
||||
MSYS*|MINGW*)
|
||||
echo " $(cygpath -w "$GHCUP_DIR")"
|
||||
;;
|
||||
*)
|
||||
echo " $GHCUP_DIR"
|
||||
;;
|
||||
esac
|
||||
else
|
||||
echo "ghcup installs into XDG directories as long as"
|
||||
echo "'GHCUP_USE_XDG_DIRS' is set."
|
||||
fi
|
||||
echo
|
||||
|
||||
if [ -z "${BOOTSTRAP_HASKELL_NONINTERACTIVE}" ] ; then
|
||||
warn "Press ENTER to proceed or ctrl-c to abort."
|
||||
warn "Note that this script can be re-run at any given time."
|
||||
echo
|
||||
# Wait for user input to continue.
|
||||
# shellcheck disable=SC2034
|
||||
read -r answer </dev/tty
|
||||
fi
|
||||
|
||||
edo mkdir -p "${GHCUP_BIN}"
|
||||
|
||||
if command -V "ghcup" >/dev/null 2>&1 ; then
|
||||
if [ -z "${BOOTSTRAP_HASKELL_NO_UPGRADE}" ] ; then
|
||||
_eghcup upgrade || download_ghcup
|
||||
fi
|
||||
else
|
||||
download_ghcup
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "$(if [ -n "${BOOTSTRAP_HASKELL_YAML}" ] ; then ghcup -s "${BOOTSTRAP_HASKELL_YAML}" tool-requirements ; else ghcup tool-requirements ; fi)"
|
||||
echo
|
||||
|
||||
if [ -z "${BOOTSTRAP_HASKELL_NONINTERACTIVE}" ] ; then
|
||||
warn "Press ENTER to proceed or ctrl-c to abort."
|
||||
warn "Installation may take a while."
|
||||
echo
|
||||
|
||||
# Wait for user input to continue.
|
||||
# shellcheck disable=SC2034
|
||||
read -r answer </dev/tty
|
||||
fi
|
||||
|
||||
eghcup --cache install ghc "${BOOTSTRAP_HASKELL_GHC_VERSION}"
|
||||
|
||||
eghcup set ghc "${BOOTSTRAP_HASKELL_GHC_VERSION}"
|
||||
eghcup --cache install cabal "${BOOTSTRAP_HASKELL_CABAL_VERSION}"
|
||||
|
||||
adjust_cabal_config() {
|
||||
edo cabal user-config -a "extra-prog-path: $(cygpath -w "$GHCUP_BIN"), $(cygpath -w "$HOME"/AppData/Roaming/cabal/bin), $(cygpath -w "$GHCUP_MSYS2"/usr/bin), $(cygpath -w "$GHCUP_MSYS2"/mingw64/bin)" -a "extra-include-dirs: $(cygpath -w "$GHCUP_MSYS2"/mingw64/include)" -a "extra-lib-dirs: $(cygpath -w "$GHCUP_MSYS2"/mingw64/lib)" -f init
|
||||
}
|
||||
|
||||
case "${plat}" in
|
||||
MSYS*|MINGW*)
|
||||
if [ -z "${BOOTSTRAP_HASKELL_NONINTERACTIVE}" ] ; then
|
||||
warn "Create an initial cabal.config including relevant msys2 paths (recommended)?"
|
||||
warn "[Y] Yes [N] No [?] Help (default is \"Y\")."
|
||||
echo
|
||||
while true; do
|
||||
read -r mingw_answer </dev/tty
|
||||
|
||||
case $mingw_answer in
|
||||
[Yy]* | "")
|
||||
adjust_cabal_config
|
||||
break ;;
|
||||
[Nn]*)
|
||||
echo "Make sure that your global cabal.config references the correct mingw64 paths (extra-prog-path, extra-include-dirs and extra-lib-dirs)."
|
||||
echo "And set the environment variable GHCUP_MSYS2 to the root path of your msys2 installation."
|
||||
sleep 5
|
||||
break ;;
|
||||
*)
|
||||
echo "Possible choices are:"
|
||||
echo
|
||||
echo "Y - Yes, create a cabal.config with pre-set paths to msys2/mingw64 (default)"
|
||||
echo "N - No, leave the current/default cabal config untouched"
|
||||
echo
|
||||
echo "Please make your choice and press ENTER."
|
||||
;;
|
||||
esac
|
||||
done
|
||||
else
|
||||
adjust_cabal_config
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
edo cabal new-update
|
||||
|
||||
if [ -z "${BOOTSTRAP_HASKELL_NONINTERACTIVE}" ] ; then
|
||||
warn "Do you want to install haskell-language-server (HLS) now?"
|
||||
warn "HLS is a language-server that provides IDE-like functionality"
|
||||
warn "and can integrate with different editors, such as Vim, Emacs, VS Code, Atom, ..."
|
||||
warn "Also see https://github.com/haskell/haskell-language-server/blob/master/README.md"
|
||||
warn ""
|
||||
warn "[Y] Yes [N] No [?] Help (default is \"N\")."
|
||||
warn ""
|
||||
|
||||
while true; do
|
||||
read -r hls_answer </dev/tty
|
||||
|
||||
case $hls_answer in
|
||||
[Yy]*)
|
||||
eghcup --cache install hls || warn "HLS installation failed, continuing anyway"
|
||||
break ;;
|
||||
[Nn]* | "")
|
||||
break ;;
|
||||
*)
|
||||
echo "Possible choices are:"
|
||||
echo
|
||||
echo "Y - Yes, install the haskell-langauge-server"
|
||||
echo "N - No, don't install anything more (default)"
|
||||
echo
|
||||
echo "Please make your choice and press ENTER."
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
warn "Do you want to install stack now?"
|
||||
warn "Stack is a haskell build tool similar to cabal that is used by some projects."
|
||||
warn "Also see https://docs.haskellstack.org/"
|
||||
warn ""
|
||||
warn "[Y] Yes [N] No [?] Help (default is \"N\")."
|
||||
warn ""
|
||||
|
||||
while true; do
|
||||
read -r stack_answer </dev/tty
|
||||
|
||||
case $stack_answer in
|
||||
[Yy]*)
|
||||
eghcup --cache install stack || warn "Stack installation failed, continuing anyway"
|
||||
break ;;
|
||||
[Nn]* | "")
|
||||
break ;;
|
||||
*)
|
||||
echo "Possible choices are:"
|
||||
echo
|
||||
echo "Y - Yes, install stack"
|
||||
echo "N - No, don't install anything more (default)"
|
||||
echo
|
||||
echo "Please make your choice and press ENTER."
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
echo "In order to run ghc and cabal, you need to adjust your PATH variable."
|
||||
echo "You may want to source '$GHCUP_DIR/env' in your shell"
|
||||
echo "configuration to do so (e.g. ~/.bashrc)."
|
||||
|
||||
case $SHELL in
|
||||
*/zsh) # login shell is zsh
|
||||
GHCUP_PROFILE_FILE="$HOME/.zshrc"
|
||||
MY_SHELL="zsh" ;;
|
||||
*/bash) # login shell is bash
|
||||
GHCUP_PROFILE_FILE="$HOME/.bashrc"
|
||||
MY_SHELL="bash" ;;
|
||||
*/sh) # login shell is sh, but might be a symlink to bash or zsh
|
||||
if [ -n "${BASH}" ] ; then
|
||||
GHCUP_PROFILE_FILE="$HOME/.bashrc"
|
||||
MY_SHELL="bash"
|
||||
elif [ -n "${ZSH_VERSION}" ] ; then
|
||||
GHCUP_PROFILE_FILE="$HOME/.zshrc"
|
||||
MY_SHELL="zsh"
|
||||
else
|
||||
_done
|
||||
fi
|
||||
;;
|
||||
*/fish) # login shell is fish
|
||||
GHCUP_PROFILE_FILE="$HOME/.config/fish/config.fish"
|
||||
MY_SHELL="fish" ;;
|
||||
*) _done ;;
|
||||
esac
|
||||
|
||||
|
||||
warn ""
|
||||
warn "Detected ${MY_SHELL} shell on your system..."
|
||||
warn "If you want ghcup to automatically add the required PATH variable to \"${GHCUP_PROFILE_FILE}\""
|
||||
warn ""
|
||||
warn "[Y] Yes [N] No [?] Help (default is \"Y\")."
|
||||
warn ""
|
||||
|
||||
while true; do
|
||||
read -r next_answer </dev/tty
|
||||
|
||||
case $next_answer in
|
||||
[Nn]*)
|
||||
_done ;;
|
||||
[Yy]* | "")
|
||||
case $MY_SHELL in
|
||||
"") break ;;
|
||||
fish)
|
||||
mkdir -p "${GHCUP_PROFILE_FILE%/*}"
|
||||
sed -i -e '/# ghcup-env$/ s/^#*/#/' "${GHCUP_PROFILE_FILE}"
|
||||
echo "set -q GHCUP_INSTALL_BASE_PREFIX[1]; or set GHCUP_INSTALL_BASE_PREFIX \$HOME ; test -f $GHCUP_DIR/env ; and set -gx PATH \$HOME/.cabal/bin $GHCUP_BIN \$PATH # ghcup-env" >> "${GHCUP_PROFILE_FILE}"
|
||||
break ;;
|
||||
bash)
|
||||
sed -i -e '/# ghcup-env$/ s/^#*/#/' "${GHCUP_PROFILE_FILE}"
|
||||
echo "[ -f \"${GHCUP_DIR}/env\" ] && source \"${GHCUP_DIR}/env\" # ghcup-env" >> "${GHCUP_PROFILE_FILE}"
|
||||
case "${plat}" in
|
||||
"Darwin"|"darwin")
|
||||
if ! grep -q "ghcup-env" "${HOME}/.bash_profile" ; then
|
||||
echo "[[ -f ~/.bashrc ]] && source ~/.bashrc # ghcup-env" >> "${HOME}/.bash_profile"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
break ;;
|
||||
|
||||
zsh)
|
||||
sed -i -e '/# ghcup-env$/ s/^#*/#/' "${GHCUP_PROFILE_FILE}"
|
||||
echo "[ -f \"${GHCUP_DIR}/env\" ] && source \"${GHCUP_DIR}/env\" # ghcup-env" >> "${GHCUP_PROFILE_FILE}"
|
||||
break ;;
|
||||
esac
|
||||
warn "OK! ${GHCUP_PROFILE_FILE} has been modified. Restart your terminal for the changes to take effect,"
|
||||
warn "or type \"source ${GHCUP_DIR}/env\" to apply them in your current terminal session."
|
||||
_done
|
||||
;;
|
||||
*)
|
||||
echo "Possible choices are:"
|
||||
echo
|
||||
echo "Y - Yes, update my \"${GHCUP_PROFILE_FILE}\" (default)"
|
||||
echo "N - No, don't mess with my configuration"
|
||||
echo
|
||||
echo "Please make your choice and press ENTER."
|
||||
;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
|
||||
_done
|
||||
|
||||
)
|
||||
|
||||
# vim: tabstop=4 shiftwidth=4 expandtab
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
packages: ./ghcup.cabal
|
||||
|
||||
with-compiler: ghc-8.10.4
|
||||
|
||||
optional-packages: ./3rdparty/*/*.cabal
|
||||
|
||||
optimization: 2
|
||||
|
||||
package streamly
|
||||
ghc-options: -O2 -fspec-constr-recursive=16 -fmax-worker-args=16
|
||||
|
||||
package ghcup
|
||||
ghc-options: -O2 -fspec-constr-recursive=16 -fmax-worker-args=16
|
||||
|
||||
constraints: http-io-streams -brotli
|
||||
|
||||
package libarchive
|
||||
flags: -system-libarchive
|
||||
|
||||
allow-newer: base, ghc-prim, template-haskell
|
||||
@@ -1,261 +0,0 @@
|
||||
active-repositories: hackage.haskell.org:merge
|
||||
constraints: any.Cabal ==3.2.1.0,
|
||||
any.HUnit ==1.6.2.0,
|
||||
any.IfElse ==0.85,
|
||||
any.QuickCheck ==2.14.2,
|
||||
QuickCheck -old-random +templatehaskell,
|
||||
any.StateVar ==1.2.1,
|
||||
any.abstract-deque ==0.3,
|
||||
abstract-deque -usecas,
|
||||
any.aeson ==1.5.6.0,
|
||||
aeson -bytestring-builder -cffi -developer -fast,
|
||||
any.aeson-pretty ==0.8.8,
|
||||
aeson-pretty -lib-only,
|
||||
any.alex ==3.2.6,
|
||||
alex +small_base,
|
||||
any.ansi-terminal ==0.11,
|
||||
ansi-terminal -example,
|
||||
any.ansi-wl-pprint ==0.6.9,
|
||||
ansi-wl-pprint -example,
|
||||
any.array ==0.5.4.0,
|
||||
any.ascii-string ==1.0.1.4,
|
||||
any.assoc ==1.0.2,
|
||||
any.async ==2.2.3,
|
||||
async -bench,
|
||||
any.atomic-primops ==0.8.4,
|
||||
atomic-primops -debug,
|
||||
any.attoparsec ==0.13.2.5,
|
||||
attoparsec -developer,
|
||||
any.auto-update ==0.1.6,
|
||||
any.base ==4.14.1.0,
|
||||
any.base-compat ==0.11.2,
|
||||
any.base-compat-batteries ==0.11.2,
|
||||
any.base-orphans ==0.8.4,
|
||||
any.base16-bytestring ==1.0.1.0,
|
||||
any.base64-bytestring ==1.2.0.1,
|
||||
any.bifunctors ==5.5.10,
|
||||
bifunctors +semigroups +tagged,
|
||||
any.binary ==0.8.8.0,
|
||||
any.blaze-builder ==0.4.2.1,
|
||||
any.bytestring ==0.10.12.0,
|
||||
any.bz2 ==1.0.1.0,
|
||||
bz2 -cross +with-bzlib,
|
||||
any.c2hs ==0.28.7,
|
||||
c2hs +base3 -regression,
|
||||
any.call-stack ==0.3.0,
|
||||
any.case-insensitive ==1.2.1.0,
|
||||
any.casing ==0.1.4.1,
|
||||
any.cereal ==0.5.8.1,
|
||||
cereal -bytestring-builder,
|
||||
any.chs-cabal ==0.1.1.0,
|
||||
any.chs-deps ==0.1.0.0,
|
||||
chs-deps -cross,
|
||||
any.clock ==0.8.2,
|
||||
clock -llvm,
|
||||
any.cmdargs ==0.10.21,
|
||||
cmdargs +quotation -testprog,
|
||||
any.colour ==2.3.5,
|
||||
any.comonad ==5.0.8,
|
||||
comonad +containers +distributive +indexed-traversable,
|
||||
any.composition-prelude ==3.0.0.2,
|
||||
composition-prelude -development,
|
||||
any.concurrent-output ==1.10.12,
|
||||
any.conduit ==1.3.4.1,
|
||||
any.conduit-extra ==1.3.5,
|
||||
any.containers ==0.6.2.1,
|
||||
any.contravariant ==1.5.3,
|
||||
contravariant +semigroups +statevar +tagged,
|
||||
any.cryptohash-sha256 ==0.11.102.0,
|
||||
cryptohash-sha256 -exe +use-cbits,
|
||||
any.data-default-class ==0.1.2.0,
|
||||
any.data-fix ==0.3.1,
|
||||
any.deepseq ==1.4.4.0,
|
||||
any.deferred-folds ==0.9.17,
|
||||
any.directory ==1.3.6.0,
|
||||
any.distributive ==0.6.2.1,
|
||||
distributive +semigroups +tagged,
|
||||
any.dlist ==1.0,
|
||||
dlist -werror,
|
||||
any.easy-file ==0.2.2,
|
||||
any.errors ==2.3.0,
|
||||
any.exceptions ==0.10.4,
|
||||
any.fast-logger ==3.0.3,
|
||||
any.filepath ==1.4.2.1,
|
||||
any.focus ==1.0.2,
|
||||
any.foldl ==1.4.11,
|
||||
any.free ==5.1.6,
|
||||
any.fusion-plugin-types ==0.1.0,
|
||||
any.generic-arbitrary ==0.1.0,
|
||||
any.generics-sop ==0.5.1.1,
|
||||
any.ghc-boot-th ==8.10.4,
|
||||
any.ghc-prim ==0.6.1,
|
||||
ghcup -internal-downloader -tar -tui,
|
||||
any.happy ==1.20.0,
|
||||
any.hashable ==1.3.1.0,
|
||||
hashable +integer-gmp,
|
||||
any.haskell-src-exts ==1.23.1,
|
||||
any.haskell-src-meta ==0.8.7,
|
||||
any.haskus-utils-data ==1.4,
|
||||
any.haskus-utils-types ==1.5.1,
|
||||
any.haskus-utils-variant ==3.1,
|
||||
any.heaps ==0.3.6.1,
|
||||
any.hpath ==0.11.0,
|
||||
any.hpath-directory ==0.14.1,
|
||||
any.hpath-filepath ==0.10.4,
|
||||
any.hpath-io ==0.14.1,
|
||||
any.hpath-posix ==0.13.2,
|
||||
any.hsc2hs ==0.68.7,
|
||||
hsc2hs -in-ghc-tree,
|
||||
any.hspec ==2.7.8,
|
||||
any.hspec-core ==2.7.8,
|
||||
any.hspec-discover ==2.7.8,
|
||||
any.hspec-expectations ==0.8.2,
|
||||
any.hspec-golden-aeson ==0.7.0.0,
|
||||
any.indexed-profunctors ==0.1,
|
||||
any.indexed-traversable ==0.1.1,
|
||||
any.indexed-traversable-instances ==0.1,
|
||||
any.integer-gmp ==1.0.3.0,
|
||||
any.integer-logarithms ==1.0.3.1,
|
||||
integer-logarithms -check-bounds +integer-gmp,
|
||||
any.language-c ==0.8.3,
|
||||
language-c -allwarnings +iecfpextension +separatesyb +usebytestrings,
|
||||
any.libarchive ==3.0.2.1,
|
||||
libarchive -cross -low-memory -system-libarchive,
|
||||
any.libyaml ==0.1.2,
|
||||
libyaml -no-unicode -system-libyaml,
|
||||
any.lifted-base ==0.2.3.12,
|
||||
any.list-t ==1.0.4,
|
||||
any.lockfree-queue ==0.2.3.1,
|
||||
lzma -static,
|
||||
any.math-functions ==0.3.4.1,
|
||||
math-functions +system-erf +system-expm1,
|
||||
any.megaparsec ==9.0.1,
|
||||
megaparsec -dev,
|
||||
any.microlens ==0.4.12.0,
|
||||
any.microlens-mtl ==0.2.0.1,
|
||||
any.microlens-th ==0.4.3.9,
|
||||
any.mmorph ==1.1.5,
|
||||
any.monad-control ==1.0.2.3,
|
||||
any.monad-logger ==0.3.36,
|
||||
monad-logger +template_haskell,
|
||||
any.monad-loops ==0.4.3,
|
||||
monad-loops +base4,
|
||||
any.mono-traversable ==1.0.15.1,
|
||||
any.mtl ==2.2.2,
|
||||
any.mwc-random ==0.15.0.1,
|
||||
any.network ==3.1.2.1,
|
||||
network -devel,
|
||||
any.old-locale ==1.0.0.7,
|
||||
any.old-time ==1.1.0.3,
|
||||
any.optics ==0.4,
|
||||
any.optics-core ==0.4,
|
||||
optics-core -explicit-generic-labels,
|
||||
any.optics-extra ==0.4,
|
||||
any.optics-th ==0.4,
|
||||
any.optics-vl ==0.2.1,
|
||||
any.optparse-applicative ==0.16.1.0,
|
||||
optparse-applicative +process,
|
||||
any.os-release ==1.0.2,
|
||||
os-release -devel,
|
||||
any.parallel ==3.2.2.0,
|
||||
any.parsec ==3.1.14.0,
|
||||
any.parser-combinators ==1.3.0,
|
||||
parser-combinators -dev,
|
||||
any.pretty ==1.1.3.6,
|
||||
any.pretty-terminal ==0.1.0.0,
|
||||
any.primitive ==0.7.1.0,
|
||||
any.primitive-extras ==0.8.2,
|
||||
any.primitive-unlifted ==0.1.3.0,
|
||||
any.process ==1.6.9.0,
|
||||
any.profunctors ==5.6.2,
|
||||
any.quickcheck-arbitrary-adt ==0.3.1.0,
|
||||
any.quickcheck-io ==0.2.0,
|
||||
any.random ==1.2.0,
|
||||
any.recursion-schemes ==5.2.2,
|
||||
recursion-schemes +template-haskell,
|
||||
any.regex-posix ==0.96.0.0,
|
||||
regex-posix -_regex-posix-clib,
|
||||
any.resourcet ==1.2.4.2,
|
||||
any.rts ==1.0,
|
||||
any.safe ==0.3.19,
|
||||
any.safe-exceptions ==0.1.7.1,
|
||||
any.scientific ==0.3.6.2,
|
||||
scientific -bytestring-builder -integer-simple,
|
||||
any.semigroupoids ==5.3.5,
|
||||
semigroupoids +comonad +containers +contravariant +distributive +tagged +unordered-containers,
|
||||
any.setenv ==0.1.1.3,
|
||||
any.sop-core ==0.5.0.1,
|
||||
any.split ==0.2.3.4,
|
||||
any.splitmix ==0.1.0.3,
|
||||
splitmix -optimised-mixer,
|
||||
any.stm ==2.5.0.0,
|
||||
any.stm-chans ==3.0.0.4,
|
||||
any.streaming-commons ==0.2.2.1,
|
||||
streaming-commons -use-bytestring-builder,
|
||||
any.streamly ==0.7.3,
|
||||
streamly -debug -dev -examples -examples-sdl -fusion-plugin -has-llvm -inspection -no-fusion -streamk,
|
||||
any.streamly-bytestring ==0.1.2,
|
||||
any.streamly-posix ==0.1.0.1,
|
||||
any.strict ==0.4.0.1,
|
||||
strict +assoc,
|
||||
any.strict-base ==0.4.0.0,
|
||||
any.string-interpolate ==0.3.1.0,
|
||||
string-interpolate -bytestring-builder -extended-benchmarks -text-builder,
|
||||
any.syb ==0.7.2.1,
|
||||
any.tagged ==0.8.6.1,
|
||||
tagged +deepseq +transformers,
|
||||
any.tasty ==1.3.1,
|
||||
tasty +clock,
|
||||
any.tasty-hunit ==0.10.0.3,
|
||||
any.tasty-quickcheck ==0.10.1.2,
|
||||
any.template-haskell ==2.16.0.0,
|
||||
any.terminal-size ==0.3.2.1,
|
||||
any.terminfo ==0.4.1.4,
|
||||
any.text ==1.2.4.1,
|
||||
any.text-conversions ==0.3.1,
|
||||
any.text-short ==0.1.3,
|
||||
text-short -asserts,
|
||||
any.tf-random ==0.5,
|
||||
any.th-abstraction ==0.4.2.0,
|
||||
any.th-compat ==0.1.1,
|
||||
any.th-lift ==0.8.2,
|
||||
any.th-lift-instances ==0.1.18,
|
||||
any.th-orphans ==0.13.11,
|
||||
any.th-reify-many ==0.1.9,
|
||||
any.these ==1.1.1.1,
|
||||
these +assoc,
|
||||
any.time ==1.9.3,
|
||||
any.time-compat ==1.9.5,
|
||||
time-compat -old-locale,
|
||||
any.transformers ==0.5.6.2,
|
||||
any.transformers-base ==0.4.5.2,
|
||||
transformers-base +orphaninstances,
|
||||
any.transformers-compat ==0.6.6,
|
||||
transformers-compat -five +five-three -four +generic-deriving +mtl -three -two,
|
||||
any.typed-process ==0.2.6.0,
|
||||
any.unbounded-delays ==0.1.1.1,
|
||||
any.unix ==2.7.2.2,
|
||||
any.unix-bytestring ==0.3.7.3,
|
||||
any.unix-compat ==0.5.3,
|
||||
unix-compat -old-time,
|
||||
any.unix-time ==0.4.7,
|
||||
any.unliftio-core ==0.2.0.1,
|
||||
any.unordered-containers ==0.2.13.0,
|
||||
unordered-containers -debug,
|
||||
any.uri-bytestring ==0.3.3.0,
|
||||
uri-bytestring -lib-werror,
|
||||
any.utf8-string ==1.0.2,
|
||||
any.uuid-types ==1.0.4,
|
||||
any.vector ==0.12.2.0,
|
||||
vector +boundschecks -internalchecks -unsafechecks -wall,
|
||||
any.vector-algorithms ==0.8.0.4,
|
||||
vector-algorithms +bench +boundschecks -internalchecks -llvm +properties -unsafechecks,
|
||||
any.versions ==4.0.3,
|
||||
any.vty ==5.33,
|
||||
any.wcwidth ==0.0.2,
|
||||
wcwidth -cli +split-base,
|
||||
any.word8 ==0.1.3,
|
||||
any.yaml ==0.11.5.0,
|
||||
yaml +no-examples +no-exe,
|
||||
zlib -non-blocking-ffi -pkg-config -static
|
||||
index-state: hackage.haskell.org 2021-03-07T18:36:25Z
|
||||
24
cabal.ghc8107.project
Normal file
@@ -0,0 +1,24 @@
|
||||
packages: ./ghcup.cabal
|
||||
|
||||
optional-packages: ./vendored/*/*.cabal
|
||||
|
||||
optimization: 2
|
||||
|
||||
package ghcup
|
||||
tests: True
|
||||
flags: +tui
|
||||
|
||||
constraints: http-io-streams -brotli
|
||||
|
||||
package libarchive
|
||||
flags: -system-libarchive
|
||||
|
||||
package aeson-pretty
|
||||
flags: +lib-only
|
||||
|
||||
package cabal-plan
|
||||
flags: -exe
|
||||
|
||||
allow-newer: base, ghc-prim, template-haskell, language-c
|
||||
|
||||
with-compiler: ghc-8.10.7
|
||||
213
cabal.ghc8107.project.freeze
Normal file
@@ -0,0 +1,213 @@
|
||||
active-repositories: hackage.haskell.org:merge
|
||||
constraints: any.Cabal ==3.2.1.0 || ==3.6.1.0,
|
||||
Cabal -bundled-binary-generic,
|
||||
any.HUnit ==1.6.2.0,
|
||||
any.HsOpenSSL ==0.11.7.2,
|
||||
HsOpenSSL -fast-bignum -homebrew-openssl -macports-openssl -use-pkg-config,
|
||||
any.HsYAML ==0.2.1.0,
|
||||
HsYAML -exe,
|
||||
any.HsYAML-aeson ==0.2.0.0,
|
||||
any.QuickCheck ==2.14.2,
|
||||
QuickCheck -old-random +templatehaskell,
|
||||
any.StateVar ==1.2.2,
|
||||
any.aeson ==1.5.6.0,
|
||||
aeson -bytestring-builder -cffi -developer -fast,
|
||||
any.aeson-pretty ==0.8.8,
|
||||
aeson-pretty +lib-only,
|
||||
any.alex ==3.2.6,
|
||||
alex +small_base,
|
||||
any.ansi-terminal ==0.11,
|
||||
ansi-terminal -example,
|
||||
any.ansi-wl-pprint ==0.6.9,
|
||||
ansi-wl-pprint -example,
|
||||
any.array ==0.5.4.0,
|
||||
any.assoc ==1.0.2,
|
||||
any.async ==2.2.3,
|
||||
async -bench,
|
||||
any.attoparsec ==0.13.2.5,
|
||||
attoparsec -developer,
|
||||
any.base ==4.14.3.0,
|
||||
any.base-compat ==0.12.0,
|
||||
any.base-compat-batteries ==0.12.0,
|
||||
any.base-orphans ==0.8.5,
|
||||
any.base16-bytestring ==1.0.1.0,
|
||||
any.base64-bytestring ==1.1.0.0,
|
||||
any.bifunctors ==5.5.11,
|
||||
bifunctors +semigroups +tagged,
|
||||
any.binary ==0.8.8.0,
|
||||
any.blaze-builder ==0.4.2.1,
|
||||
any.brick ==0.64.1,
|
||||
brick -demos,
|
||||
any.bytestring ==0.10.12.0,
|
||||
any.bz2 ==1.0.1.0,
|
||||
bz2 -cross +with-bzlib,
|
||||
any.c2hs ==0.28.8,
|
||||
c2hs +base3 -regression,
|
||||
any.cabal-plan ==0.7.2.0,
|
||||
cabal-plan -_ -exe -license-report,
|
||||
any.call-stack ==0.4.0,
|
||||
any.case-insensitive ==1.2.1.0,
|
||||
any.casing ==0.1.4.1,
|
||||
any.chs-cabal ==0.1.1.1,
|
||||
any.chs-deps ==0.1.0.0,
|
||||
chs-deps -cross,
|
||||
any.clock ==0.8.2,
|
||||
clock -llvm,
|
||||
any.colour ==2.3.6,
|
||||
any.comonad ==5.0.8,
|
||||
comonad +containers +distributive +indexed-traversable,
|
||||
any.composition-prelude ==3.0.0.2,
|
||||
composition-prelude -development,
|
||||
any.config-ini ==0.2.4.0,
|
||||
config-ini -enable-doctests,
|
||||
any.containers ==0.6.5.1,
|
||||
any.contravariant ==1.5.5,
|
||||
contravariant +semigroups +statevar +tagged,
|
||||
any.cpphs ==1.20.9.1,
|
||||
cpphs -old-locale,
|
||||
any.cryptohash-sha1 ==0.11.100.1,
|
||||
any.cryptohash-sha256 ==0.11.102.0,
|
||||
cryptohash-sha256 -exe +use-cbits,
|
||||
any.data-clist ==0.1.2.3,
|
||||
any.data-fix ==0.3.2,
|
||||
any.deepseq ==1.4.4.0,
|
||||
any.directory ==1.3.6.0,
|
||||
any.disk-free-space ==0.1.0.1,
|
||||
any.distributive ==0.6.2.1,
|
||||
distributive +semigroups +tagged,
|
||||
any.dlist ==1.0,
|
||||
dlist -werror,
|
||||
any.exceptions ==0.10.4,
|
||||
any.filepath ==1.4.2.1,
|
||||
any.free ==5.1.7,
|
||||
any.generic-arbitrary ==0.1.0,
|
||||
any.ghc-boot-th ==8.10.7,
|
||||
any.ghc-byteorder ==4.11.0.0.10,
|
||||
any.ghc-prim ==0.6.1,
|
||||
any.happy ==1.20.0,
|
||||
any.hashable ==1.3.3.0,
|
||||
hashable +integer-gmp -random-initial-seed,
|
||||
any.haskus-utils-data ==1.4,
|
||||
any.haskus-utils-types ==1.5.1,
|
||||
any.haskus-utils-variant ==3.1,
|
||||
any.hsc2hs ==0.68.7,
|
||||
hsc2hs -in-ghc-tree,
|
||||
any.hspec ==2.7.10,
|
||||
any.hspec-core ==2.7.10,
|
||||
any.hspec-discover ==2.7.10,
|
||||
any.hspec-expectations ==0.8.2,
|
||||
any.hspec-golden-aeson ==0.9.0.0,
|
||||
any.http-io-streams ==0.1.6.0,
|
||||
http-io-streams -brotli +fast-xor,
|
||||
any.indexed-profunctors ==0.1.1,
|
||||
any.indexed-traversable ==0.1.1,
|
||||
any.indexed-traversable-instances ==0.1,
|
||||
any.integer-gmp ==1.0.3.0,
|
||||
any.integer-logarithms ==1.0.3.1,
|
||||
integer-logarithms -check-bounds +integer-gmp,
|
||||
any.io-streams ==1.5.2.1,
|
||||
io-streams +network -nointeractivetests +zlib,
|
||||
any.language-c ==0.9.0.1,
|
||||
language-c -allwarnings +iecfpextension +usebytestrings,
|
||||
any.libarchive ==3.0.3.0,
|
||||
libarchive -cross -low-memory -system-libarchive,
|
||||
any.lzma-static ==5.2.5.4,
|
||||
any.megaparsec ==9.0.1,
|
||||
megaparsec -dev,
|
||||
any.microlens ==0.4.12.0,
|
||||
any.microlens-mtl ==0.2.0.1,
|
||||
any.microlens-th ==0.4.3.10,
|
||||
any.mtl ==2.2.2,
|
||||
any.network ==3.1.2.2,
|
||||
network -devel,
|
||||
any.network-uri ==2.6.4.1,
|
||||
any.openssl-streams ==1.2.3.0,
|
||||
any.optics ==0.4,
|
||||
any.optics-core ==0.4,
|
||||
optics-core -explicit-generic-labels,
|
||||
any.optics-extra ==0.4,
|
||||
any.optics-th ==0.4,
|
||||
any.optparse-applicative ==0.16.1.0,
|
||||
optparse-applicative +process,
|
||||
any.os-release ==1.0.2,
|
||||
os-release -devel,
|
||||
any.parallel ==3.2.2.0,
|
||||
any.parsec ==3.1.14.0,
|
||||
any.parser-combinators ==1.3.0,
|
||||
parser-combinators -dev,
|
||||
any.polyparse ==1.13,
|
||||
any.pretty ==1.1.3.6,
|
||||
any.pretty-terminal ==0.1.0.0,
|
||||
any.primitive ==0.7.2.0,
|
||||
any.process ==1.6.13.2,
|
||||
any.profunctors ==5.6.2,
|
||||
any.quickcheck-arbitrary-adt ==0.3.1.0,
|
||||
any.quickcheck-io ==0.2.0,
|
||||
any.random ==1.2.1,
|
||||
any.recursion-schemes ==5.2.2.1,
|
||||
recursion-schemes +template-haskell,
|
||||
any.regex-base ==0.94.0.1,
|
||||
any.regex-posix ==0.96.0.1,
|
||||
regex-posix -_regex-posix-clib,
|
||||
any.resourcet ==1.2.4.3,
|
||||
any.rts ==1.0.1,
|
||||
any.safe ==0.3.19,
|
||||
any.safe-exceptions ==0.1.7.2,
|
||||
any.scientific ==0.3.7.0,
|
||||
scientific -bytestring-builder -integer-simple,
|
||||
any.semigroupoids ==5.3.5,
|
||||
semigroupoids +comonad +containers +contravariant +distributive +tagged +unordered-containers,
|
||||
any.setenv ==0.1.1.3,
|
||||
any.split ==0.2.3.4,
|
||||
any.splitmix ==0.1.0.3,
|
||||
splitmix -optimised-mixer,
|
||||
any.stm ==2.5.0.1,
|
||||
any.strict ==0.4.0.1,
|
||||
strict +assoc,
|
||||
any.strict-base ==0.4.0.0,
|
||||
any.tagged ==0.8.6.1,
|
||||
tagged +deepseq +transformers,
|
||||
any.template-haskell ==2.16.0.0,
|
||||
any.temporary ==1.3,
|
||||
any.terminal-progress-bar ==0.4.1,
|
||||
any.terminal-size ==0.3.2.1,
|
||||
any.terminfo ==0.4.1.4,
|
||||
any.text ==1.2.4.1,
|
||||
any.text-zipper ==0.11,
|
||||
any.tf-random ==0.5,
|
||||
any.th-abstraction ==0.4.3.0,
|
||||
any.th-compat ==0.1.3,
|
||||
any.th-lift ==0.8.2,
|
||||
any.th-lift-instances ==0.1.18,
|
||||
any.these ==1.1.1.1,
|
||||
these +assoc,
|
||||
any.time ==1.9.3,
|
||||
any.time-compat ==1.9.6.1,
|
||||
time-compat -old-locale,
|
||||
any.transformers ==0.5.6.2,
|
||||
any.transformers-base ==0.4.6,
|
||||
transformers-base +orphaninstances,
|
||||
any.transformers-compat ==0.7,
|
||||
transformers-compat -five +five-three -four +generic-deriving +mtl -three -two,
|
||||
any.unix ==2.7.2.2,
|
||||
any.unix-bytestring ==0.3.7.3,
|
||||
any.unix-compat ==0.5.3,
|
||||
unix-compat -old-time,
|
||||
any.unliftio-core ==0.2.0.1,
|
||||
any.unordered-containers ==0.2.14.0,
|
||||
unordered-containers -debug,
|
||||
any.uri-bytestring ==0.3.3.1,
|
||||
uri-bytestring -lib-werror,
|
||||
any.utf8-string ==1.0.2,
|
||||
any.uuid-types ==1.0.5,
|
||||
any.vector ==0.12.3.1,
|
||||
vector +boundschecks -internalchecks -unsafechecks -wall,
|
||||
any.versions ==5.0.0,
|
||||
any.vty ==5.33,
|
||||
any.word-wrap ==0.5,
|
||||
any.word8 ==0.1.3,
|
||||
any.xor ==0.0.1.0,
|
||||
any.zlib ==0.6.2.3,
|
||||
zlib -bundled-c-zlib -non-blocking-ffi -pkg-config,
|
||||
any.zlib-bindings ==0.1.1.5
|
||||
index-state: hackage.haskell.org 2021-10-01T15:16:26Z
|
||||
@@ -1,20 +0,0 @@
|
||||
packages: ./ghcup.cabal
|
||||
|
||||
with-compiler: ghc-8.8.4
|
||||
|
||||
optional-packages: ./3rdparty/*/*.cabal
|
||||
|
||||
optimization: 2
|
||||
|
||||
package streamly
|
||||
ghc-options: -O2 -fspec-constr-recursive=16 -fmax-worker-args=16
|
||||
|
||||
package ghcup
|
||||
ghc-options: -O2 -fspec-constr-recursive=16 -fmax-worker-args=16
|
||||
|
||||
constraints: http-io-streams -brotli
|
||||
|
||||
package libarchive
|
||||
flags: -system-libarchive
|
||||
|
||||
allow-newer: base, ghc-prim, template-haskell
|
||||
@@ -1,262 +0,0 @@
|
||||
active-repositories: hackage.haskell.org:merge
|
||||
constraints: any.Cabal ==3.0.1.0,
|
||||
any.HUnit ==1.6.2.0,
|
||||
any.IfElse ==0.85,
|
||||
any.QuickCheck ==2.14.2,
|
||||
QuickCheck -old-random +templatehaskell,
|
||||
any.StateVar ==1.2.1,
|
||||
any.abstract-deque ==0.3,
|
||||
abstract-deque -usecas,
|
||||
any.aeson ==1.5.6.0,
|
||||
aeson -bytestring-builder -cffi -developer -fast,
|
||||
any.aeson-pretty ==0.8.8,
|
||||
aeson-pretty -lib-only,
|
||||
any.alex ==3.2.6,
|
||||
alex +small_base,
|
||||
any.ansi-terminal ==0.11,
|
||||
ansi-terminal -example,
|
||||
any.ansi-wl-pprint ==0.6.9,
|
||||
ansi-wl-pprint -example,
|
||||
any.array ==0.5.4.0,
|
||||
any.ascii-string ==1.0.1.4,
|
||||
any.assoc ==1.0.2,
|
||||
any.async ==2.2.3,
|
||||
async -bench,
|
||||
any.atomic-primops ==0.8.4,
|
||||
atomic-primops -debug,
|
||||
any.attoparsec ==0.13.2.5,
|
||||
attoparsec -developer,
|
||||
any.auto-update ==0.1.6,
|
||||
any.base ==4.13.0.0,
|
||||
any.base-compat ==0.11.2,
|
||||
any.base-compat-batteries ==0.11.2,
|
||||
any.base-orphans ==0.8.4,
|
||||
any.base16-bytestring ==1.0.1.0,
|
||||
any.base64-bytestring ==1.2.0.1,
|
||||
any.bifunctors ==5.5.10,
|
||||
bifunctors +semigroups +tagged,
|
||||
any.binary ==0.8.7.0,
|
||||
any.blaze-builder ==0.4.2.1,
|
||||
any.bytestring ==0.10.10.1,
|
||||
any.bz2 ==1.0.1.0,
|
||||
bz2 -cross +with-bzlib,
|
||||
any.c2hs ==0.28.7,
|
||||
c2hs +base3 -regression,
|
||||
any.call-stack ==0.3.0,
|
||||
any.case-insensitive ==1.2.1.0,
|
||||
any.casing ==0.1.4.1,
|
||||
any.cereal ==0.5.8.1,
|
||||
cereal -bytestring-builder,
|
||||
any.chs-cabal ==0.1.1.0,
|
||||
any.chs-deps ==0.1.0.0,
|
||||
chs-deps -cross,
|
||||
any.clock ==0.8.2,
|
||||
clock -llvm,
|
||||
any.cmdargs ==0.10.21,
|
||||
cmdargs +quotation -testprog,
|
||||
any.colour ==2.3.5,
|
||||
any.comonad ==5.0.8,
|
||||
comonad +containers +distributive +indexed-traversable,
|
||||
any.composition-prelude ==3.0.0.2,
|
||||
composition-prelude -development,
|
||||
any.concurrent-output ==1.10.12,
|
||||
any.conduit ==1.3.4.1,
|
||||
any.conduit-extra ==1.3.5,
|
||||
any.containers ==0.6.2.1,
|
||||
any.contravariant ==1.5.3,
|
||||
contravariant +semigroups +statevar +tagged,
|
||||
any.cryptohash-sha256 ==0.11.102.0,
|
||||
cryptohash-sha256 -exe +use-cbits,
|
||||
any.data-default-class ==0.1.2.0,
|
||||
any.data-fix ==0.3.1,
|
||||
any.deepseq ==1.4.4.0,
|
||||
any.deferred-folds ==0.9.17,
|
||||
any.directory ==1.3.6.0,
|
||||
any.distributive ==0.6.2.1,
|
||||
distributive +semigroups +tagged,
|
||||
any.dlist ==1.0,
|
||||
dlist -werror,
|
||||
any.easy-file ==0.2.2,
|
||||
any.errors ==2.3.0,
|
||||
any.exceptions ==0.10.4,
|
||||
exceptions +transformers-0-4,
|
||||
any.fast-logger ==3.0.3,
|
||||
any.filepath ==1.4.2.1,
|
||||
any.focus ==1.0.2,
|
||||
any.foldl ==1.4.11,
|
||||
any.free ==5.1.6,
|
||||
any.fusion-plugin-types ==0.1.0,
|
||||
any.generic-arbitrary ==0.1.0,
|
||||
any.generics-sop ==0.5.1.1,
|
||||
any.ghc-boot-th ==8.8.4,
|
||||
any.ghc-prim ==0.5.3,
|
||||
ghcup -internal-downloader -tar -tui,
|
||||
any.happy ==1.20.0,
|
||||
any.hashable ==1.3.1.0,
|
||||
hashable +integer-gmp,
|
||||
any.haskell-src-exts ==1.23.1,
|
||||
any.haskell-src-meta ==0.8.7,
|
||||
any.haskus-utils-data ==1.4,
|
||||
any.haskus-utils-types ==1.5.1,
|
||||
any.haskus-utils-variant ==3.1,
|
||||
any.heaps ==0.3.6.1,
|
||||
any.hpath ==0.11.0,
|
||||
any.hpath-directory ==0.14.1,
|
||||
any.hpath-filepath ==0.10.4,
|
||||
any.hpath-io ==0.14.1,
|
||||
any.hpath-posix ==0.13.2,
|
||||
any.hsc2hs ==0.68.7,
|
||||
hsc2hs -in-ghc-tree,
|
||||
any.hspec ==2.7.8,
|
||||
any.hspec-core ==2.7.8,
|
||||
any.hspec-discover ==2.7.8,
|
||||
any.hspec-expectations ==0.8.2,
|
||||
any.hspec-golden-aeson ==0.7.0.0,
|
||||
any.indexed-profunctors ==0.1,
|
||||
any.indexed-traversable ==0.1.1,
|
||||
any.indexed-traversable-instances ==0.1,
|
||||
any.integer-gmp ==1.0.2.0,
|
||||
any.integer-logarithms ==1.0.3.1,
|
||||
integer-logarithms -check-bounds +integer-gmp,
|
||||
any.language-c ==0.8.3,
|
||||
language-c -allwarnings +iecfpextension +separatesyb +usebytestrings,
|
||||
any.libarchive ==3.0.2.1,
|
||||
libarchive -cross -low-memory -system-libarchive,
|
||||
any.libyaml ==0.1.2,
|
||||
libyaml -no-unicode -system-libyaml,
|
||||
any.lifted-base ==0.2.3.12,
|
||||
any.list-t ==1.0.4,
|
||||
any.lockfree-queue ==0.2.3.1,
|
||||
lzma -static,
|
||||
any.math-functions ==0.3.4.1,
|
||||
math-functions +system-erf +system-expm1,
|
||||
any.megaparsec ==9.0.1,
|
||||
megaparsec -dev,
|
||||
any.microlens ==0.4.12.0,
|
||||
any.microlens-mtl ==0.2.0.1,
|
||||
any.microlens-th ==0.4.3.9,
|
||||
any.mmorph ==1.1.5,
|
||||
any.monad-control ==1.0.2.3,
|
||||
any.monad-logger ==0.3.36,
|
||||
monad-logger +template_haskell,
|
||||
any.monad-loops ==0.4.3,
|
||||
monad-loops +base4,
|
||||
any.mono-traversable ==1.0.15.1,
|
||||
any.mtl ==2.2.2,
|
||||
any.mwc-random ==0.15.0.1,
|
||||
any.network ==3.1.2.1,
|
||||
network -devel,
|
||||
any.old-locale ==1.0.0.7,
|
||||
any.old-time ==1.1.0.3,
|
||||
any.optics ==0.4,
|
||||
any.optics-core ==0.4,
|
||||
optics-core -explicit-generic-labels,
|
||||
any.optics-extra ==0.4,
|
||||
any.optics-th ==0.4,
|
||||
any.optics-vl ==0.2.1,
|
||||
any.optparse-applicative ==0.16.1.0,
|
||||
optparse-applicative +process,
|
||||
any.os-release ==1.0.2,
|
||||
os-release -devel,
|
||||
any.parallel ==3.2.2.0,
|
||||
any.parsec ==3.1.14.0,
|
||||
any.parser-combinators ==1.3.0,
|
||||
parser-combinators -dev,
|
||||
any.pretty ==1.1.3.6,
|
||||
any.pretty-terminal ==0.1.0.0,
|
||||
any.primitive ==0.7.1.0,
|
||||
any.primitive-extras ==0.8.2,
|
||||
any.primitive-unlifted ==0.1.3.0,
|
||||
any.process ==1.6.9.0,
|
||||
any.profunctors ==5.6.2,
|
||||
any.quickcheck-arbitrary-adt ==0.3.1.0,
|
||||
any.quickcheck-io ==0.2.0,
|
||||
any.random ==1.2.0,
|
||||
any.recursion-schemes ==5.2.2,
|
||||
recursion-schemes +template-haskell,
|
||||
any.regex-posix ==0.96.0.0,
|
||||
regex-posix -_regex-posix-clib,
|
||||
any.resourcet ==1.2.4.2,
|
||||
any.rts ==1.0,
|
||||
any.safe ==0.3.19,
|
||||
any.safe-exceptions ==0.1.7.1,
|
||||
any.scientific ==0.3.6.2,
|
||||
scientific -bytestring-builder -integer-simple,
|
||||
any.semigroupoids ==5.3.5,
|
||||
semigroupoids +comonad +containers +contravariant +distributive +tagged +unordered-containers,
|
||||
any.setenv ==0.1.1.3,
|
||||
any.sop-core ==0.5.0.1,
|
||||
any.split ==0.2.3.4,
|
||||
any.splitmix ==0.1.0.3,
|
||||
splitmix -optimised-mixer,
|
||||
any.stm ==2.5.0.0,
|
||||
any.stm-chans ==3.0.0.4,
|
||||
any.streaming-commons ==0.2.2.1,
|
||||
streaming-commons -use-bytestring-builder,
|
||||
any.streamly ==0.7.3,
|
||||
streamly -debug -dev -examples -examples-sdl -fusion-plugin -has-llvm -inspection -no-fusion -streamk,
|
||||
any.streamly-bytestring ==0.1.2,
|
||||
any.streamly-posix ==0.1.0.1,
|
||||
any.strict ==0.4.0.1,
|
||||
strict +assoc,
|
||||
any.strict-base ==0.4.0.0,
|
||||
any.string-interpolate ==0.3.1.0,
|
||||
string-interpolate -bytestring-builder -extended-benchmarks -text-builder,
|
||||
any.syb ==0.7.2.1,
|
||||
any.tagged ==0.8.6.1,
|
||||
tagged +deepseq +transformers,
|
||||
any.tasty ==1.3.1,
|
||||
tasty +clock,
|
||||
any.tasty-hunit ==0.10.0.3,
|
||||
any.tasty-quickcheck ==0.10.1.2,
|
||||
any.template-haskell ==2.15.0.0,
|
||||
any.terminal-size ==0.3.2.1,
|
||||
any.terminfo ==0.4.1.4,
|
||||
any.text ==1.2.4.0,
|
||||
any.text-conversions ==0.3.1,
|
||||
any.text-short ==0.1.3,
|
||||
text-short -asserts,
|
||||
any.tf-random ==0.5,
|
||||
any.th-abstraction ==0.4.2.0,
|
||||
any.th-compat ==0.1.1,
|
||||
any.th-lift ==0.8.2,
|
||||
any.th-lift-instances ==0.1.18,
|
||||
any.th-orphans ==0.13.11,
|
||||
any.th-reify-many ==0.1.9,
|
||||
any.these ==1.1.1.1,
|
||||
these +assoc,
|
||||
any.time ==1.9.3,
|
||||
any.time-compat ==1.9.5,
|
||||
time-compat -old-locale,
|
||||
any.transformers ==0.5.6.2,
|
||||
any.transformers-base ==0.4.5.2,
|
||||
transformers-base +orphaninstances,
|
||||
any.transformers-compat ==0.6.6,
|
||||
transformers-compat -five +five-three -four +generic-deriving +mtl -three -two,
|
||||
any.typed-process ==0.2.6.0,
|
||||
any.unbounded-delays ==0.1.1.1,
|
||||
any.unix ==2.7.2.2,
|
||||
any.unix-bytestring ==0.3.7.3,
|
||||
any.unix-compat ==0.5.3,
|
||||
unix-compat -old-time,
|
||||
any.unix-time ==0.4.7,
|
||||
any.unliftio-core ==0.2.0.1,
|
||||
any.unordered-containers ==0.2.13.0,
|
||||
unordered-containers -debug,
|
||||
any.uri-bytestring ==0.3.3.0,
|
||||
uri-bytestring -lib-werror,
|
||||
any.utf8-string ==1.0.2,
|
||||
any.uuid-types ==1.0.4,
|
||||
any.vector ==0.12.2.0,
|
||||
vector +boundschecks -internalchecks -unsafechecks -wall,
|
||||
any.vector-algorithms ==0.8.0.4,
|
||||
vector-algorithms +bench +boundschecks -internalchecks -llvm +properties -unsafechecks,
|
||||
any.versions ==4.0.3,
|
||||
any.vty ==5.33,
|
||||
any.wcwidth ==0.0.2,
|
||||
wcwidth -cli +split-base,
|
||||
any.word8 ==0.1.3,
|
||||
any.yaml ==0.11.5.0,
|
||||
yaml +no-examples +no-exe,
|
||||
zlib -non-blocking-ffi -pkg-config -static
|
||||
index-state: hackage.haskell.org 2021-03-07T18:36:25Z
|
||||
24
cabal.ghc901.project
Normal file
@@ -0,0 +1,24 @@
|
||||
packages: ./ghcup.cabal
|
||||
|
||||
optional-packages: ./vendored/*/*.cabal
|
||||
|
||||
optimization: 2
|
||||
|
||||
package ghcup
|
||||
tests: True
|
||||
flags: +tui
|
||||
|
||||
constraints: http-io-streams -brotli
|
||||
|
||||
package libarchive
|
||||
flags: -system-libarchive
|
||||
|
||||
package aeson-pretty
|
||||
flags: +lib-only
|
||||
|
||||
package cabal-plan
|
||||
flags: -exe
|
||||
|
||||
allow-newer: base, ghc-prim, template-haskell, language-c
|
||||
|
||||
with-compiler: ghc-9.0.1
|
||||
213
cabal.ghc901.project.freeze
Normal file
@@ -0,0 +1,213 @@
|
||||
active-repositories: hackage.haskell.org:merge
|
||||
constraints: any.Cabal ==3.4.0.0 || ==3.6.1.0,
|
||||
Cabal -bundled-binary-generic,
|
||||
any.HUnit ==1.6.2.0,
|
||||
any.HsOpenSSL ==0.11.7.2,
|
||||
HsOpenSSL -fast-bignum -homebrew-openssl -macports-openssl -use-pkg-config,
|
||||
any.HsYAML ==0.2.1.0,
|
||||
HsYAML -exe,
|
||||
any.HsYAML-aeson ==0.2.0.0,
|
||||
any.QuickCheck ==2.14.2,
|
||||
QuickCheck -old-random +templatehaskell,
|
||||
any.StateVar ==1.2.2,
|
||||
any.aeson ==1.5.6.0,
|
||||
aeson -bytestring-builder -cffi -developer -fast,
|
||||
any.aeson-pretty ==0.8.8,
|
||||
aeson-pretty +lib-only,
|
||||
any.alex ==3.2.6,
|
||||
alex +small_base,
|
||||
any.ansi-terminal ==0.11,
|
||||
ansi-terminal -example,
|
||||
any.ansi-wl-pprint ==0.6.9,
|
||||
ansi-wl-pprint -example,
|
||||
any.array ==0.5.4.0,
|
||||
any.assoc ==1.0.2,
|
||||
any.async ==2.2.3,
|
||||
async -bench,
|
||||
any.attoparsec ==0.13.2.5,
|
||||
attoparsec -developer,
|
||||
any.base ==4.15.0.0,
|
||||
any.base-compat ==0.12.0,
|
||||
any.base-compat-batteries ==0.12.0,
|
||||
any.base-orphans ==0.8.5,
|
||||
any.base16-bytestring ==1.0.1.0,
|
||||
any.base64-bytestring ==1.1.0.0,
|
||||
any.bifunctors ==5.5.11,
|
||||
bifunctors +semigroups +tagged,
|
||||
any.binary ==0.8.8.0,
|
||||
any.blaze-builder ==0.4.2.1,
|
||||
any.brick ==0.64.1,
|
||||
brick -demos,
|
||||
any.bytestring ==0.10.12.1,
|
||||
any.bz2 ==1.0.1.0,
|
||||
bz2 -cross +with-bzlib,
|
||||
any.c2hs ==0.28.8,
|
||||
c2hs +base3 -regression,
|
||||
any.cabal-plan ==0.7.2.0,
|
||||
cabal-plan -_ -exe -license-report,
|
||||
any.call-stack ==0.4.0,
|
||||
any.case-insensitive ==1.2.1.0,
|
||||
any.casing ==0.1.4.1,
|
||||
any.chs-cabal ==0.1.1.1,
|
||||
any.chs-deps ==0.1.0.0,
|
||||
chs-deps -cross,
|
||||
any.clock ==0.8.2,
|
||||
clock -llvm,
|
||||
any.colour ==2.3.6,
|
||||
any.comonad ==5.0.8,
|
||||
comonad +containers +distributive +indexed-traversable,
|
||||
any.composition-prelude ==3.0.0.2,
|
||||
composition-prelude -development,
|
||||
any.config-ini ==0.2.4.0,
|
||||
config-ini -enable-doctests,
|
||||
any.containers ==0.6.4.1,
|
||||
any.contravariant ==1.5.5,
|
||||
contravariant +semigroups +statevar +tagged,
|
||||
any.cpphs ==1.20.9.1,
|
||||
cpphs -old-locale,
|
||||
any.cryptohash-sha1 ==0.11.100.1,
|
||||
any.cryptohash-sha256 ==0.11.102.0,
|
||||
cryptohash-sha256 -exe +use-cbits,
|
||||
any.data-clist ==0.1.2.3,
|
||||
any.data-fix ==0.3.2,
|
||||
any.deepseq ==1.4.5.0,
|
||||
any.directory ==1.3.6.1,
|
||||
any.disk-free-space ==0.1.0.1,
|
||||
any.distributive ==0.6.2.1,
|
||||
distributive +semigroups +tagged,
|
||||
any.dlist ==1.0,
|
||||
dlist -werror,
|
||||
any.exceptions ==0.10.4,
|
||||
any.filepath ==1.4.2.1,
|
||||
any.free ==5.1.7,
|
||||
any.generic-arbitrary ==0.1.0,
|
||||
any.ghc-bignum ==1.0,
|
||||
any.ghc-boot-th ==9.0.1,
|
||||
any.ghc-byteorder ==4.11.0.0.10,
|
||||
any.ghc-prim ==0.7.0,
|
||||
any.happy ==1.20.0,
|
||||
any.hashable ==1.3.3.0,
|
||||
hashable +integer-gmp -random-initial-seed,
|
||||
any.haskus-utils-data ==1.4,
|
||||
any.haskus-utils-types ==1.5.1,
|
||||
any.haskus-utils-variant ==3.1,
|
||||
any.hsc2hs ==0.68.7,
|
||||
hsc2hs -in-ghc-tree,
|
||||
any.hspec ==2.7.10,
|
||||
any.hspec-core ==2.7.10,
|
||||
any.hspec-discover ==2.7.10,
|
||||
any.hspec-expectations ==0.8.2,
|
||||
any.hspec-golden-aeson ==0.9.0.0,
|
||||
any.http-io-streams ==0.1.6.0,
|
||||
http-io-streams -brotli +fast-xor,
|
||||
any.indexed-profunctors ==0.1.1,
|
||||
any.indexed-traversable ==0.1.1,
|
||||
any.indexed-traversable-instances ==0.1,
|
||||
any.integer-logarithms ==1.0.3.1,
|
||||
integer-logarithms -check-bounds +integer-gmp,
|
||||
any.io-streams ==1.5.2.1,
|
||||
io-streams +network -nointeractivetests +zlib,
|
||||
any.language-c ==0.9.0.1,
|
||||
language-c -allwarnings +iecfpextension +usebytestrings,
|
||||
any.libarchive ==3.0.3.0,
|
||||
libarchive -cross -low-memory -system-libarchive,
|
||||
any.lzma-static ==5.2.5.4,
|
||||
any.megaparsec ==9.0.1,
|
||||
megaparsec -dev,
|
||||
any.microlens ==0.4.12.0,
|
||||
any.microlens-mtl ==0.2.0.1,
|
||||
any.microlens-th ==0.4.3.10,
|
||||
any.mtl ==2.2.2,
|
||||
any.network ==3.1.2.2,
|
||||
network -devel,
|
||||
any.network-uri ==2.6.4.1,
|
||||
any.openssl-streams ==1.2.3.0,
|
||||
any.optics ==0.4,
|
||||
any.optics-core ==0.4,
|
||||
optics-core -explicit-generic-labels,
|
||||
any.optics-extra ==0.4,
|
||||
any.optics-th ==0.4,
|
||||
any.optparse-applicative ==0.16.1.0,
|
||||
optparse-applicative +process,
|
||||
any.os-release ==1.0.2,
|
||||
os-release -devel,
|
||||
any.parallel ==3.2.2.0,
|
||||
any.parsec ==3.1.14.0,
|
||||
any.parser-combinators ==1.3.0,
|
||||
parser-combinators -dev,
|
||||
any.polyparse ==1.13,
|
||||
any.pretty ==1.1.3.6,
|
||||
any.pretty-terminal ==0.1.0.0,
|
||||
any.primitive ==0.7.2.0,
|
||||
any.process ==1.6.11.0,
|
||||
any.profunctors ==5.6.2,
|
||||
any.quickcheck-arbitrary-adt ==0.3.1.0,
|
||||
any.quickcheck-io ==0.2.0,
|
||||
any.random ==1.2.1,
|
||||
any.recursion-schemes ==5.2.2.1,
|
||||
recursion-schemes +template-haskell,
|
||||
any.regex-base ==0.94.0.1,
|
||||
any.regex-posix ==0.96.0.1,
|
||||
regex-posix -_regex-posix-clib,
|
||||
any.resourcet ==1.2.4.3,
|
||||
any.rts ==1.0,
|
||||
any.safe ==0.3.19,
|
||||
any.safe-exceptions ==0.1.7.2,
|
||||
any.scientific ==0.3.7.0,
|
||||
scientific -bytestring-builder -integer-simple,
|
||||
any.semigroupoids ==5.3.5,
|
||||
semigroupoids +comonad +containers +contravariant +distributive +tagged +unordered-containers,
|
||||
any.setenv ==0.1.1.3,
|
||||
any.split ==0.2.3.4,
|
||||
any.splitmix ==0.1.0.3,
|
||||
splitmix -optimised-mixer,
|
||||
any.stm ==2.5.0.0,
|
||||
any.strict ==0.4.0.1,
|
||||
strict +assoc,
|
||||
any.strict-base ==0.4.0.0,
|
||||
any.tagged ==0.8.6.1,
|
||||
tagged +deepseq +transformers,
|
||||
any.template-haskell ==2.17.0.0,
|
||||
any.temporary ==1.3,
|
||||
any.terminal-progress-bar ==0.4.1,
|
||||
any.terminal-size ==0.3.2.1,
|
||||
any.terminfo ==0.4.1.4,
|
||||
any.text ==1.2.4.1,
|
||||
any.text-zipper ==0.11,
|
||||
any.tf-random ==0.5,
|
||||
any.th-abstraction ==0.4.3.0,
|
||||
any.th-compat ==0.1.3,
|
||||
any.th-lift ==0.8.2,
|
||||
any.th-lift-instances ==0.1.18,
|
||||
any.these ==1.1.1.1,
|
||||
these +assoc,
|
||||
any.time ==1.9.3,
|
||||
any.time-compat ==1.9.6.1,
|
||||
time-compat -old-locale,
|
||||
any.transformers ==0.5.6.2,
|
||||
any.transformers-base ==0.4.6,
|
||||
transformers-base +orphaninstances,
|
||||
any.transformers-compat ==0.7,
|
||||
transformers-compat -five +five-three -four +generic-deriving +mtl -three -two,
|
||||
any.unix ==2.7.2.2,
|
||||
any.unix-bytestring ==0.3.7.3,
|
||||
any.unix-compat ==0.5.3,
|
||||
unix-compat -old-time,
|
||||
any.unliftio-core ==0.2.0.1,
|
||||
any.unordered-containers ==0.2.14.0,
|
||||
unordered-containers -debug,
|
||||
any.uri-bytestring ==0.3.3.1,
|
||||
uri-bytestring -lib-werror,
|
||||
any.utf8-string ==1.0.2,
|
||||
any.uuid-types ==1.0.5,
|
||||
any.vector ==0.12.3.1,
|
||||
vector +boundschecks -internalchecks -unsafechecks -wall,
|
||||
any.versions ==5.0.0,
|
||||
any.vty ==5.33,
|
||||
any.word-wrap ==0.5,
|
||||
any.word8 ==0.1.3,
|
||||
any.xor ==0.0.1.0,
|
||||
any.zlib ==0.6.2.3,
|
||||
zlib -bundled-c-zlib -non-blocking-ffi -pkg-config,
|
||||
any.zlib-bindings ==0.1.1.5
|
||||
index-state: hackage.haskell.org 2021-10-01T15:16:26Z
|
||||
@@ -1,24 +1,24 @@
|
||||
packages: ./ghcup.cabal
|
||||
|
||||
optional-packages: ./vendored/*/*.cabal
|
||||
|
||||
optimization: 2
|
||||
|
||||
package ghcup
|
||||
tests: True
|
||||
flags: +tui
|
||||
|
||||
source-repository-package
|
||||
type: git
|
||||
location: https://github.com/Bodigrim/tar
|
||||
tag: ac197ec7ea4838dc2b4e22b9b888b080cedf29cf
|
||||
constraints: http-io-streams -brotli,
|
||||
any.Cabal ==3.4.0.0 || ==3.6.2.0
|
||||
|
||||
source-repository-package
|
||||
type: git
|
||||
location: https://github.com/bgamari/terminal-size
|
||||
tag: 34ea816bd63f75f800eedac12c6908c6f3736036
|
||||
|
||||
constraints: http-io-streams -brotli
|
||||
|
||||
package libarchive
|
||||
flags: -system-libarchive
|
||||
|
||||
package aeson-pretty
|
||||
flags: +lib-only
|
||||
|
||||
package cabal-plan
|
||||
flags: -exe
|
||||
|
||||
allow-newer: base, ghc-prim, template-haskell, language-c
|
||||
|
||||
9
data/build_mk/cross
Normal file
@@ -0,0 +1,9 @@
|
||||
V=0
|
||||
BUILD_MAN = NO
|
||||
BUILD_SPHINX_HTML = NO
|
||||
BUILD_SPHINX_PDF = NO
|
||||
HADDOCK_DOCS = NO
|
||||
ifneq "$(BuildFlavour)" ""
|
||||
include mk/flavours/$(BuildFlavour).mk
|
||||
endif
|
||||
Stage1Only = YES
|
||||
8
data/build_mk/default
Normal file
@@ -0,0 +1,8 @@
|
||||
V=0
|
||||
BUILD_MAN = NO
|
||||
BUILD_SPHINX_HTML = NO
|
||||
BUILD_SPHINX_PDF = NO
|
||||
HADDOCK_DOCS = YES
|
||||
ifneq "$(BuildFlavour)" ""
|
||||
include mk/flavours/$(BuildFlavour).mk
|
||||
endif
|
||||
@@ -8,6 +8,10 @@ verbose: False
|
||||
keep-dirs: Errors # Always | Never | Errors
|
||||
# Which downloader to use
|
||||
downloader: Curl # Curl | Wget | Internal
|
||||
# whether to run in offline mode
|
||||
no-network: False
|
||||
# whether/how to do gpg verification
|
||||
gpg-setting: GPGNone # GPGStrict | GPGLax | GPGNone
|
||||
|
||||
# TUI key bindings,
|
||||
# see https://hackage.haskell.org/package/vty-5.31/docs/Graphics-Vty-Input-Events.html#t:Key
|
||||
2179
data/metadata/ghcup-0.0.1.json
Normal file
2729
data/metadata/ghcup-0.0.2.json
Normal file
@@ -1384,7 +1384,7 @@ ghcupDownloads:
|
||||
dlUri: https://oleg.fi/cabal-install-3.4.0.0-rc4/cabal-install-3.4.0.0-x86_64-freebsd-12.1-release.tar.xz
|
||||
dlHash: 9705e16d03497b46be4ad477e6c64d10890af853eafa8a9adf6dba89aa9e05f7
|
||||
GHCup:
|
||||
0.1.14:
|
||||
0.1.16.2:
|
||||
viTags:
|
||||
- Recommended
|
||||
- Latest
|
||||
@@ -1394,22 +1394,22 @@ ghcupDownloads:
|
||||
A_64:
|
||||
Linux_UnknownLinux:
|
||||
unknown_versioning: &ghcup-64
|
||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.14/x86_64-linux-ghcup-0.1.14
|
||||
dlHash: e9b314d248f4d4604ce64cee1be7161c77c8940efd11986c9205779ec3b598dd
|
||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.16.2/x86_64-linux-ghcup-0.1.16.2
|
||||
dlHash: d5e43b95ce1d42263376e414f7eb7c5dd440271c7c6cd9bad446fdeff3823893
|
||||
Darwin:
|
||||
unknown_versioning:
|
||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.14/x86_64-apple-darwin-ghcup-0.1.14
|
||||
dlHash: 69ede9db36c0ae631b679fceb87dd856d4753ee26f33610da37dd7a694809919
|
||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.16.2/x86_64-apple-darwin-ghcup-0.1.16.2
|
||||
dlHash: a334620ccce7705211b2142882dde544003e6030af4b91a44c890542a90f879f
|
||||
FreeBSD:
|
||||
unknown_versioning:
|
||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.14/x86_64-portbld-freebsd-ghcup-0.1.14
|
||||
dlHash: 68b09404cf49061da539463f42f8ad67c9cef5c5d3f68a3c7c4f6760e8442bb9
|
||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.16.2/x86_64-portbld-freebsd-ghcup-0.1.16.2
|
||||
dlHash: 92359592a5694375e53b22628920086bf4bbf0faff5be018a0ed3e745a6426a9
|
||||
Linux_Alpine:
|
||||
unknown_versioning: *ghcup-64
|
||||
A_32:
|
||||
Linux_UnknownLinux:
|
||||
unknown_versioning: &ghcup-32
|
||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.14/i386-linux-ghcup-0.1.14
|
||||
dlHash: ecb1157f010d2421764c52ab0cdbbf9a5c3da555827172c7b904d5f3f96c80fa
|
||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.16.2/i386-linux-ghcup-0.1.16.2
|
||||
dlHash: 01968ca6decac7b6e8ba6e2c817870d3fa47289a6507e0c1ab563f7b6eec0e38
|
||||
Linux_Alpine:
|
||||
unknown_versioning: *ghcup-32
|
||||
@@ -1451,7 +1451,7 @@ ghcupDownloads:
|
||||
dlUri: https://oleg.fi/cabal-install-3.4.0.0-rc4/cabal-install-3.4.0.0-x86_64-freebsd-12.1-release.tar.xz
|
||||
dlHash: 9705e16d03497b46be4ad477e6c64d10890af853eafa8a9adf6dba89aa9e05f7
|
||||
GHCup:
|
||||
0.1.14:
|
||||
0.1.16.2:
|
||||
viTags:
|
||||
- Recommended
|
||||
- Latest
|
||||
@@ -1461,23 +1461,23 @@ ghcupDownloads:
|
||||
A_64:
|
||||
Linux_UnknownLinux:
|
||||
unknown_versioning: &ghcup-64
|
||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.14/x86_64-linux-ghcup-0.1.14
|
||||
dlHash: e9b314d248f4d4604ce64cee1be7161c77c8940efd11986c9205779ec3b598dd
|
||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.16.2/x86_64-linux-ghcup-0.1.16.2
|
||||
dlHash: d5e43b95ce1d42263376e414f7eb7c5dd440271c7c6cd9bad446fdeff3823893
|
||||
Darwin:
|
||||
unknown_versioning:
|
||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.14/x86_64-apple-darwin-ghcup-0.1.14
|
||||
dlHash: 69ede9db36c0ae631b679fceb87dd856d4753ee26f33610da37dd7a694809919
|
||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.16.2/x86_64-apple-darwin-ghcup-0.1.16.2
|
||||
dlHash: a334620ccce7705211b2142882dde544003e6030af4b91a44c890542a90f879f
|
||||
FreeBSD:
|
||||
unknown_versioning:
|
||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.14/x86_64-portbld-freebsd-ghcup-0.1.14
|
||||
dlHash: 68b09404cf49061da539463f42f8ad67c9cef5c5d3f68a3c7c4f6760e8442bb9
|
||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.16.2/x86_64-portbld-freebsd-ghcup-0.1.16.2
|
||||
dlHash: 92359592a5694375e53b22628920086bf4bbf0faff5be018a0ed3e745a6426a9
|
||||
Linux_Alpine:
|
||||
unknown_versioning: *ghcup-64
|
||||
A_32:
|
||||
Linux_UnknownLinux:
|
||||
unknown_versioning: &ghcup-32
|
||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.14/i386-linux-ghcup-0.1.14
|
||||
dlHash: ecb1157f010d2421764c52ab0cdbbf9a5c3da555827172c7b904d5f3f96c80fa
|
||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.16.2/i386-linux-ghcup-0.1.16.2
|
||||
dlHash: 01968ca6decac7b6e8ba6e2c817870d3fa47289a6507e0c1ab563f7b6eec0e38
|
||||
Linux_Alpine:
|
||||
unknown_versioning: *ghcup-32
|
||||
HLS:
|
||||
@@ -1868,7 +1868,7 @@ ghcupDownloads:
|
||||
dlUri: https://downloads.haskell.org/~ghcup/unofficial-bindists/cabal/3.4.0.0/cabal-install-3.4.0.0-armv7-linux-bootstrapped.tar.xz
|
||||
dlHash: 16c0d1eaba24bed14f3e152970179a45d9f9bb5cc839b2c210ad06eb7d4826ed
|
||||
GHCup:
|
||||
0.1.15.1:
|
||||
0.1.16.2:
|
||||
viTags:
|
||||
- Recommended
|
||||
- Latest
|
||||
@@ -1878,39 +1878,39 @@ ghcupDownloads:
|
||||
A_64:
|
||||
Linux_UnknownLinux:
|
||||
unknown_versioning: &ghcup-64
|
||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.15.1/x86_64-linux-ghcup-0.1.15.1
|
||||
dlHash: 871c9dc1bfbf7df6fe3b9b7250c20a3dae8a7aee171712a3e63689ab75bc9439
|
||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.16.2/x86_64-linux-ghcup-0.1.16.2
|
||||
dlHash: d5e43b95ce1d42263376e414f7eb7c5dd440271c7c6cd9bad446fdeff3823893
|
||||
Darwin:
|
||||
unknown_versioning:
|
||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.15.1/x86_64-apple-darwin-ghcup-0.1.15.1
|
||||
dlHash: 7cd67b554fc58c4ffb224b73e369c5dd27c5276c01f102f6423230b34cc635bc
|
||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.16.2/x86_64-apple-darwin-ghcup-0.1.16.2
|
||||
dlHash: a334620ccce7705211b2142882dde544003e6030af4b91a44c890542a90f879f
|
||||
FreeBSD:
|
||||
unknown_versioning:
|
||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.15.1/x86_64-portbld-freebsd-ghcup-0.1.15.1
|
||||
dlHash: b4ad9c9f1a878560e8f770d985d53b8fb70582baf99e40e53ec9ee97dc47ae64
|
||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.16.2/x86_64-portbld-freebsd-ghcup-0.1.16.2
|
||||
dlHash: 92359592a5694375e53b22628920086bf4bbf0faff5be018a0ed3e745a6426a9
|
||||
Linux_Alpine:
|
||||
unknown_versioning: *ghcup-64
|
||||
A_32:
|
||||
Linux_UnknownLinux:
|
||||
unknown_versioning: &ghcup-32
|
||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.15.1/i386-linux-ghcup-0.1.15.1
|
||||
dlHash: 0c1dcbdd7cfa8accdfbe14c623924f3ca29a35d32a2ac3e61f0eb322855e2cb1
|
||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.16.2/i386-linux-ghcup-0.1.16.2
|
||||
dlHash: 01968ca6decac7b6e8ba6e2c817870d3fa47289a6507e0c1ab563f7b6eec0e38
|
||||
Linux_Alpine:
|
||||
unknown_versioning: *ghcup-32
|
||||
A_ARM64:
|
||||
Linux_UnknownLinux:
|
||||
unknown_versioning:
|
||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.15.1/aarch64-linux-ghcup-0.1.15.1
|
||||
dlHash: 7fa29d8e9a9fe3d1e3a63a1d16fc3550128edbdb9b5b5dff7974358c4dab192c
|
||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.16.2/aarch64-linux-ghcup-0.1.16.2
|
||||
dlHash: 0bdbfc724e0ddabb266156eea83c2c4e19c6ed79dd06db0c29b7d69df8d9fa8c
|
||||
Darwin:
|
||||
unknown_versioning:
|
||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.15.1/aarch64-apple-darwin-ghcup-0.1.15.1
|
||||
dlHash: 6a743cd50e8124ac2de8be77013d49dcf3b99ce7cc463ec86ed99a904a51dfd9
|
||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.16.2/aarch64-apple-darwin-ghcup-0.1.16.2
|
||||
dlHash: 8854e991a2ba1350abda59dab96ce50ae7729d1ce99399d67929ef31e90f1da5
|
||||
A_ARM:
|
||||
Linux_UnknownLinux:
|
||||
unknown_versioning:
|
||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.15.1/armv7-linux-ghcup-0.1.15.1
|
||||
dlHash: 77ee5d9828c2ba771127274e301e81412b9f29af2d65dd85dada4786d9438c2c
|
||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.16.2/armv7-linux-ghcup-0.1.16.2
|
||||
dlHash: 983ebb5b584bfa600704216a63f94b40d36a02573834e90ef1042c8472d9ad57
|
||||
HLS:
|
||||
1.1.0:
|
||||
viTags:
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
globalTools:
|
||||
ShimGen:
|
||||
dlUri: https://downloads.haskell.org/~ghcup/shimgen/gs.exe
|
||||
dlHash: 9ce8b7dad7ff4e5017dbd63d6f6f3d16412b889560cb6ccd3903dbcab0bf4f0d
|
||||
dlUri: https://downloads.haskell.org/~ghcup/shimgen/shim-2.exe
|
||||
dlHash: 7c55e201f71860c5babea886007c8fa44b861abf50d1c07e5677eb0bda387a70
|
||||
toolRequirements:
|
||||
GHC:
|
||||
unknown_version:
|
||||
@@ -96,6 +96,7 @@ toolRequirements:
|
||||
Linux_Alpine:
|
||||
unknown_versioning:
|
||||
distroPKGs:
|
||||
- binutils-gold
|
||||
- curl
|
||||
- gcc
|
||||
- g++
|
||||
@@ -2024,7 +2025,7 @@ ghcupDownloads:
|
||||
dlUri: https://downloads.haskell.org/~ghcup/unofficial-bindists/cabal/3.4.0.0/cabal-install-3.4.0.0-armv7-linux-bootstrapped.tar.xz
|
||||
dlHash: 16c0d1eaba24bed14f3e152970179a45d9f9bb5cc839b2c210ad06eb7d4826ed
|
||||
GHCup:
|
||||
0.1.15.1:
|
||||
0.1.16.2:
|
||||
viTags:
|
||||
- Recommended
|
||||
- Latest
|
||||
@@ -2034,54 +2035,55 @@ ghcupDownloads:
|
||||
A_64:
|
||||
Linux_UnknownLinux:
|
||||
unknown_versioning: &ghcup-64
|
||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.15.1/x86_64-linux-ghcup-0.1.15.1
|
||||
dlHash: 871c9dc1bfbf7df6fe3b9b7250c20a3dae8a7aee171712a3e63689ab75bc9439
|
||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.16.2/x86_64-linux-ghcup-0.1.16.2
|
||||
dlHash: d5e43b95ce1d42263376e414f7eb7c5dd440271c7c6cd9bad446fdeff3823893
|
||||
Darwin:
|
||||
unknown_versioning:
|
||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.15.1/x86_64-apple-darwin-ghcup-0.1.15.1
|
||||
dlHash: 7cd67b554fc58c4ffb224b73e369c5dd27c5276c01f102f6423230b34cc635bc
|
||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.16.2/x86_64-apple-darwin-ghcup-0.1.16.2
|
||||
dlHash: a334620ccce7705211b2142882dde544003e6030af4b91a44c890542a90f879f
|
||||
FreeBSD:
|
||||
unknown_versioning:
|
||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.15.1/x86_64-portbld-freebsd-ghcup-0.1.15.1
|
||||
dlHash: b4ad9c9f1a878560e8f770d985d53b8fb70582baf99e40e53ec9ee97dc47ae64
|
||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.16.2/x86_64-portbld-freebsd-ghcup-0.1.16.2
|
||||
dlHash: 92359592a5694375e53b22628920086bf4bbf0faff5be018a0ed3e745a6426a9
|
||||
Windows:
|
||||
unknown_versioning:
|
||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.15.1/x86_64-mingw64-ghcup-0.1.15.1.exe
|
||||
dlHash: 045bac4620fc9d1119ed4961aeba46b616ed572dd11b7d35b48caf58eea08d0f
|
||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.16.2/x86_64-mingw64-ghcup-0.1.16.2.exe
|
||||
dlHash: ec78872a84213968c490675127b9aad2285980b747c68207801ae824b98c7948
|
||||
Linux_Alpine:
|
||||
unknown_versioning: *ghcup-64
|
||||
A_32:
|
||||
Linux_UnknownLinux:
|
||||
unknown_versioning: &ghcup-32
|
||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.15.1/i386-linux-ghcup-0.1.15.1
|
||||
dlHash: 0c1dcbdd7cfa8accdfbe14c623924f3ca29a35d32a2ac3e61f0eb322855e2cb1
|
||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.16.2/i386-linux-ghcup-0.1.16.2
|
||||
dlHash: 01968ca6decac7b6e8ba6e2c817870d3fa47289a6507e0c1ab563f7b6eec0e38
|
||||
Linux_Alpine:
|
||||
unknown_versioning: *ghcup-32
|
||||
A_ARM64:
|
||||
Linux_UnknownLinux:
|
||||
unknown_versioning:
|
||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.15.1/aarch64-linux-ghcup-0.1.15.1
|
||||
dlHash: 7fa29d8e9a9fe3d1e3a63a1d16fc3550128edbdb9b5b5dff7974358c4dab192c
|
||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.16.2/aarch64-linux-ghcup-0.1.16.2
|
||||
dlHash: 0bdbfc724e0ddabb266156eea83c2c4e19c6ed79dd06db0c29b7d69df8d9fa8c
|
||||
Darwin:
|
||||
unknown_versioning:
|
||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.15.1/aarch64-apple-darwin-ghcup-0.1.15.1
|
||||
dlHash: 6a743cd50e8124ac2de8be77013d49dcf3b99ce7cc463ec86ed99a904a51dfd9
|
||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.16.2/aarch64-apple-darwin-ghcup-0.1.16.2
|
||||
dlHash: 8854e991a2ba1350abda59dab96ce50ae7729d1ce99399d67929ef31e90f1da5
|
||||
A_ARM:
|
||||
Linux_UnknownLinux:
|
||||
unknown_versioning:
|
||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.15.1/armv7-linux-ghcup-0.1.15.1
|
||||
dlHash: 77ee5d9828c2ba771127274e301e81412b9f29af2d65dd85dada4786d9438c2c
|
||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.16.2/armv7-linux-ghcup-0.1.16.2
|
||||
dlHash: 983ebb5b584bfa600704216a63f94b40d36a02573834e90ef1042c8472d9ad57
|
||||
HLS:
|
||||
1.1.0:
|
||||
viTags:
|
||||
- Recommended
|
||||
- Latest
|
||||
viTags: []
|
||||
viChangeLog: https://github.com/haskell/haskell-language-server/blob/master/ChangeLog.md#110
|
||||
viPostInstall: "This is just the server part of your LSP configuration. Consult the README on how to configure HLS, your project and your LSP client in your editor: https://github.com/haskell/haskell-language-server/blob/master/README.md"
|
||||
viPostInstall: &hls-post-install |
|
||||
This is just the server part of your LSP configuration. Consult the README on how to
|
||||
configure HLS, your project and your LSP client in your editor:
|
||||
https://github.com/haskell/haskell-language-server/blob/master/README.md
|
||||
viArch:
|
||||
A_64:
|
||||
Linux_UnknownLinux:
|
||||
unknown_versioning: &hls-64
|
||||
unknown_versioning: &hls-110-64
|
||||
dlUri: https://github.com/haskell/haskell-language-server/releases/download/1.1.0/haskell-language-server-Linux-1.1.0.tar.gz
|
||||
dlHash: 0f0dadb0e9a08273658f565fd71c636801959b954be2737f38f2a1aac522208f
|
||||
Darwin:
|
||||
@@ -2093,15 +2095,66 @@ ghcupDownloads:
|
||||
dlUri: https://downloads.haskell.org/ghcup/unofficial-bindists/hls/1.1.0/haskell-language-server-Windows-1.1.0.tar.gz
|
||||
dlHash: a1d3f451e64a041aa527a25da29e4716a2de6ae347cef4ef9312fc7611e168cc
|
||||
Linux_Alpine:
|
||||
unknown_versioning: *hls-64
|
||||
unknown_versioning: *hls-110-64
|
||||
1.2.0:
|
||||
viTags: []
|
||||
viChangeLog: https://github.com/haskell/haskell-language-server/blob/master/ChangeLog.md#120
|
||||
viPostInstall: *hls-post-install
|
||||
viArch:
|
||||
A_64:
|
||||
Linux_UnknownLinux:
|
||||
unknown_versioning: &hls-120-64
|
||||
dlUri: https://github.com/haskell/haskell-language-server/releases/download/1.2.0/haskell-language-server-Linux-1.2.0.tar.gz
|
||||
dlHash: d29ee22f7bd706da2e2a1bd7640e25bb9736adeafb34eef47d29ea143b0fa927
|
||||
Darwin:
|
||||
unknown_versioning:
|
||||
dlUri: https://github.com/haskell/haskell-language-server/releases/download/1.2.0/haskell-language-server-macOS-1.2.0.tar.gz
|
||||
dlHash: a310d8a3e9c5c4218210f750682c74a0f82ad0f59995adde0dbe775115b1e357
|
||||
Windows:
|
||||
unknown_versioning:
|
||||
dlUri: https://github.com/haskell/haskell-language-server/releases/download/1.2.0/haskell-language-server-Windows-1.2.0.tar.gz
|
||||
dlHash: 961c6ff12c9a9c7a4609f239c5ac70d7d16753cdb8c10348a6a51feeaa0b6aea
|
||||
Linux_Alpine:
|
||||
unknown_versioning: *hls-120-64
|
||||
1.3.0:
|
||||
viTags:
|
||||
- Recommended
|
||||
- Latest
|
||||
viChangeLog: https://github.com/haskell/haskell-language-server/blob/master/ChangeLog.md#130
|
||||
viPostInstall: *hls-post-install
|
||||
viArch:
|
||||
A_64:
|
||||
Linux_UnknownLinux:
|
||||
unknown_versioning: &hls-130-64
|
||||
dlUri: https://github.com/haskell/haskell-language-server/releases/download/1.3.0/haskell-language-server-Linux-1.3.0.tar.gz
|
||||
dlHash: d29ee22f7bd706da2e2a1bd7640e25bb9736adeafb34eef47d29ea143b0fa927
|
||||
Darwin:
|
||||
unknown_versioning:
|
||||
dlUri: https://github.com/haskell/haskell-language-server/releases/download/1.3.0/haskell-language-server-macOS-1.3.0.tar.gz
|
||||
dlHash: a310d8a3e9c5c4218210f750682c74a0f82ad0f59995adde0dbe775115b1e357
|
||||
Windows:
|
||||
unknown_versioning:
|
||||
dlUri: https://github.com/haskell/haskell-language-server/releases/download/1.3.0/haskell-language-server-Windows-1.3.0.tar.gz
|
||||
dlHash: 961c6ff12c9a9c7a4609f239c5ac70d7d16753cdb8c10348a6a51feeaa0b6aea
|
||||
Linux_Alpine:
|
||||
unknown_versioning: *hls-130-64
|
||||
Stack:
|
||||
2.5.1:
|
||||
viTags:
|
||||
- old
|
||||
viChangeLog: https://github.com/commercialhaskell/stack/blob/master/ChangeLog.md#v251
|
||||
viPostInstall: &stack-post |
|
||||
Stack manages GHC versions internally by default. In order to make it use ghcup installed GHC versions have a look at the options 'system-ghc', 'compiler-check' and 'compiler': https://docs.haskellstack.org/en/stable/yaml_configuration/#system-ghc
|
||||
Additionally, you should upgrade stack only through ghcup.
|
||||
Stack manages GHC versions internally by default. In order to make it use ghcup installed
|
||||
GHC versions you can run the following commands:
|
||||
stack config set install-ghc false --global
|
||||
stack config set system-ghc true --global
|
||||
|
||||
On windows, you may find the following config options useful too:
|
||||
skip-msys, extra-path, extra-include-dirs, extra-lib-dirs
|
||||
|
||||
Also check out: https://docs.haskellstack.org/en/stable/yaml_configuration
|
||||
|
||||
!!! Additionally, you should upgrade stack only through ghcup and not use 'stack upgrade' !!!
|
||||
viArch:
|
||||
A_64:
|
||||
Linux_UnknownLinux:
|
||||
@@ -2126,14 +2179,13 @@ ghcupDownloads:
|
||||
unknown_versioning: *stack-251-64
|
||||
2.7.1:
|
||||
viTags:
|
||||
- Recommended
|
||||
- Latest
|
||||
- old
|
||||
viChangeLog: https://github.com/commercialhaskell/stack/blob/master/ChangeLog.md#v271
|
||||
viPostInstall: *stack-post
|
||||
viArch:
|
||||
A_64:
|
||||
Linux_UnknownLinux:
|
||||
unknown_versioning: &stack-64
|
||||
unknown_versioning: &stack-271-64
|
||||
dlUri: https://github.com/commercialhaskell/stack/releases/download/v2.7.1/stack-2.7.1-linux-x86_64.tar.gz
|
||||
dlHash: 2bc47749ee4be5eccb52a2d4a6a00b0f3b28b92517742b40c675836d7db2777d
|
||||
dlSubdir:
|
||||
@@ -2151,5 +2203,33 @@ ghcupDownloads:
|
||||
dlSubdir:
|
||||
RegexDir: "stack-.*"
|
||||
Linux_Alpine:
|
||||
unknown_versioning: *stack-64
|
||||
unknown_versioning: *stack-271-64
|
||||
2.7.3:
|
||||
viTags:
|
||||
- Latest
|
||||
- Recommended
|
||||
viChangeLog: https://github.com/commercialhaskell/stack/blob/master/ChangeLog.md#v273
|
||||
viPostInstall: *stack-post
|
||||
viArch:
|
||||
A_64:
|
||||
Linux_UnknownLinux:
|
||||
unknown_versioning: &stack-273-64
|
||||
dlUri: https://github.com/commercialhaskell/stack/releases/download/v2.7.3/stack-2.7.3-linux-x86_64.tar.gz
|
||||
dlHash: a6c090555fa1c64aa61c29aa4449765a51d79e870cf759cde192937cd614e72b
|
||||
dlSubdir:
|
||||
RegexDir: "stack-.*"
|
||||
Darwin:
|
||||
unknown_versioning:
|
||||
dlUri: https://github.com/commercialhaskell/stack/releases/download/v2.7.3/stack-2.7.3-osx-x86_64.tar.gz
|
||||
dlHash: 42e5000a00af44a7b26852421ac63ce75f510ad1a97742cb131107088ee9fe30
|
||||
dlSubdir:
|
||||
RegexDir: "stack-.*"
|
||||
Windows:
|
||||
unknown_versioning:
|
||||
dlUri: https://github.com/commercialhaskell/stack/releases/download/v2.7.3/stack-2.7.3-windows-x86_64.tar.gz
|
||||
dlHash: e6ba12e0ecabf0df2567d88a0d247da238bc114bcccfca4195f5e86472c9330c
|
||||
dlSubdir:
|
||||
RegexDir: "stack-.*"
|
||||
Linux_Alpine:
|
||||
unknown_versioning: *stack-273-64
|
||||
|
||||
2643
data/metadata/ghcup-0.0.6.yaml
Normal file
1
docs/BUGS.md
Normal file
@@ -0,0 +1 @@
|
||||
# Known BUGS
|
||||
216
docs/about.md
Normal file
@@ -0,0 +1,216 @@
|
||||
# About
|
||||
|
||||
All you wanted to know about GHCup.
|
||||
|
||||
## Team
|
||||
|
||||
### Author and Maintainer
|
||||
|
||||
* [Julian Ospald](https://github.com/hasufell) (aka: maerwald, hasufell)
|
||||
|
||||
### Collaborators
|
||||
|
||||
* [Arjun Kathuria](https://github.com/arjunkathuria)
|
||||
* [Ben Gamari](https://github.com/bgamari)
|
||||
* [Javier Neira](https://github.com/jneira)
|
||||
|
||||
### Contributors
|
||||
|
||||
* amesgen
|
||||
* Chris Smith
|
||||
* Anton-Latukha
|
||||
* Brian McKenna
|
||||
* Huw campbell
|
||||
* Tom Ellis
|
||||
* Sigmund Vestergaard
|
||||
* Ron Toland
|
||||
* Paolo Martini
|
||||
* Mario Lang
|
||||
* Jan Hrček
|
||||
* vglfr
|
||||
* Fendor
|
||||
* Enrico Maria De Angelis
|
||||
* Emily Pillmore
|
||||
* Colin Barrett
|
||||
* Artur Gajowy
|
||||
|
||||
### Sponsors
|
||||
|
||||
* All [opencollective](https://opencollective.com/ghcup#category-CONTRIBUTE) contributors
|
||||
* [haskell.org](https://www.haskell.org/haskell-org-committee/) via CI and infrastructure
|
||||
* [Haskell Foundation](https://haskell.foundation/affiliates/) via affiliation
|
||||
|
||||
## Design goals
|
||||
|
||||
1. simplicity
|
||||
2. non-interactive CLI interface
|
||||
3. portable
|
||||
4. do one thing and do it well (UNIX philosophy)
|
||||
|
||||
## Non-goals
|
||||
|
||||
1. invoking `sudo`, `apt-get` or *any* package manager
|
||||
2. handling system packages
|
||||
3. handling cabal projects
|
||||
4. being a stack alternative
|
||||
|
||||
## How
|
||||
|
||||
Installs a specified GHC version into `~/.ghcup/ghc/<ver>`, and places `ghc-<ver>` symlinks in `~/.ghcup/bin/`.
|
||||
|
||||
Optionally, an unversioned `ghc` link can point to a default version of your choice.
|
||||
|
||||
This uses precompiled GHC binaries that have been compiled on fedora/debian by [upstream GHC](https://www.haskell.org/ghc/download_ghc_8_6_1.html#binaries).
|
||||
|
||||
Alternatively, you can also tell it to compile from source (note that this might fail due to missing requirements).
|
||||
|
||||
cabal-install/HLS/stack are installed in `~/.ghcup/bin/<tool>-<ver>` and have unversioned symlinks to the latest version by default (`~/.ghcup/bin/<tool>-<ver>`).
|
||||
|
||||
## Known users
|
||||
|
||||
* Github actions:
|
||||
- [actions/virtual-environments](https://github.com/actions/virtual-environments)
|
||||
- [haskell/actions/setup](https://github.com/haskell/actions/tree/main/setup)
|
||||
* mirrors:
|
||||
- [sjtug](https://mirror.sjtu.edu.cn/docs/ghcup)
|
||||
* tools:
|
||||
- [vabal](https://github.com/Franciman/vabal)
|
||||
|
||||
## Known problems
|
||||
|
||||
### Custom ghc version names
|
||||
|
||||
When installing ghc bindists with custom version names as outlined in
|
||||
[installing custom bindists](#installing-custom-bindists), then cabal might
|
||||
be unable to find the correct `ghc-pkg` (also see [#73](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/73))
|
||||
if you use `cabal build --with-compiler=ghc-foo`. Instead, point it to the full path, such as:
|
||||
`cabal build --with-compiler=$HOME/.ghcup/ghc/<version-name>/bin/ghc` or set that GHC version
|
||||
as the current one via: `ghcup set ghc <version-name>`.
|
||||
|
||||
This problem doesn't exist for regularly installed GHC versions.
|
||||
|
||||
### Limited distributions supported
|
||||
|
||||
Currently only GNU/Linux distributions compatible with the [upstream GHC](https://www.haskell.org/ghc/download_ghc_8_6_1.html#binaries) binaries are supported.
|
||||
|
||||
### Precompiled binaries
|
||||
|
||||
Since this uses precompiled binaries you may run into
|
||||
several problems.
|
||||
|
||||
#### Missing libtinfo (ncurses)
|
||||
|
||||
You may run into problems with *ncurses* and **missing libtinfo**, in case
|
||||
your distribution doesn't use the legacy way of building
|
||||
ncurses and has no compatibility symlinks in place.
|
||||
|
||||
Ask your distributor on how to solve this or
|
||||
try to compile from source via `ghcup compile <version>`.
|
||||
|
||||
#### Libnuma required
|
||||
|
||||
This was a [bug](https://ghc.haskell.org/trac/ghc/ticket/15688) in the build system of some GHC versions that lead to
|
||||
unconditionally enabled libnuma support. To mitigate this you might have to install the libnuma
|
||||
package of your distribution. See [here](https://gitlab.haskell.org/haskell/ghcup/issues/58) for a discussion.
|
||||
|
||||
### Compilation
|
||||
|
||||
Although this script can compile GHC for you, it's just a very thin
|
||||
wrapper around the build system. It makes no effort in trying
|
||||
to figure out whether you have the correct toolchain and
|
||||
the correct dependencies. Refer to [the official docs](https://ghc.haskell.org/trac/ghc/wiki/Building/Preparation/Linux)
|
||||
on how to prepare your environment for building GHC.
|
||||
|
||||
### Stack support
|
||||
|
||||
There may be a number of bugs when trying to make ghcup installed GHC versions work with stack,
|
||||
such as:
|
||||
|
||||
- https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/188
|
||||
|
||||
Further, stack's upgrade procedure may break/confuse ghcup. There are a number of integration
|
||||
issues discussed here:
|
||||
|
||||
- https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/153
|
||||
|
||||
### Windows support
|
||||
|
||||
Windows support is in early stages. Since windows doesn't support symbolic links properly,
|
||||
ghcup uses a [shimgen wrapper](https://github.com/71/scoop-better-shimexe). It seems to work
|
||||
well, but there may be unknown issues with that approach.
|
||||
|
||||
Windows 7 and Powershell 2.0 aren't well supported at the moment, also see:
|
||||
|
||||
- https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/140
|
||||
- https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/197
|
||||
|
||||
## FAQ
|
||||
|
||||
### Why reimplement stack?
|
||||
|
||||
GHCup is not a reimplementation of stack. The only common part is automatic installation of GHC,
|
||||
but even that differs in scope and design.
|
||||
|
||||
### Why should I use ghcup over stack?
|
||||
|
||||
GHCup is not a replacement for stack. Instead, it supports installing and managing stack versions.
|
||||
It does the same for cabal, GHC and HLS. As such, It doesn't make a workflow choice for you.
|
||||
|
||||
### Why should I let ghcup manage stack?
|
||||
|
||||
You don't need to. However, some users seem to prefer to have a central tool that manages cabal and stack
|
||||
at the same time. Additionally, it can allow better sharing of GHC installation across these tools.
|
||||
Also see:
|
||||
|
||||
* https://docs.haskellstack.org/en/stable/yaml_configuration/#system-ghc
|
||||
* https://github.com/commercialhaskell/stack/pull/5585
|
||||
|
||||
### Why does ghcup not use stack code?
|
||||
|
||||
1. GHCup started as a shell script. At the time of rewriting it in Haskell, the authors didn't even know that stack exposes *some* of its [installation API](https://hackage.haskell.org/package/stack-2.5.1.1/docs/Stack-Setup.html)
|
||||
2. it doesn't support cabal installation, which was the main motivation behind GHCup back then
|
||||
3. depending on a codebase as big as stack for a central part of one's application without having a short contribution pipeline would likely have caused stagnation or resulted in simply copy-pasting the relevant code in order to adjust it
|
||||
4. it's not clear how GHCup would have been implemented with the provided API. It seems the codebases are fairly different. GHCup does a lot of symlink handling to expose a central `bin/` directory that users can easily put in PATH, without having to worry about anything more. It also provides explicit removal functionality, GHC cross-compilation, a TUI, etc etc.
|
||||
|
||||
### Why not unify...
|
||||
|
||||
#### ...stack and Cabal and do away with standalone installers
|
||||
|
||||
GHCup is not involved in such decisions. cabal-install and stack might have a
|
||||
sufficiently different user experience to warrant having a choice.
|
||||
|
||||
#### ...installer implementations and have a common library
|
||||
|
||||
This sounds like an interesting goal. However, GHC installation isn't a hard engineering problem
|
||||
and the shared code wouldn't be too exciting. For such an effort to make sense, all involved
|
||||
parties would need to collaborate and have a short pipeline to get patches in.
|
||||
|
||||
It's true this would solve the integration problem, but following unix principles, we can
|
||||
do similar via **hooks**. Both cabal and stack can support installation hooks. These hooks
|
||||
can then call into ghcup or anything else, also see:
|
||||
|
||||
* https://github.com/haskell/cabal/issues/7394
|
||||
* https://github.com/commercialhaskell/stack/pull/5585
|
||||
|
||||
#### ...installers (like, all of it)
|
||||
|
||||
So far, there hasn't been an open discussion about this. Is this even a good idea?
|
||||
Sometimes projects converge eventually if their overlap is big enough, sometimes they don't.
|
||||
|
||||
While unification sounds like a simplification of the ecosystem, it also takes away choice.
|
||||
Take `curl` and `wget` as an example.
|
||||
|
||||
### Why not support windows?
|
||||
|
||||
Windows is supported since GHCup version 0.1.15.1.
|
||||
|
||||
### Why the haskell reimplementation?
|
||||
|
||||
GHCup started as a portable posix shell script of maybe 50 LOC. GHC installation itself can be carried out in
|
||||
about ~3 lines of shell code (download, unpack , configure+make install). However, much convenient functionality
|
||||
has been added since, as well as ensuring that all operations are safe and correct. The shell script ended up with
|
||||
over 2k LOC, which was very hard to maintain.
|
||||
|
||||
The main concern when switching from a portable shell script to haskell was platform/architecture support.
|
||||
However, ghcup now re-uses GHCs CI infrastructure and as such is perfectly in sync with all platforms that
|
||||
GHC supports.
|
||||
251
docs/css/extra.css
Normal file
@@ -0,0 +1,251 @@
|
||||
h2
|
||||
{
|
||||
border-bottom:1px solid #CCC;
|
||||
padding-bottom:5px;
|
||||
padding-top:15px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
font-size: 60px;
|
||||
font-weight: 300;
|
||||
padding-top:15px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 30px;
|
||||
padding-top:10px;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 25px;
|
||||
padding-top:10px;
|
||||
}
|
||||
|
||||
|
||||
div.col-md-9 h1:first-of-type {
|
||||
text-align: center;
|
||||
font-size: 60px;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
div.col-md-9>p:first-of-type {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
div.col-md-9 p.admonition-title:first-of-type {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
div.col-md-9 h1:first-of-type .headerlink {
|
||||
display: none;
|
||||
}
|
||||
|
||||
code.no-highlight {
|
||||
color: black;
|
||||
}
|
||||
|
||||
div.gh-badge img {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 25px;
|
||||
}
|
||||
|
||||
a.donate-badge img {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 0;
|
||||
padding: 0;
|
||||
height: 35px;
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 1000px) {
|
||||
a.donate-badge img {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Definition List styles */
|
||||
|
||||
dd {
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
/* Homepage */
|
||||
|
||||
body.homepage div.jumbotron {
|
||||
margin-top: 1.5rem;
|
||||
padding-top: 1rem;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
body.homepage div.jumbotron div.card {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
body.homepage>div.container div.col-md-3 {
|
||||
display: none;
|
||||
}
|
||||
|
||||
body.homepage>div.container div.col-md-9 {
|
||||
/* margin-left: 0; */
|
||||
/* padding-left: 0; */
|
||||
flex: 0 0 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.center {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
.bg-primary {
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#996FC2), color-stop(60%, #6A478D), to(#5E5086)) !important;
|
||||
background-image: linear-gradient(#996FC2, #6A478D 60%, #5E5086) !important;
|
||||
background-repeat: no-repeat !important;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#996FC2), color-stop(60%, #6A478D), to(#5E5086)) !important;
|
||||
background-image: linear-gradient(#996FC2, #6A478D 60%, #5E5086) !important;
|
||||
background-repeat: no-repeat !important;
|
||||
|
||||
color: #fff;
|
||||
background-color: #996FC1;
|
||||
border-color: #996FC1;
|
||||
|
||||
border-bottom: 1px solid #453A62;
|
||||
}
|
||||
|
||||
.navbar {
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#996FC2), color-stop(60%, #6A478D), to(#5E5086)) !important;
|
||||
background-image: linear-gradient(#996FC2, #6A478D 60%, #5E5086) !important;
|
||||
background-repeat: no-repeat !important;
|
||||
|
||||
color: #fff;
|
||||
background-color: #996FC1;
|
||||
border-color: #996FC1;
|
||||
|
||||
border-bottom: 1px solid #453A62;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #996FC2;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #674489;
|
||||
}
|
||||
|
||||
.col-md-9 img.main-logo {
|
||||
border: 0px;
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
.navbar-default .navbar-nav>.active>a, .navbar-default .navbar-nav>.active>a:hover, .navbar-default .navbar-nav>.active>a:focus {
|
||||
color: #fff;
|
||||
background-color: #453A62;
|
||||
border-color: #996FC1;
|
||||
}
|
||||
|
||||
.navbar-default .navbar-nav>li>a:hover, .navbar-default .navbar-nav>li>a:focus {
|
||||
color: #fff;
|
||||
background-color: #453A62;
|
||||
}
|
||||
|
||||
.ghcup-intro {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.main-buttons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.main-buttons a {
|
||||
margin-right: 5px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.command-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.command-button > pre {
|
||||
flex: 0 1 80%;
|
||||
margin: 0;
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
background-color: #515151;
|
||||
color: white;
|
||||
border-radius: 3px;
|
||||
box-shadow: inset 0px 0px 20px 0px #333333;
|
||||
font-size: 1em;
|
||||
white-space: nowrap;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.ghcup-command:before {
|
||||
color: #999;
|
||||
content: " $ ";
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
div.command-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.command-button pre {
|
||||
|
||||
}
|
||||
|
||||
div.command-button button {
|
||||
color: #515151;
|
||||
background: rgb(230, 230, 230);
|
||||
border: 1px solid grey;
|
||||
margin: 0 0 0 10px;
|
||||
padding: 10px;
|
||||
flex-basis: 0 0 20%;
|
||||
}
|
||||
|
||||
div.command-button button .fa {
|
||||
font-size: x-large;
|
||||
}
|
||||
|
||||
div.command-button button:hover {
|
||||
background: rgb(220, 220, 220);
|
||||
color: black;
|
||||
border: 1px solid black;
|
||||
}
|
||||
|
||||
div.command-button button:focus {
|
||||
background-color: #04aa6d;
|
||||
}
|
||||
|
||||
footer > hr {
|
||||
border-top: 0.5px solid #CCC;
|
||||
}
|
||||
|
||||
.qi-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.ghcup-os-container {
|
||||
width: 100%;
|
||||
margin: 10px 0;
|
||||
}
|
||||
.ghcup-os-container > * {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* fix list overflows (esp about page) */
|
||||
ul > li {
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
120
docs/dev.md
Normal file
@@ -0,0 +1,120 @@
|
||||
# Development
|
||||
|
||||
All you wanted to know about GHCup development.
|
||||
|
||||
## Module graph
|
||||
|
||||
[{: .center style="width:900px"}](./modules_wide.svg)
|
||||
|
||||
Main functionality is in `GHCup` module. Utility functions are
|
||||
organised tree-ish in `GHCup.Utils` and `GHCup.Utils.*`.
|
||||
|
||||
Anything dealing with ghcup specific directories is in
|
||||
`GHCup.Utils.Dirs`.
|
||||
|
||||
Download information on where to fetch bindists from is in the appropriate
|
||||
yaml files: `data/metadata/ghcup-<yaml-ver>.yaml`.
|
||||
|
||||
## Design decisions
|
||||
|
||||
### Using [Excepts](https://hackage.haskell.org/package/haskus-utils-variant-3.0/docs/Haskus-Utils-Variant-Excepts.html) as a beefed up ExceptT
|
||||
|
||||
This is an open variant, similar to [plucky](https://hackage.haskell.org/package/plucky) or [oops](https://github.com/i-am-tom/oops) and allows us to combine different error types. Maybe it is too much and it's a little bit [unergonomic](https://github.com/haskus/packages/issues/32) at times. If it really hurts maintenance, it will be removed. It was more of an experiment.
|
||||
|
||||
### No use of haskell-TLS
|
||||
|
||||
I consider haskell-TLS an interesting experiment, but not a battle-tested and peer-reviewed crypto implementation. There is little to no research about what the intricacies of using haskell for low-level crypto are and how vulnerable such binaries are. Instead, we use either curl the binary or wget. There's also an implementation based on OpenSSL bindings, but it isn't enabled by default, since it would complicate shipping static binaries.
|
||||
|
||||
### Optics instead of lens
|
||||
|
||||
They're a little safer (less Monoid weirdness with view) and have better error messages. Consider the following with [lens](https://hackage.haskell.org/package/lens):
|
||||
|
||||
```
|
||||
> view (_Just . to (++ "abc")) Nothing
|
||||
""
|
||||
```
|
||||
|
||||
vs [optics](https://hackage.haskell.org/package/optics):
|
||||
|
||||
```
|
||||
> view (_Just % to (++ "abc")) Nothing
|
||||
|
||||
<interactive>:2:1: error:
|
||||
• An_AffineFold cannot be used as A_Getter
|
||||
• In the expression: view (_Just % to (++ "abc")) Nothing
|
||||
In an equation for ‘it’: it = view (_Just % to (++ "abc")) Nothing
|
||||
```
|
||||
|
||||
### StrictData on by default
|
||||
|
||||
Kazu Yamamoto [explained it in his PR](https://github.com/yesodweb/wai/pull/752#issuecomment-501531386) very well. I like to agree with him. The instances where we need non-strict behavior, we annotate it.
|
||||
|
||||
`Strict` is a little more odd as a default, since it depends on how you define your functions as well.
|
||||
|
||||
## Code style and formatting
|
||||
|
||||
Unfortunately, code formatters are semi-broken on this codebase, due to TH and CPP.
|
||||
|
||||
Some light suggestions:
|
||||
|
||||
1. mtl-style preferred
|
||||
2. no overly pointfree style
|
||||
3. use `where` a lot, so the main function body reads like prose
|
||||
4. documentation is part of the code
|
||||
|
||||
## Common Tasks
|
||||
|
||||
### Adding a new GHC version
|
||||
|
||||
1. open the latest `data/metadata/ghcup-<yaml-ver>.yaml`
|
||||
2. find the latest ghc version (in yaml tree e.g. `ghcupDownloads -> GHC -> 8.10.7`)
|
||||
3. copy-paste it
|
||||
4. adjust the version, tags, changelog, source url
|
||||
5. adjust the various bindist urls (make sure to also change the yaml anchors)
|
||||
6. run `cabal run exe:ghcup-gen -- check -f data/metadata/ghcup-<yaml-ver>.yaml`
|
||||
7. run `cabal run exe:ghcup-gen -- check-tarballs -f data/metadata/ghcup-<yaml-ver>.yaml -u 'ghc-8\.10\.8'`
|
||||
|
||||
### Adding a new CLI command
|
||||
|
||||
An example illustration on how to deal with [optparse-applicative](https://hackage.haskell.org/package/optparse-applicative) can be seen here: https://gitlab.haskell.org/haskell/ghcup-hs/-/commit/c19dd5ee8b2edbaf0336af143f1c75b6f4843e26
|
||||
|
||||
## Major refactors
|
||||
|
||||
1. First major refactor included adding cross support. This added
|
||||
`GHCTargetVersion`, which includes the target in addition to the version.
|
||||
Most of the `Version` parameters to functions had to be replaced with
|
||||
that and ensured the logic is consistent for cross and non-cross
|
||||
installs.
|
||||
2. This refactor added windows support wrt [#130](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/130).
|
||||
The major changes here were switching `hpath` library out for `filepath`/`directory` (sadly) and
|
||||
introducing a non-unix way of handling processes via the `process` library. It also introduced considerable
|
||||
amounts of CPP wrt file handling, installation etc.
|
||||
|
||||
# Releasing
|
||||
|
||||
1. Update version in `ghcup.cabal` and `boostrap-haskell` (`ghver` variable at the top of the script)
|
||||
|
||||
2. Update `GHCup.Version` module. `ghcupURL` must only be updated if we change the `GHCupInfo` type or the YAML representation of it. The version of the YAML represents the change increments. `ghcUpVer` is the current application version, read from `ghcup.cabal`.
|
||||
|
||||
3. Add ChangeLog entry
|
||||
|
||||
4. Add/fix downloads in `ghcup-<ver>.yaml` (under `data/metadata`), then verify with `ghcup-gen check -f data/metadata/ghcup-<ver>.yaml` and possibly (example only) `ghcup-gen check-tarballs -f data/metadata/ghcup-<ver>.yaml -u 'ghc-8.10.7'`. Generally, new GHC/cabal/stack/hls versions are only added to the latest yaml file. New GHCup versions are added to all (great care must be taken here to not break the parser... e.g. ARM platforms don't parse in all older formats).
|
||||
|
||||
5. Commit and git push with tag. Wait for tests to succeed and release artifacts to build.
|
||||
|
||||
6. Download release artifacts and upload them `downloads.haskell.org/~ghcup` along with checksum files (`sha256sum --tag * > SHA256SUMS && gpg --detach-sign -u <your-email> SHA256SUMS`)
|
||||
|
||||
7. Add ghcup release artifacts to ALL yaml files (see point 4.)
|
||||
|
||||
8. Upload the final `data/metadata/ghcup-<ver>.yaml` (and a detached GPG sig of it) to `webhost.haskell.org/ghcup/data/`.
|
||||
|
||||
9. Update `bootstrap-haskell` and `bootstrap-haskell.ps1` to `webhost.haskell.org/ghcup/sh/`
|
||||
|
||||
10. Update the top-level ghcup symlinks at `downloads.haskell.org/~ghcup`
|
||||
|
||||
11. Post on reddit/discourse/etc. and collect rewards
|
||||
|
||||
# Documentation
|
||||
|
||||
This documentation page is built via [mkdocs](https://www.mkdocs.org/), see `mkdocs.yml` and `docs/` subfolder.
|
||||
The module graph needs [graphmod](https://github.com/yav/graphmod) and is generated via `scripts/dev/modgraph.sh`.
|
||||
65
docs/expand-piece.svg
Normal file
@@ -0,0 +1,65 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="158.21451"
|
||||
height="33.036404"
|
||||
id="svg2997"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.5 r10040"
|
||||
sodipodi:docname="expand-piece.svg">
|
||||
<defs
|
||||
id="defs2999" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="11.2"
|
||||
inkscape:cx="74.534935"
|
||||
inkscape:cy="-6.6497355"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:window-height="1374"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata3002">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-218.01937,-324.40519)">
|
||||
<path
|
||||
style="fill:none;stroke:#524a67;stroke-width:13;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||
d="m 224.64286,330.93361 74.64102,20 70.35898,-18.85263"
|
||||
id="path2994"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.0 KiB |
BIN
docs/ghcup.gif
Normal file
|
After Width: | Height: | Size: 198 KiB |
307
docs/guide.md
Normal file
@@ -0,0 +1,307 @@
|
||||
# User Guide
|
||||
|
||||
`ghcup --help` is your friend.
|
||||
|
||||
## Basic usage
|
||||
|
||||
For the simple interactive TUI (not available on windows), run:
|
||||
|
||||
```sh
|
||||
ghcup tui
|
||||
```
|
||||
|
||||
For the full functionality via cli:
|
||||
|
||||
```sh
|
||||
# list available ghc/cabal versions
|
||||
ghcup list
|
||||
|
||||
# install the recommended GHC version
|
||||
ghcup install ghc
|
||||
|
||||
# install a specific GHC version
|
||||
ghcup install ghc 8.2.2
|
||||
|
||||
# set the currently "active" GHC version
|
||||
ghcup set ghc 8.4.4
|
||||
|
||||
# install cabal-install
|
||||
ghcup install cabal
|
||||
|
||||
# update ghcup itself
|
||||
ghcup upgrade
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
A configuration file can be put in `~/.ghcup/config.yaml`. The default config file
|
||||
explaining all possible configurations can be found in this repo: [config.yaml](https://gitlab.haskell.org/haskell/ghcup-hs/-/blob/master/data/config.yaml).
|
||||
|
||||
Partial configuration is fine. Command line options always override the config file settings.
|
||||
|
||||
## GPG verification
|
||||
|
||||
GHCup supports verifying the GPG signature of the metadata file. The metadata file then contains SHA256 hashes of all downloads, so
|
||||
this is cryptographically secure.
|
||||
|
||||
First, obtain the gpg key:
|
||||
|
||||
```sh
|
||||
gpg --batch --keyserver keys.openpgp.org --recv-keys 7784930957807690A66EBDBE3786C5262ECB4A3F
|
||||
```
|
||||
|
||||
Then verify the gpg key in one of these ways:
|
||||
|
||||
1. find out where I live and visit me to do offline key signing
|
||||
2. figure out my mobile phone number and call me to verify the fingerprint
|
||||
3. more boring: contact me on Libera IRC (`maerwald`) and verify the fingerprint
|
||||
|
||||
Once you've verified the key, you have to figure out if you trust me.
|
||||
|
||||
If you trust me, then you can configure gpg in `~/.ghcup/config.yaml`:
|
||||
|
||||
```yml
|
||||
gpg-setting: GPGLax # GPGStrict | GPGLax | GPGNone
|
||||
```
|
||||
|
||||
In `GPGStrict` mode, ghcup will fail if verification fails. In `GPGLax` mode it will just print a warning.
|
||||
You can also pass the mode via `ghcup --gpg <strict|lax|none>`.
|
||||
|
||||
## Manpages
|
||||
|
||||
For man pages to work you need [man-db](http://man-db.nongnu.org/) as your `man` provider, then issue `man ghc`. Manpages only work for the currently set ghc.
|
||||
`MANPATH` may be required to be unset.
|
||||
|
||||
## Shell-completion
|
||||
|
||||
Shell completions are in [scripts/shell-completions](https://gitlab.haskell.org/haskell/ghcup-hs/-/tree/master/scripts/shell-completions) directory of this repository.
|
||||
|
||||
For bash: install `shell-completions/bash`
|
||||
as e.g. `/etc/bash_completion.d/ghcup` (depending on distro)
|
||||
and make sure your bashrc sources the startup script
|
||||
(`/usr/share/bash-completion/bash_completion` on some distros).
|
||||
|
||||
## Compiling GHC from source
|
||||
|
||||
Compiling from source is supported for both source tarballs and arbitrary git refs. See `ghcup compile ghc --help`
|
||||
for a list of all available options.
|
||||
|
||||
If you need to overwrite the existing `build.mk`, check the default files
|
||||
in [data/build_mk](https://gitlab.haskell.org/haskell/ghcup-hs/-/tree/master/data/build_mk), copy them somewhere, adjust them and
|
||||
pass `--config path/to/build.mk` to `ghcup compile ghc`.
|
||||
Common `build.mk` options are explained [here](https://gitlab.haskell.org/ghc/ghc/-/wikis/building/using#build-configuration).
|
||||
|
||||
Make sure your system meets all the [prerequisites](https://gitlab.haskell.org/ghc/ghc/-/wikis/building/preparation).
|
||||
|
||||
### Cross support
|
||||
|
||||
ghcup can compile and install a cross GHC for any target. However, this
|
||||
requires that the build host has a complete cross toolchain and various
|
||||
libraries installed for the target platform.
|
||||
|
||||
Consult the GHC documentation on the [prerequisites](https://gitlab.haskell.org/ghc/ghc/-/wikis/building/cross-compiling#tools-to-install).
|
||||
For distributions with non-standard locations of cross toolchain and
|
||||
libraries, this may need some tweaking of `build.mk` or configure args.
|
||||
See `ghcup compile ghc --help` for further information.
|
||||
|
||||
## XDG support
|
||||
|
||||
To enable XDG style directories, set the environment variable `GHCUP_USE_XDG_DIRS` to anything.
|
||||
|
||||
Then you can control the locations via XDG environment variables as such:
|
||||
|
||||
* `XDG_DATA_HOME`: GHCs will be unpacked in `ghcup/ghc` subdir (default: `~/.local/share`)
|
||||
* `XDG_CACHE_HOME`: logs and download files will be stored in `ghcup` subdir (default: `~/.cache`)
|
||||
* `XDG_BIN_HOME`: binaries end up here (default: `~/.local/bin`)
|
||||
* `XDG_CONFIG_HOME`: the config file is stored in `ghcup` subdir as `config.yaml` (default: `~/.config`)
|
||||
|
||||
**Note that `ghcup` makes some assumptions about structure of files in `XDG_BIN_HOME`. So if you have other tools
|
||||
installing e.g. stack/cabal/ghc into it, this will likely clash. In that case consider disabling XDG support.**
|
||||
|
||||
## Env variables
|
||||
|
||||
This is the complete list of env variables that change GHCup behavior:
|
||||
|
||||
* `GHCUP_USE_XDG_DIRS`: see [XDG support](#xdg-support) above
|
||||
* `TMPDIR`: where ghcup does the work (unpacking, building, ...)
|
||||
* `GHCUP_INSTALL_BASE_PREFIX`: the base of ghcup (default: `$HOME`)
|
||||
* `GHCUP_CURL_OPTS`: additional options that can be passed to curl
|
||||
* `GHCUP_WGET_OPTS`: additional options that can be passed to wget
|
||||
* `GHCUP_GPG_OPTS`: additional options that can be passed to gpg
|
||||
* `GHCUP_SKIP_UPDATE_CHECK`: Skip the (possibly annoying) update check when you run a command
|
||||
* `CC`/`LD` etc.: full environment is passed to the build system when compiling GHC via GHCup
|
||||
|
||||
## Installing custom bindists
|
||||
|
||||
There are a couple of good use cases to install custom bindists:
|
||||
|
||||
1. manually built bindists (e.g. with patches)
|
||||
- example: `ghcup install ghc -u 'file:///home/mearwald/tmp/ghc-eff-patches/ghc-8.10.2-x86_64-deb10-linux.tar.xz' 8.10.2-eff`
|
||||
2. GHC head CI bindists
|
||||
- example: `ghcup install ghc -u 'https://gitlab.haskell.org/api/v4/projects/1/jobs/artifacts/master/raw/ghc-x86_64-fedora27-linux.tar.xz?job=validate-x86_64-linux-fedora27' head`
|
||||
3. DWARF bindists
|
||||
- example: `ghcup install ghc -u 'https://downloads.haskell.org/~ghc/8.10.2/ghc-8.10.2-x86_64-deb10-linux-dwarf.tar.xz' 8.10.2-dwarf`
|
||||
|
||||
Since the version parser is pretty lax, `8.10.2-eff` and `head` are both valid versions
|
||||
and produce the binaries `ghc-8.10.2-eff` and `ghc-head` respectively.
|
||||
GHCup always needs to know which version the bindist corresponds to (this is not automatically
|
||||
detected).
|
||||
|
||||
## Isolated installs
|
||||
|
||||
Ghcup also enables you to install a tool (GHC, Cabal, HLS, Stack) at an isolated location of your choosing.
|
||||
These installs, as the name suggests, are separate from your main installs and DO NOT conflict with them.
|
||||
|
||||
|
||||
- No symlinks are made to these isolated installed tools, you'd have to manually point to them wherever you intend to use them.
|
||||
|
||||
- These installs, can also NOT be deleted from ghcup, you'd have to go and manually delete these.
|
||||
|
||||
You need to use the `--isolate` or `-i` flag followed by the directory path.
|
||||
|
||||
Examples:
|
||||
|
||||
1. install an isolated GHC version at location /home/user/isolated_dir/ghc/
|
||||
- `ghcup install ghc 8.10.5 --isolate /home/user/isolated_dir/ghc`
|
||||
|
||||
2. isolated install Cabal at a location you desire
|
||||
- `ghcup install cabal --isolate /home/username/my_isolated_dir/`
|
||||
|
||||
3. do an isolated install with a custom bindist
|
||||
- `ghcup install ghc --isolate /home/username/my_isolated_dir/ -u 'https://gitlab.haskell.org/api/v4/projects/1/jobs/artifacts/master/raw/ghc-x86_64-fedora27-linux.tar.xz?job=validate-x86_64-linux-fedora27' head`
|
||||
|
||||
4. isolated install HLS
|
||||
- `ghcup install hls --isolate /home/username/dir/hls/`
|
||||
|
||||
5. you can even compile ghc to an isolated location.
|
||||
- `ghcup compile ghc -j 4 -v 9.0.1 -b 8.10.5 -i /home/username/my/dir/ghc`
|
||||
|
||||
## Continuous integration
|
||||
|
||||
On windows, ghcup can be installed automatically on a CI runner non-interactively like so:
|
||||
|
||||
```ps
|
||||
Set-ExecutionPolicy Bypass -Scope Process -Force;[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072;Invoke-Command -ScriptBlock ([ScriptBlock]::Create((Invoke-WebRequest https://www.haskell.org/ghcup/sh/bootstrap-haskell.ps1 -UseBasicParsing))) -ArgumentList $false,$true,$true,$false,$false,$false,$false,"C:\"
|
||||
```
|
||||
|
||||
On linux/darwin/freebsd, run the following on your runner:
|
||||
|
||||
```sh
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | BOOTSTRAP_HASKELL_NONINTERACTIVE=1 BOOTSTRAP_HASKELL_MINIMAL=1 sh
|
||||
```
|
||||
|
||||
This will just install `ghcup` and on windows additionally `msys2`.
|
||||
|
||||
For the full list of env variables and parameters to tweak the script behavior, see:
|
||||
|
||||
* [bootstrap-haskell for linux/darwin/freebsd](https://gitlab.haskell.org/haskell/ghcup-hs/-/blob/master/scripts/bootstrap/bootstrap-haskell#L7)
|
||||
* [bootstrap-haskell.ps1 for windows](https://gitlab.haskell.org/haskell/ghcup-hs/-/blob/master/scripts/bootstrap/bootstrap-haskell.ps1#L17)
|
||||
|
||||
### Example github workflow
|
||||
|
||||
On github workflows you can use https://github.com/haskell/actions/
|
||||
|
||||
If you want to install ghcup manually though, here's an example config:
|
||||
|
||||
```yml
|
||||
name: Haskell CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
build-cabal:
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, macOS-latest, windows-latest]
|
||||
ghc: ['8.10.7', '9.0.1']
|
||||
cabal: ['3.4.0.0']
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- if: matrix.os == 'windows-latest'
|
||||
name: Install ghcup on windows
|
||||
run: Set-ExecutionPolicy Bypass -Scope Process -Force;[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072;Invoke-Command -ScriptBlock ([ScriptBlock]::Create((Invoke-WebRequest https://www.haskell.org/ghcup/sh/bootstrap-haskell.ps1 -UseBasicParsing))) -ArgumentList $false,$true,$true,$false,$false,$false,$false,"C:\"
|
||||
|
||||
- if: matrix.os == 'windows-latest'
|
||||
name: Add ghcup to PATH
|
||||
run: echo "/c/ghcup/bin" >> $GITHUB_PATH
|
||||
shell: bash
|
||||
|
||||
- if: matrix.os != 'windows-latest'
|
||||
name: Install ghcup on non-windows
|
||||
run: curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | BOOTSTRAP_HASKELL_NONINTERACTIVE=1 BOOTSTRAP_HASKELL_MINIMAL=1 sh
|
||||
|
||||
- name: Install ghc/cabal
|
||||
run: |
|
||||
ghcup install ghc ${{ matrix.ghc }}
|
||||
ghcup install cabal ${{ matrix.cabal }}
|
||||
shell: bash
|
||||
|
||||
- name: Update cabal index
|
||||
run: cabal update
|
||||
shell: bash
|
||||
|
||||
- name: Build
|
||||
run: cabal build --enable-tests --enable-benchmarks
|
||||
shell: bash
|
||||
|
||||
- name: Run tests
|
||||
run: cabal test
|
||||
shell: bash
|
||||
```
|
||||
|
||||
## Tips and tricks
|
||||
|
||||
### with_ghc wrapper (e.g. for HLS)
|
||||
|
||||
Due to some HLS [bugs](https://github.com/mpickering/hie-bios/issues/194) it's necessary that the `ghc` in PATH
|
||||
is the one defined in `cabal.project`. With some simple shell functions, we can start our editor with the appropriate
|
||||
path prepended.
|
||||
|
||||
For bash, in e.g. `~/.bashrc` define:
|
||||
|
||||
```sh
|
||||
with_ghc() {
|
||||
local np=$(ghcup --offline whereis -d ghc $1 || { ghcup --cache install ghc $1 && ghcup whereis -d ghc $1 ;})
|
||||
if [ -e "${np}" ] ; then
|
||||
shift
|
||||
PATH="$np:$PATH" "$@"
|
||||
else
|
||||
>&2 echo "Cannot find or install GHC version $1"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
```
|
||||
|
||||
For fish shell, in e.g. `~/.config/fish/config.fish` define:
|
||||
|
||||
```fish
|
||||
function with_ghc
|
||||
set --local np (ghcup --offline whereis -d ghc $argv[1] ; or begin ghcup --cache install ghc $argv[1] ; and ghcup whereis -d ghc $argv[1] ; end)
|
||||
if test -e "$np"
|
||||
PATH="$np:$PATH" $argv[2..-1]
|
||||
else
|
||||
echo "Cannot find or install GHC version $argv[1]" 1>&2
|
||||
return 1
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
Then start a new shell and issue:
|
||||
|
||||
```sh
|
||||
# replace 'code' with your editor
|
||||
with_ghc 8.10.5 code path/to/haskell/source
|
||||
```
|
||||
|
||||
Cabal and HLS will now see `8.10.5` as the primary GHC, without the need to
|
||||
run `ghcup set` all the time when switching between projects.
|
||||
|
||||
BIN
docs/haskell_logo.png
Normal file
|
After Width: | Height: | Size: 93 KiB |
66
docs/index.md
Normal file
@@ -0,0 +1,66 @@
|
||||
---
|
||||
hide:
|
||||
- navigation
|
||||
- toc
|
||||
---
|
||||
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
|
||||
<script src="javascripts/extra.js"></script>
|
||||
|
||||
|
||||
# {: .main-logo style="width:100px"} GHCup
|
||||
|
||||
<p class="ghcup-intro">GHCup is an installer for the general purpose language <a href="https://www.haskell.org">Haskell</a>.</p>
|
||||
|
||||
<div class="text-center gh-badge">
|
||||
<a href="https://kiwiirc.com/nextclient/irc.libera.chat/?nick=Guest%7C?#haskell,#haskell-ghcup"><img src="https://img.shields.io/badge/chat-on%20libera%20IRC-brightgreen.svg" alt="Join the chat at Libera.chat"></a>
|
||||
<a href="https://app.element.io/#/room/#haskell-tooling:matrix.org"><img src="https://img.shields.io/matrix/haskell-tooling:matrix.org?label=chat%20on%20matrix.org" alt="Join the chat at Matrix.org"></a>
|
||||
<a href="https://discord.gg/pKYf3zDQU7"><img src="https://img.shields.io/discord/280033776820813825?label=chat%20on%20discord" alt="Join the chat at Discord"></a>
|
||||
<a href="https://gitter.im/haskell/ghcup?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge"><img src="https://badges.gitter.im/haskell/ghcup.svg" alt="Join the chat at https://gitter.im/haskell/ghcup"></a>
|
||||
<a href="https://opencollective.com/ghcup#category-CONTRIBUTE" class="donate-badge"><img src="https://opencollective.com/webpack/donate/button@2x.png?color=blue" alt="Donate"></a>
|
||||
</div>
|
||||
|
||||
----
|
||||
|
||||
GHCup makes it easy to install specific versions of GHC on GNU/Linux,
|
||||
macOS (aka Darwin), FreeBSD and Windows and can also bootstrap a fresh [Haskell developer environment](./install/#supported-tools) from scratch.
|
||||
It follows the unix UNIX philosophy of [do one thing and do it well](https://en.wikipedia.org/wiki/Unix_philosophy#Do_One_Thing_and_Do_It_Well). Similar in scope to [rustup](https://github.com/rust-lang-nursery/rustup.rs), [pyenv](https://github.com/pyenv/pyenv) and [jenv](http://www.jenv.be).
|
||||
|
||||
<div class="text-center main-buttons">
|
||||
<a href="#quick-install" class="btn btn-primary" role="button">Quick Install</a>
|
||||
<a href="install/" class="btn btn-primary" role="button">Getting Started</a>
|
||||
<a href="guide/" class="btn btn-primary" role="button">User Guide</a>
|
||||
<a href="https://gitlab.haskell.org/haskell/ghcup-hs/-/issues" class="btn btn-primary" role="button">Issue tracker</a>
|
||||
</div>
|
||||
|
||||
[{: .center style="width:700px"}](install#installation)
|
||||
|
||||
<section class="qi-container">
|
||||
<h2 class="text-center" id="quick-install">Quick Install<a class="headerlink" href="#quick-install" title="Permanent link"></a></h2>
|
||||
|
||||
<div class="ghcup-os-container">
|
||||
<h3>Linux, macOS, FreeBSD or <a href="https://docs.microsoft.com/en-us/windows/wsl/"> WSL2 </a></h3>
|
||||
<p>Run the following in a terminal (as a non-root user):<p>
|
||||
<div class="command-button">
|
||||
<pre>
|
||||
<span class="ghcup-command" id="ghcup-command-linux">curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh</span>
|
||||
</pre>
|
||||
<button class="btn" onclick="copyToClipboardNux()" id="ghcup-linux-button"><i class="fa fa-copy"></i></button>
|
||||
</div>
|
||||
<span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="ghcup-os-container">
|
||||
<h3>Windows</h3>
|
||||
<p>Run the following in a PowerShell session (as a non-admin user):<p>
|
||||
|
||||
<div class="command-button">
|
||||
<pre>
|
||||
<span class="ghcup-command" id="ghcup-command-windows">Set-ExecutionPolicy Bypass -Scope Process -Force;[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072;Invoke-Command -ScriptBlock ([ScriptBlock]::Create((Invoke-WebRequest https://www.haskell.org/ghcup/sh/bootstrap-haskell.ps1 -UseBasicParsing))) -ArgumentList $true
|
||||
</span>
|
||||
</pre>
|
||||
<button class="btn" onclick="copyToClipboardWin()" id="ghcup-windows-button"><i class="fa fa-copy"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
101
docs/install.md
Normal file
@@ -0,0 +1,101 @@
|
||||
# Getting started
|
||||
|
||||
Let's get started....
|
||||
|
||||
## Installation
|
||||
|
||||
The following commands will download the `ghcup` binary into `~/.ghcup/bin` (or `C:\ghcup\bin` on windows) and then
|
||||
run it to interactively install the [Haskell Toolchain](#supported-tools). These commands should be run as **non-root/non-admin
|
||||
user**.
|
||||
|
||||
For Linux, macOS, FreeBSD or Windows Subsystem 2 for Linux, run this in a terminal:
|
||||
|
||||
```sh
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh
|
||||
```
|
||||
|
||||
For Windows, run this in a PowerShell session:
|
||||
|
||||
```psh
|
||||
Set-ExecutionPolicy Bypass -Scope Process -Force;[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072;Invoke-Command -ScriptBlock ([ScriptBlock]::Create((Invoke-WebRequest https://www.haskell.org/ghcup/sh/bootstrap-haskell.ps1 -UseBasicParsing))) -ArgumentList $true
|
||||
```
|
||||
|
||||
Advanced users may want to perform a [manual installation](#manual-install) and GPG verify the binaries.
|
||||
|
||||
## Supported tools
|
||||
|
||||
GHCup supports the following tools, which are also known as the **Haskell Toolchain**:
|
||||
|
||||
1. [GHC](https://www.haskell.org/ghc/)
|
||||
2. [cabal-install](https://cabal.readthedocs.io/en/latest/)
|
||||
3. [haskell-language-server](https://haskell-language-server.readthedocs.io/en/latest/)
|
||||
4. [stack](https://docs.haskellstack.org/en/latest/README/)
|
||||
|
||||
## Supported platforms
|
||||
|
||||
This list may not be exhaustive and specifies support for bindists only.
|
||||
|
||||
| Platform | Architecture | ghcup | GHC | cabal | HLS | stack |
|
||||
| ------ | ------ | ------ | ------ | ------ | ------ | ------ |
|
||||
| Windows 7 | amd64 | ❔ | ✅ | ✅ | ✅ | ✅ |
|
||||
| Windows 10 | amd64 | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| Windows Server 2016 | amd64 | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| Windows Server 2019 | amd64 | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| Windows Server 2022 | amd64 | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| Windows WSL1 | amd64 | ❌ | ❔ | ❔ | ❔ | ❔ |
|
||||
| Windows WSL2 | amd64 | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| MacOS >=10.13 | amd64 | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| MacOS <10.13 | amd64 | ❌ | ❔ | ❔ | ❔ | ❔ |
|
||||
| MacOS | aarch64 | ✅ | ✅ | ✅ | ⚠️ | ❌ |
|
||||
| FreeBSD | amd64 | ✅ | ⚠️ | ✅ | ⚠️ | ❌ |
|
||||
| Linux generic | x86 | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| Linux generic | amd64 | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| Linux generic | aarch64 | ✅ | ⚠️ | ✅ | ⚠️ | ❌ |
|
||||
| Linux generic | armv7 | ✅ | ⚠️ | ✅ | ⚠️ | ❌ |
|
||||
|
||||
### Windows 7
|
||||
|
||||
May or may not work, several issues:
|
||||
|
||||
* https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/140
|
||||
* https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/197
|
||||
|
||||
### WSL1
|
||||
|
||||
Unsupported. GHC may or may not work. Upgrade to WSL2.
|
||||
|
||||
### MacOS <13
|
||||
|
||||
Not supported. Would require separate binaries, since >=13 binaries are incompatible.
|
||||
Please upgrade.
|
||||
|
||||
### MacOS aarch64
|
||||
|
||||
HLS bindists are still experimental. Stack is theoretically supported, but has no binaries yet.
|
||||
|
||||
### FreeBSD
|
||||
|
||||
Lacks some upstream bindists and may need compat libs, since most bindists are built on FreeBSD-12.
|
||||
HLS bindists are experimental.
|
||||
|
||||
### Linux ARMv7/AARCH64
|
||||
|
||||
Lower availability of bindists. HLS only has experimental ones. Stack not supported currently.
|
||||
|
||||
## Manual install
|
||||
|
||||
Download the binary for your platform at [https://downloads.haskell.org/~ghcup/](https://downloads.haskell.org/~ghcup/)
|
||||
and place it into your `PATH` anywhere.
|
||||
|
||||
If you want to GPG verify the binaries, import the following key first: `7784930957807690A66EBDBE3786C5262ECB4A3F`.
|
||||
|
||||
Then adjust your `PATH` in `~/.bashrc` (or similar, depending on your shell) like so:
|
||||
|
||||
```sh
|
||||
export PATH="$HOME/.cabal/bin:$HOME/.ghcup/bin:$PATH"
|
||||
```
|
||||
|
||||
## Vim integration
|
||||
|
||||
See [ghcup.vim](https://github.com/hasufell/ghcup.vim).
|
||||
|
||||
23
docs/javascripts/extra.js
Normal file
@@ -0,0 +1,23 @@
|
||||
function copyToClipboardNux() {
|
||||
const text = document.getElementById("ghcup-command-linux").innerText;
|
||||
const el = document.createElement('textarea');
|
||||
el.value = text;
|
||||
document.body.appendChild(el);
|
||||
el.select();
|
||||
document.execCommand('copy');
|
||||
document.body.removeChild(el);
|
||||
const button = document.getElementById("ghcup-linux-button");
|
||||
button.focus();
|
||||
}
|
||||
|
||||
function copyToClipboardWin() {
|
||||
const text = document.getElementById("ghcup-command-windows").innerText;
|
||||
const el = document.createElement('textarea');
|
||||
el.value = text;
|
||||
document.body.appendChild(el);
|
||||
el.select();
|
||||
document.execCommand('copy');
|
||||
document.body.removeChild(el);
|
||||
const button = document.getElementById("ghcup-windows-button");
|
||||
button.focus();
|
||||
}
|
||||
366
docs/modules_small.svg
Normal file
@@ -0,0 +1,366 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<!-- Generated by graphviz version 2.44.0 (0)
|
||||
-->
|
||||
<!-- Title: G Pages: 1 -->
|
||||
<svg width="719pt" height="648pt"
|
||||
viewBox="0.00 0.00 719.28 648.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph0" class="graph" transform="scale(0.81 0.81) rotate(0) translate(4 794.2)">
|
||||
<title>G</title>
|
||||
<polygon fill="white" stroke="transparent" points="-4,4 -4,-794.2 882,-794.2 882,4 -4,4"/>
|
||||
<g id="clust1" class="cluster">
|
||||
<title>cluster_0</title>
|
||||
<polygon fill="#000000" fill-opacity="0.058824" stroke="#000000" stroke-opacity="0.058824" points="8,-8.95 8,-660.37 870,-660.37 870,-8.95 8,-8.95"/>
|
||||
<text text-anchor="middle" x="439" y="-645.17" font-family="Times-Roman" font-size="14.00">GHCup</text>
|
||||
</g>
|
||||
<g id="clust2" class="cluster">
|
||||
<title>cluster_1</title>
|
||||
<polygon fill="#000000" fill-opacity="0.058824" stroke="#000000" stroke-opacity="0.058824" points="190,-364.88 190,-541.72 450,-541.72 450,-364.88 190,-364.88"/>
|
||||
<text text-anchor="middle" x="320" y="-526.52" font-family="Times-Roman" font-size="14.00">Download</text>
|
||||
</g>
|
||||
<g id="clust3" class="cluster">
|
||||
<title>cluster_2</title>
|
||||
<polygon fill="#000000" fill-opacity="0.058824" stroke="#000000" stroke-opacity="0.058824" points="271,-191.39 271,-355.93 452,-355.93 452,-191.39 271,-191.39"/>
|
||||
<text text-anchor="middle" x="361.5" y="-340.73" font-family="Times-Roman" font-size="14.00">Types</text>
|
||||
</g>
|
||||
<g id="clust4" class="cluster">
|
||||
<title>cluster_3</title>
|
||||
<polygon fill="#000000" fill-opacity="0.058824" stroke="#000000" stroke-opacity="0.058824" points="566,-17.91 566,-576.42 862,-576.42 862,-17.91 566,-17.91"/>
|
||||
<text text-anchor="middle" x="714" y="-561.22" font-family="Times-Roman" font-size="14.00">Utils</text>
|
||||
</g>
|
||||
<g id="clust5" class="cluster">
|
||||
<title>cluster_4</title>
|
||||
<polygon fill="#000000" fill-opacity="0.058824" stroke="#000000" stroke-opacity="0.058824" points="640,-271.98 640,-448.82 758,-448.82 758,-271.98 640,-271.98"/>
|
||||
<text text-anchor="middle" x="699" y="-433.62" font-family="Times-Roman" font-size="14.00">File</text>
|
||||
</g>
|
||||
<g id="clust6" class="cluster">
|
||||
<title>cluster_5</title>
|
||||
<polygon fill="#000000" fill-opacity="0.058824" stroke="#000000" stroke-opacity="0.058824" points="583,-26.86 583,-110.81 653,-110.81 653,-26.86 583,-26.86"/>
|
||||
<text text-anchor="middle" x="618" y="-95.61" font-family="Times-Roman" font-size="14.00">String</text>
|
||||
</g>
|
||||
<g id="clust7" class="cluster">
|
||||
<title>cluster_6</title>
|
||||
<polygon fill="#000000" fill-opacity="0.058824" stroke="#000000" stroke-opacity="0.058824" points="712,-457.78 712,-541.72 782,-541.72 782,-457.78 712,-457.78"/>
|
||||
<text text-anchor="middle" x="747" y="-526.52" font-family="Times-Roman" font-size="14.00">Version</text>
|
||||
</g>
|
||||
<!-- u1 -->
|
||||
<g id="node1" class="node">
|
||||
<title>u1</title>
|
||||
<ellipse fill="#ffffbb" stroke="black" stroke-width="2" cx="387" cy="-486.95" rx="55.49" ry="18"/>
|
||||
<text text-anchor="middle" x="387" y="-483.25" font-family="Times-Roman" font-size="14.00">Download</text>
|
||||
</g>
|
||||
<!-- u12 -->
|
||||
<g id="node7" class="node">
|
||||
<title>u12</title>
|
||||
<ellipse fill="#bbffff" stroke="black" stroke-width="2" cx="688" cy="-393.95" rx="27" ry="18"/>
|
||||
<text text-anchor="middle" x="688" y="-390.25" font-family="Times-Roman" font-size="14.00">File</text>
|
||||
</g>
|
||||
<!-- u1->u12 -->
|
||||
<g id="edge15" class="edge">
|
||||
<title>u1->u12</title>
|
||||
<path fill="none" stroke="black" d="M416.08,-471.48C425.43,-467.42 435.96,-463.44 446,-460.95 491.68,-449.63 616.67,-467.2 657,-442.95 665.62,-437.77 672.27,-429.17 677.16,-420.67"/>
|
||||
<polygon fill="black" stroke="black" points="680.34,-422.15 681.79,-411.65 674.11,-418.95 680.34,-422.15"/>
|
||||
</g>
|
||||
<!-- u11 -->
|
||||
<g id="node15" class="node">
|
||||
<title>u11</title>
|
||||
<ellipse fill="#bbffff" stroke="black" stroke-width="0" cx="603" cy="-393.95" rx="28.7" ry="18"/>
|
||||
<text text-anchor="middle" x="603" y="-390.25" font-family="Times-Roman" font-size="14.00">Dirs</text>
|
||||
</g>
|
||||
<!-- u1->u11 -->
|
||||
<g id="edge14" class="edge">
|
||||
<title>u1->u11</title>
|
||||
<path fill="none" stroke="black" d="M419.14,-472.31C427.86,-468.62 437.29,-464.63 446,-460.95 489.08,-442.77 538.85,-421.87 570.6,-408.54"/>
|
||||
<polygon fill="black" stroke="black" points="571.98,-411.76 579.85,-404.66 569.27,-405.3 571.98,-411.76"/>
|
||||
</g>
|
||||
<!-- u13 -->
|
||||
<g id="node18" class="node">
|
||||
<title>u13</title>
|
||||
<ellipse fill="#ffffbb" stroke="black" stroke-width="0" cx="109" cy="-300.95" rx="44.39" ry="18"/>
|
||||
<text text-anchor="middle" x="109" y="-297.25" font-family="Times-Roman" font-size="14.00">Version</text>
|
||||
</g>
|
||||
<!-- u1->u13 -->
|
||||
<g id="edge13" class="edge">
|
||||
<title>u1->u13</title>
|
||||
<path fill="none" stroke="black" d="M356.68,-471.88C346.23,-467.63 334.3,-463.44 323,-460.95 290.82,-453.87 49.58,-466.95 27,-442.95 4.16,-418.68 12.6,-398.02 27,-367.95 36.61,-347.88 55.63,-331.97 72.94,-320.81"/>
|
||||
<polygon fill="black" stroke="black" points="75.07,-323.61 81.77,-315.4 71.41,-317.64 75.07,-323.61"/>
|
||||
</g>
|
||||
<!-- u17 -->
|
||||
<g id="node2" class="node">
|
||||
<title>u17</title>
|
||||
<ellipse fill="#bbbbff" stroke="black" stroke-width="0" cx="332" cy="-393.95" rx="30.59" ry="18"/>
|
||||
<text text-anchor="middle" x="332" y="-390.25" font-family="Times-Roman" font-size="14.00">Utils</text>
|
||||
</g>
|
||||
<!-- u5 -->
|
||||
<g id="node6" class="node">
|
||||
<title>u5</title>
|
||||
<ellipse fill="#ffbbbb" stroke="black" stroke-width="0" cx="410" cy="-300.95" rx="33.6" ry="18"/>
|
||||
<text text-anchor="middle" x="410" y="-297.25" font-family="Times-Roman" font-size="14.00">JSON</text>
|
||||
</g>
|
||||
<!-- u17->u5 -->
|
||||
<g id="edge16" class="edge">
|
||||
<title>u17->u5</title>
|
||||
<path fill="none" stroke="black" d="M345.23,-377.52C357.37,-363.35 375.54,-342.16 389.55,-325.81"/>
|
||||
<polygon fill="black" stroke="black" points="392.59,-327.64 396.44,-317.77 387.28,-323.09 392.59,-327.64"/>
|
||||
</g>
|
||||
<!-- u19 -->
|
||||
<g id="node3" class="node">
|
||||
<title>u19</title>
|
||||
<ellipse fill="#bbbbff" stroke="black" stroke-width="0" cx="256" cy="-486.95" rx="57.69" ry="18"/>
|
||||
<text text-anchor="middle" x="256" y="-483.25" font-family="Times-Roman" font-size="14.00">IOStreams</text>
|
||||
</g>
|
||||
<!-- u19->u17 -->
|
||||
<g id="edge17" class="edge">
|
||||
<title>u19->u17</title>
|
||||
<path fill="none" stroke="black" d="M272.49,-469.68C280.19,-461.83 289.33,-452.14 297,-442.95 303.18,-435.56 309.51,-427.17 315.06,-419.49"/>
|
||||
<polygon fill="black" stroke="black" points="318.21,-421.09 321.16,-410.91 312.51,-417.03 318.21,-421.09"/>
|
||||
</g>
|
||||
<!-- u3 -->
|
||||
<g id="node4" class="node">
|
||||
<title>u3</title>
|
||||
<ellipse fill="#ffffbb" stroke="black" stroke-width="2" cx="399" cy="-220.95" rx="36.29" ry="18"/>
|
||||
<text text-anchor="middle" x="399" y="-217.25" font-family="Times-Roman" font-size="14.00">Types</text>
|
||||
</g>
|
||||
<!-- u4 -->
|
||||
<g id="node5" class="node">
|
||||
<title>u4</title>
|
||||
<ellipse fill="#ffbbbb" stroke="black" stroke-width="0" cx="319" cy="-300.95" rx="39.79" ry="18"/>
|
||||
<text text-anchor="middle" x="319" y="-297.25" font-family="Times-Roman" font-size="14.00">Optics</text>
|
||||
</g>
|
||||
<!-- u4->u3 -->
|
||||
<g id="edge18" class="edge">
|
||||
<title>u4->u3</title>
|
||||
<path fill="none" stroke="black" d="M335.19,-284.17C346.87,-272.78 362.8,-257.24 375.83,-244.55"/>
|
||||
<polygon fill="black" stroke="black" points="378.39,-246.94 383.11,-237.45 373.5,-241.92 378.39,-246.94"/>
|
||||
</g>
|
||||
<!-- u6 -->
|
||||
<g id="node12" class="node">
|
||||
<title>u6</title>
|
||||
<ellipse fill="#bbffff" stroke="black" stroke-width="0" cx="638" cy="-486.95" rx="64.19" ry="18"/>
|
||||
<text text-anchor="middle" x="638" y="-483.25" font-family="Times-Roman" font-size="14.00">MegaParsec</text>
|
||||
</g>
|
||||
<!-- u5->u6 -->
|
||||
<g id="edge19" class="edge">
|
||||
<title>u5->u6</title>
|
||||
<path fill="none" stroke="black" d="M425.28,-317.32C443.67,-335.87 472.3,-364.95 474,-367.95 491,-397.97 469.27,-418.9 494,-442.95 518.89,-467.15 536.76,-450.95 570,-460.95 577.45,-463.2 585.27,-465.82 592.85,-468.5"/>
|
||||
<polygon fill="black" stroke="black" points="591.68,-471.8 602.27,-471.91 594.06,-465.22 591.68,-471.8"/>
|
||||
</g>
|
||||
<!-- u7 -->
|
||||
<g id="node13" class="node">
|
||||
<title>u7</title>
|
||||
<ellipse fill="#bbffff" stroke="black" stroke-width="0" cx="618" cy="-220.95" rx="44.39" ry="18"/>
|
||||
<text text-anchor="middle" x="618" y="-217.25" font-family="Times-Roman" font-size="14.00">Prelude</text>
|
||||
</g>
|
||||
<!-- u5->u7 -->
|
||||
<g id="edge20" class="edge">
|
||||
<title>u5->u7</title>
|
||||
<path fill="none" stroke="black" d="M429.11,-285.89C434.97,-281.99 441.58,-277.99 448,-274.95 487.67,-256.18 535.63,-241.92 570.48,-232.95"/>
|
||||
<polygon fill="black" stroke="black" points="571.56,-236.29 580.4,-230.45 569.85,-229.51 571.56,-236.29"/>
|
||||
</g>
|
||||
<!-- u9 -->
|
||||
<g id="node8" class="node">
|
||||
<title>u9</title>
|
||||
<ellipse fill="#ffbbff" stroke="black" stroke-width="0" cx="699" cy="-300.95" rx="51.19" ry="18"/>
|
||||
<text text-anchor="middle" x="699" y="-297.25" font-family="Times-Roman" font-size="14.00">Common</text>
|
||||
</g>
|
||||
<!-- u12->u9 -->
|
||||
<g id="edge30" class="edge">
|
||||
<title>u12->u9</title>
|
||||
<path fill="none" stroke="black" d="M690.07,-375.84C691.65,-362.75 693.87,-344.43 695.69,-329.32"/>
|
||||
<polygon fill="black" stroke="black" points="699.21,-329.34 696.94,-318.99 692.27,-328.5 699.21,-329.34"/>
|
||||
</g>
|
||||
<!-- u9->u7 -->
|
||||
<g id="edge31" class="edge">
|
||||
<title>u9->u7</title>
|
||||
<path fill="none" stroke="black" d="M682.22,-283.79C670.52,-272.53 654.74,-257.34 641.76,-244.83"/>
|
||||
<polygon fill="black" stroke="black" points="644.12,-242.24 634.48,-237.83 639.26,-247.29 644.12,-242.24"/>
|
||||
</g>
|
||||
<!-- u10 -->
|
||||
<g id="node9" class="node">
|
||||
<title>u10</title>
|
||||
<ellipse fill="#77ff77" stroke="black" stroke-width="0" cx="618" cy="-55.95" rx="27" ry="18"/>
|
||||
<text text-anchor="middle" x="618" y="-52.25" font-family="Times-Roman" font-size="14.00">QQ</text>
|
||||
</g>
|
||||
<!-- u16 -->
|
||||
<g id="node10" class="node">
|
||||
<title>u16</title>
|
||||
<ellipse fill="#ffff77" stroke="black" stroke-width="0" cx="747" cy="-486.95" rx="27" ry="18"/>
|
||||
<text text-anchor="middle" x="747" y="-483.25" font-family="Times-Roman" font-size="14.00">QQ</text>
|
||||
</g>
|
||||
<!-- u15 -->
|
||||
<g id="node11" class="node">
|
||||
<title>u15</title>
|
||||
<ellipse fill="#ffffbb" stroke="black" stroke-width="2" cx="823" cy="-486.95" rx="30.59" ry="18"/>
|
||||
<text text-anchor="middle" x="823" y="-483.25" font-family="Times-Roman" font-size="14.00">Utils</text>
|
||||
</g>
|
||||
<!-- u15->u12 -->
|
||||
<g id="edge22" class="edge">
|
||||
<title>u15->u12</title>
|
||||
<path fill="none" stroke="black" d="M803.42,-472.71C797.8,-468.92 791.66,-464.77 786,-460.95 761.96,-444.74 734.59,-426.31 714.9,-413.05"/>
|
||||
<polygon fill="black" stroke="black" points="716.68,-410.03 706.43,-407.35 712.77,-415.84 716.68,-410.03"/>
|
||||
</g>
|
||||
<!-- u15->u11 -->
|
||||
<g id="edge21" class="edge">
|
||||
<title>u15->u11</title>
|
||||
<path fill="none" stroke="black" d="M805.88,-471.91C799.92,-467.72 792.97,-463.55 786,-460.95 723.08,-437.5 693.45,-477.7 636,-442.95 627.23,-437.65 620.23,-429.02 614.98,-420.54"/>
|
||||
<polygon fill="black" stroke="black" points="617.89,-418.57 609.96,-411.54 611.78,-421.98 617.89,-418.57"/>
|
||||
</g>
|
||||
<!-- u6->u3 -->
|
||||
<g id="edge23" class="edge">
|
||||
<title>u6->u3</title>
|
||||
<path fill="none" stroke="black" d="M608.52,-470.77C594.78,-463.16 578.53,-453.36 565,-442.95 527.38,-414.03 523.93,-400.08 489,-367.95 479.95,-359.63 474.21,-360.56 468,-349.95 450.82,-320.62 469.18,-304.85 453,-274.95 446.44,-262.83 436.18,-251.74 426.36,-242.87"/>
|
||||
<polygon fill="black" stroke="black" points="428.53,-240.12 418.66,-236.26 423.97,-245.43 428.53,-240.12"/>
|
||||
</g>
|
||||
<!-- u8 -->
|
||||
<g id="node14" class="node">
|
||||
<title>u8</title>
|
||||
<ellipse fill="#bbffff" stroke="black" stroke-width="0" cx="618" cy="-139.95" rx="42.49" ry="18"/>
|
||||
<text text-anchor="middle" x="618" y="-136.25" font-family="Times-Roman" font-size="14.00">Logger</text>
|
||||
</g>
|
||||
<!-- u7->u8 -->
|
||||
<g id="edge25" class="edge">
|
||||
<title>u7->u8</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M618,-202.81C618,-192.67 618,-179.59 618,-168.07"/>
|
||||
<polygon fill="black" stroke="black" points="621.5,-168.06 618,-158.06 614.5,-168.06 621.5,-168.06"/>
|
||||
</g>
|
||||
<!-- u2 -->
|
||||
<g id="node17" class="node">
|
||||
<title>u2</title>
|
||||
<ellipse fill="#ffffbb" stroke="black" stroke-width="0" cx="520" cy="-300.95" rx="37.89" ry="18"/>
|
||||
<text text-anchor="middle" x="520" y="-297.25" font-family="Times-Roman" font-size="14.00">Errors</text>
|
||||
</g>
|
||||
<!-- u7->u2 -->
|
||||
<g id="edge24" class="edge">
|
||||
<title>u7->u2</title>
|
||||
<path fill="none" stroke="black" d="M598.83,-237.21C584.07,-248.96 563.49,-265.34 547.06,-278.42"/>
|
||||
<polygon fill="black" stroke="black" points="544.54,-275.95 538.9,-284.91 548.9,-281.43 544.54,-275.95"/>
|
||||
</g>
|
||||
<!-- u8->u4 -->
|
||||
<g id="edge26" class="edge">
|
||||
<title>u8->u4</title>
|
||||
<path fill="none" stroke="black" d="M576.88,-144.38C511.17,-150.66 386.55,-166.09 354,-194.95 331.93,-214.52 323.74,-248.37 320.73,-272.34"/>
|
||||
<polygon fill="black" stroke="black" points="317.22,-272.27 319.67,-282.57 324.18,-272.99 317.22,-272.27"/>
|
||||
</g>
|
||||
<!-- u8->u9 -->
|
||||
<g id="edge27" class="edge">
|
||||
<title>u8->u9</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M637.21,-156.09C648.59,-166.01 662.41,-179.89 671,-194.95 684.9,-219.32 692.1,-250.8 695.69,-272.91"/>
|
||||
<polygon fill="black" stroke="black" points="692.25,-273.56 697.18,-282.94 699.17,-272.53 692.25,-273.56"/>
|
||||
</g>
|
||||
<!-- u8->u10 -->
|
||||
<g id="edge28" class="edge">
|
||||
<title>u8->u10</title>
|
||||
<path fill="none" stroke="black" d="M618,-121.56C618,-110.73 618,-96.56 618,-84.25"/>
|
||||
<polygon fill="black" stroke="black" points="621.5,-84.04 618,-74.04 614.5,-84.04 621.5,-84.04"/>
|
||||
</g>
|
||||
<!-- u11->u5 -->
|
||||
<g id="edge29" class="edge">
|
||||
<title>u11->u5</title>
|
||||
<path fill="none" stroke="black" d="M575.99,-387.58C537.44,-379.55 469,-363.89 448,-349.95 439.06,-344.02 431.26,-335.31 425.1,-326.92"/>
|
||||
<polygon fill="black" stroke="black" points="427.82,-324.71 419.28,-318.44 422.05,-328.67 427.82,-324.71"/>
|
||||
</g>
|
||||
<!-- u0 -->
|
||||
<g id="node16" class="node">
|
||||
<title>u0</title>
|
||||
<ellipse fill="#bbffbb" stroke="black" stroke-width="2" cx="627" cy="-605.95" rx="42.49" ry="18"/>
|
||||
<text text-anchor="middle" x="627" y="-602.25" font-family="Times-Roman" font-size="14.00">GHCup</text>
|
||||
</g>
|
||||
<!-- u0->u1 -->
|
||||
<g id="edge4" class="edge">
|
||||
<title>u0->u1</title>
|
||||
<path fill="none" stroke="black" d="M584.67,-604.4C545.83,-602.07 488.09,-593.82 446,-566.95 425.91,-554.13 410.22,-531.89 400.09,-514.27"/>
|
||||
<polygon fill="black" stroke="black" points="402.91,-512.13 395.04,-505.04 396.77,-515.5 402.91,-512.13"/>
|
||||
</g>
|
||||
<!-- u0->u16 -->
|
||||
<g id="edge6" class="edge">
|
||||
<title>u0->u16</title>
|
||||
<path fill="none" stroke="black" d="M663.33,-596.57C681.18,-590.83 701.84,-581.54 716,-566.95 729.77,-552.77 737.62,-531.76 741.97,-514.97"/>
|
||||
<polygon fill="black" stroke="black" points="745.4,-515.69 744.26,-505.16 738.58,-514.11 745.4,-515.69"/>
|
||||
</g>
|
||||
<!-- u0->u15 -->
|
||||
<g id="edge5" class="edge">
|
||||
<title>u0->u15</title>
|
||||
<path fill="none" stroke="black" d="M669.23,-604.64C704.08,-602.27 753,-593.85 786,-566.95 801.95,-553.96 811.39,-532.52 816.74,-515.25"/>
|
||||
<polygon fill="black" stroke="black" points="820.24,-515.72 819.56,-505.15 813.5,-513.84 820.24,-515.72"/>
|
||||
</g>
|
||||
<!-- u14 -->
|
||||
<g id="node19" class="node">
|
||||
<title>u14</title>
|
||||
<ellipse fill="#ffffbb" stroke="black" stroke-width="0" cx="508" cy="-486.95" rx="48.19" ry="18"/>
|
||||
<text text-anchor="middle" x="508" y="-483.25" font-family="Times-Roman" font-size="14.00">Platform</text>
|
||||
</g>
|
||||
<!-- u0->u14 -->
|
||||
<g id="edge3" class="edge">
|
||||
<title>u0->u14</title>
|
||||
<path fill="none" stroke="black" d="M599.25,-592.23C586.98,-585.76 572.9,-577.11 562,-566.95 545.64,-551.71 531.56,-530.66 521.88,-514.12"/>
|
||||
<polygon fill="black" stroke="black" points="524.68,-511.96 516.71,-504.98 518.59,-515.41 524.68,-511.96"/>
|
||||
</g>
|
||||
<!-- u2->u3 -->
|
||||
<g id="edge7" class="edge">
|
||||
<title>u2->u3</title>
|
||||
<path fill="none" stroke="black" d="M498.37,-286.01C479.01,-273.53 450.45,-255.12 428.91,-241.23"/>
|
||||
<polygon fill="black" stroke="black" points="430.75,-238.25 420.45,-235.78 426.95,-244.14 430.75,-238.25"/>
|
||||
</g>
|
||||
<!-- u13->u3 -->
|
||||
<g id="edge8" class="edge">
|
||||
<title>u13->u3</title>
|
||||
<path fill="none" stroke="black" d="M144.85,-290.31C198.89,-275.78 300.93,-248.33 357.9,-233.01"/>
|
||||
<polygon fill="black" stroke="black" points="358.91,-236.36 367.66,-230.38 357.09,-229.6 358.91,-236.36"/>
|
||||
</g>
|
||||
<!-- u14->u5 -->
|
||||
<g id="edge9" class="edge">
|
||||
<title>u14->u5</title>
|
||||
<path fill="none" stroke="black" d="M492.36,-469.49C485.88,-461.9 478.78,-452.48 474,-442.95 458.54,-412.12 468.2,-399.39 454,-367.95 447.34,-353.21 437.53,-338.1 428.85,-326.06"/>
|
||||
<polygon fill="black" stroke="black" points="431.57,-323.84 422.81,-317.89 425.94,-328.01 431.57,-323.84"/>
|
||||
</g>
|
||||
<!-- u14->u12 -->
|
||||
<g id="edge10" class="edge">
|
||||
<title>u14->u12</title>
|
||||
<path fill="none" stroke="black" d="M534.95,-471.89C543.43,-467.9 552.95,-463.86 562,-460.95 602.92,-447.83 621.35,-466.95 657,-442.95 665.13,-437.48 671.61,-429.08 676.49,-420.83"/>
|
||||
<polygon fill="black" stroke="black" points="679.72,-422.21 681.33,-411.74 673.54,-418.92 679.72,-422.21"/>
|
||||
</g>
|
||||
<!-- u18 -->
|
||||
<g id="node20" class="node">
|
||||
<title>u18</title>
|
||||
<ellipse fill="#ffffbb" stroke="black" stroke-width="0" cx="109" cy="-393.95" rx="73.39" ry="18"/>
|
||||
<text text-anchor="middle" x="109" y="-390.25" font-family="Times-Roman" font-size="14.00">Requirements</text>
|
||||
</g>
|
||||
<!-- u18->u5 -->
|
||||
<g id="edge12" class="edge">
|
||||
<title>u18->u5</title>
|
||||
<path fill="none" stroke="black" d="M147.73,-378.58C159.84,-374.58 173.34,-370.6 186,-367.95 265.56,-351.31 295.73,-387.15 368,-349.95 378.45,-344.58 387.45,-335.41 394.41,-326.53"/>
|
||||
<polygon fill="black" stroke="black" points="397.39,-328.37 400.44,-318.22 391.73,-324.26 397.39,-328.37"/>
|
||||
</g>
|
||||
<!-- u18->u13 -->
|
||||
<g id="edge11" class="edge">
|
||||
<title>u18->u13</title>
|
||||
<path fill="none" stroke="black" d="M109,-375.84C109,-362.75 109,-344.43 109,-329.32"/>
|
||||
<polygon fill="black" stroke="black" points="112.5,-328.99 109,-318.99 105.5,-328.99 112.5,-328.99"/>
|
||||
</g>
|
||||
<!-- u20 -->
|
||||
<g id="node21" class="node">
|
||||
<title>u20</title>
|
||||
<ellipse fill="#bbffbb" stroke="black" stroke-width="0" cx="627" cy="-769.95" rx="32.49" ry="18"/>
|
||||
<text text-anchor="middle" x="627" y="-766.25" font-family="Times-Roman" font-size="14.00">Main</text>
|
||||
</g>
|
||||
<!-- u21 -->
|
||||
<g id="node22" class="node">
|
||||
<title>u21</title>
|
||||
<ellipse fill="#bbffbb" stroke="black" stroke-width="0" cx="627" cy="-689.95" rx="46.29" ry="18"/>
|
||||
<text text-anchor="middle" x="627" y="-686.25" font-family="Times-Roman" font-size="14.00">Validate</text>
|
||||
</g>
|
||||
<!-- u20->u21 -->
|
||||
<g id="edge1" class="edge">
|
||||
<title>u20->u21</title>
|
||||
<path fill="none" stroke="black" d="M627,-751.64C627,-741.85 627,-729.38 627,-718.29"/>
|
||||
<polygon fill="black" stroke="black" points="630.5,-718.22 627,-708.22 623.5,-718.22 630.5,-718.22"/>
|
||||
</g>
|
||||
<!-- u21->u0 -->
|
||||
<g id="edge2" class="edge">
|
||||
<title>u21->u0</title>
|
||||
<path fill="none" stroke="black" d="M627,-671.56C627,-660.73 627,-646.56 627,-634.25"/>
|
||||
<polygon fill="black" stroke="black" points="630.5,-634.04 627,-624.04 623.5,-634.04 630.5,-634.04"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 19 KiB |
366
docs/modules_wide.svg
Normal file
@@ -0,0 +1,366 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<!-- Generated by graphviz version 2.44.0 (0)
|
||||
-->
|
||||
<!-- Title: G Pages: 1 -->
|
||||
<svg width="1075pt" height="648pt"
|
||||
viewBox="0.00 0.00 1075.16 648.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph0" class="graph" transform="scale(0.91 0.91) rotate(0) translate(4 710)">
|
||||
<title>G</title>
|
||||
<polygon fill="white" stroke="transparent" points="-4,4 -4,-710 1180.67,-710 1180.67,4 -4,4"/>
|
||||
<g id="clust1" class="cluster">
|
||||
<title>cluster_0</title>
|
||||
<polygon fill="#000000" fill-opacity="0.058824" stroke="#000000" stroke-opacity="0.058824" points="10.72,-8 10.72,-590 1165.95,-590 1165.95,-8 10.72,-8"/>
|
||||
<text text-anchor="middle" x="588.33" y="-574.8" font-family="Times-Roman" font-size="14.00">GHCup</text>
|
||||
</g>
|
||||
<g id="clust2" class="cluster">
|
||||
<title>cluster_1</title>
|
||||
<polygon fill="#000000" fill-opacity="0.058824" stroke="#000000" stroke-opacity="0.058824" points="254.63,-326 254.63,-484 603.08,-484 603.08,-326 254.63,-326"/>
|
||||
<text text-anchor="middle" x="428.85" y="-468.8" font-family="Times-Roman" font-size="14.00">Download</text>
|
||||
</g>
|
||||
<g id="clust3" class="cluster">
|
||||
<title>cluster_2</title>
|
||||
<polygon fill="#000000" fill-opacity="0.058824" stroke="#000000" stroke-opacity="0.058824" points="363.19,-171 363.19,-318 605.76,-318 605.76,-171 363.19,-171"/>
|
||||
<text text-anchor="middle" x="484.47" y="-302.8" font-family="Times-Roman" font-size="14.00">Types</text>
|
||||
</g>
|
||||
<g id="clust4" class="cluster">
|
||||
<title>cluster_3</title>
|
||||
<polygon fill="#000000" fill-opacity="0.058824" stroke="#000000" stroke-opacity="0.058824" points="758.53,-16 758.53,-515 1155.22,-515 1155.22,-16 758.53,-16"/>
|
||||
<text text-anchor="middle" x="956.88" y="-499.8" font-family="Times-Roman" font-size="14.00">Utils</text>
|
||||
</g>
|
||||
<g id="clust5" class="cluster">
|
||||
<title>cluster_4</title>
|
||||
<polygon fill="#000000" fill-opacity="0.058824" stroke="#000000" stroke-opacity="0.058824" points="857.71,-243 857.71,-401 1015.85,-401 1015.85,-243 857.71,-243"/>
|
||||
<text text-anchor="middle" x="936.78" y="-385.8" font-family="Times-Roman" font-size="14.00">File</text>
|
||||
</g>
|
||||
<g id="clust6" class="cluster">
|
||||
<title>cluster_5</title>
|
||||
<polygon fill="#000000" fill-opacity="0.058824" stroke="#000000" stroke-opacity="0.058824" points="781.32,-24 781.32,-99 875.13,-99 875.13,-24 781.32,-24"/>
|
||||
<text text-anchor="middle" x="828.22" y="-83.8" font-family="Times-Roman" font-size="14.00">String</text>
|
||||
</g>
|
||||
<g id="clust7" class="cluster">
|
||||
<title>cluster_6</title>
|
||||
<polygon fill="#000000" fill-opacity="0.058824" stroke="#000000" stroke-opacity="0.058824" points="954.2,-409 954.2,-484 1048.01,-484 1048.01,-409 954.2,-409"/>
|
||||
<text text-anchor="middle" x="1001.1" y="-468.8" font-family="Times-Roman" font-size="14.00">Version</text>
|
||||
</g>
|
||||
<!-- u1 -->
|
||||
<g id="node1" class="node">
|
||||
<title>u1</title>
|
||||
<ellipse fill="#ffffbb" stroke="black" stroke-width="2" cx="518.39" cy="-435" rx="55.49" ry="18"/>
|
||||
<text text-anchor="middle" x="518.39" y="-431.3" font-family="Times-Roman" font-size="14.00">Download</text>
|
||||
</g>
|
||||
<!-- u12 -->
|
||||
<g id="node7" class="node">
|
||||
<title>u12</title>
|
||||
<ellipse fill="#bbffff" stroke="black" stroke-width="2" cx="922.39" cy="-352" rx="27" ry="18"/>
|
||||
<text text-anchor="middle" x="922.39" y="-348.3" font-family="Times-Roman" font-size="14.00">File</text>
|
||||
</g>
|
||||
<!-- u1->u12 -->
|
||||
<g id="edge15" class="edge">
|
||||
<title>u1->u12</title>
|
||||
<path fill="none" stroke="black" d="M546.79,-419.43C556.27,-415.25 567.06,-411.24 577.39,-409 594.44,-405.31 876.17,-409.54 891.39,-401 900.16,-396.08 906.84,-387.53 911.72,-379"/>
|
||||
<polygon fill="black" stroke="black" points="914.92,-380.43 916.31,-369.92 908.67,-377.26 914.92,-380.43"/>
|
||||
</g>
|
||||
<!-- u11 -->
|
||||
<g id="node15" class="node">
|
||||
<title>u11</title>
|
||||
<ellipse fill="#bbffff" stroke="black" stroke-width="0" cx="808.39" cy="-352" rx="28.7" ry="18"/>
|
||||
<text text-anchor="middle" x="808.39" y="-348.3" font-family="Times-Roman" font-size="14.00">Dirs</text>
|
||||
</g>
|
||||
<!-- u1->u11 -->
|
||||
<g id="edge14" class="edge">
|
||||
<title>u1->u11</title>
|
||||
<path fill="none" stroke="black" d="M548.95,-419.93C557.99,-416.08 567.99,-412.11 577.39,-409 586.69,-405.92 709.34,-376.59 772.03,-361.65"/>
|
||||
<polygon fill="black" stroke="black" points="772.99,-365.02 781.91,-359.3 771.37,-358.21 772.99,-365.02"/>
|
||||
</g>
|
||||
<!-- u13 -->
|
||||
<g id="node18" class="node">
|
||||
<title>u13</title>
|
||||
<ellipse fill="#ffffbb" stroke="black" stroke-width="0" cx="146.39" cy="-269" rx="44.39" ry="18"/>
|
||||
<text text-anchor="middle" x="146.39" y="-265.3" font-family="Times-Roman" font-size="14.00">Version</text>
|
||||
</g>
|
||||
<!-- u1->u13 -->
|
||||
<g id="edge13" class="edge">
|
||||
<title>u1->u13</title>
|
||||
<path fill="none" stroke="black" d="M477.97,-422.58C457.84,-417.42 433.02,-411.85 410.39,-409 400.85,-407.8 71.11,-407.88 64.39,-401 41.09,-377.16 48.83,-355.48 64.39,-326 73.49,-308.76 90.55,-295.83 106.76,-286.76"/>
|
||||
<polygon fill="black" stroke="black" points="108.39,-289.86 115.62,-282.11 105.14,-283.66 108.39,-289.86"/>
|
||||
</g>
|
||||
<!-- u17 -->
|
||||
<g id="node2" class="node">
|
||||
<title>u17</title>
|
||||
<ellipse fill="#bbbbff" stroke="black" stroke-width="0" cx="445.39" cy="-352" rx="30.59" ry="18"/>
|
||||
<text text-anchor="middle" x="445.39" y="-348.3" font-family="Times-Roman" font-size="14.00">Utils</text>
|
||||
</g>
|
||||
<!-- u5 -->
|
||||
<g id="node6" class="node">
|
||||
<title>u5</title>
|
||||
<ellipse fill="#ffbbbb" stroke="black" stroke-width="0" cx="549.39" cy="-269" rx="33.6" ry="18"/>
|
||||
<text text-anchor="middle" x="549.39" y="-265.3" font-family="Times-Roman" font-size="14.00">JSON</text>
|
||||
</g>
|
||||
<!-- u17->u5 -->
|
||||
<g id="edge16" class="edge">
|
||||
<title>u17->u5</title>
|
||||
<path fill="none" stroke="black" d="M463.03,-337.26C479.49,-324.44 504.26,-305.15 523.05,-290.51"/>
|
||||
<polygon fill="black" stroke="black" points="525.22,-293.26 530.96,-284.35 520.92,-287.74 525.22,-293.26"/>
|
||||
</g>
|
||||
<!-- u19 -->
|
||||
<g id="node3" class="node">
|
||||
<title>u19</title>
|
||||
<ellipse fill="#bbbbff" stroke="black" stroke-width="0" cx="343.39" cy="-435" rx="57.69" ry="18"/>
|
||||
<text text-anchor="middle" x="343.39" y="-431.3" font-family="Times-Roman" font-size="14.00">IOStreams</text>
|
||||
</g>
|
||||
<!-- u19->u17 -->
|
||||
<g id="edge17" class="edge">
|
||||
<title>u19->u17</title>
|
||||
<path fill="none" stroke="black" d="M378.72,-420.5C389.55,-415.38 401.06,-408.84 410.39,-401 418.16,-394.47 425.12,-385.87 430.76,-377.75"/>
|
||||
<polygon fill="black" stroke="black" points="433.77,-379.54 436.33,-369.25 427.92,-375.7 433.77,-379.54"/>
|
||||
</g>
|
||||
<!-- u3 -->
|
||||
<g id="node4" class="node">
|
||||
<title>u3</title>
|
||||
<ellipse fill="#ffffbb" stroke="black" stroke-width="2" cx="534.39" cy="-197" rx="36.29" ry="18"/>
|
||||
<text text-anchor="middle" x="534.39" y="-193.3" font-family="Times-Roman" font-size="14.00">Types</text>
|
||||
</g>
|
||||
<!-- u4 -->
|
||||
<g id="node5" class="node">
|
||||
<title>u4</title>
|
||||
<ellipse fill="#ffbbbb" stroke="black" stroke-width="0" cx="427.39" cy="-269" rx="39.79" ry="18"/>
|
||||
<text text-anchor="middle" x="427.39" y="-265.3" font-family="Times-Roman" font-size="14.00">Optics</text>
|
||||
</g>
|
||||
<!-- u4->u3 -->
|
||||
<g id="edge18" class="edge">
|
||||
<title>u4->u3</title>
|
||||
<path fill="none" stroke="black" d="M449.04,-253.83C464.95,-243.42 486.78,-229.15 504.37,-217.64"/>
|
||||
<polygon fill="black" stroke="black" points="506.68,-220.31 513.13,-211.91 502.85,-214.45 506.68,-220.31"/>
|
||||
</g>
|
||||
<!-- u6 -->
|
||||
<g id="node12" class="node">
|
||||
<title>u6</title>
|
||||
<ellipse fill="#bbffff" stroke="black" stroke-width="0" cx="855.39" cy="-435" rx="64.19" ry="18"/>
|
||||
<text text-anchor="middle" x="855.39" y="-431.3" font-family="Times-Roman" font-size="14.00">MegaParsec</text>
|
||||
</g>
|
||||
<!-- u5->u6 -->
|
||||
<g id="edge19" class="edge">
|
||||
<title>u5->u6</title>
|
||||
<path fill="none" stroke="black" d="M566.7,-284.68C579.52,-295.01 597.75,-308.62 615.39,-318 624.58,-322.89 630.09,-318.59 637.39,-326 662.15,-351.13 635.32,-379.63 663.39,-401 674.37,-409.36 773.88,-406.14 787.39,-409 795.7,-410.76 804.37,-413.33 812.61,-416.16"/>
|
||||
<polygon fill="black" stroke="black" points="811.46,-419.47 822.06,-419.57 813.84,-412.88 811.46,-419.47"/>
|
||||
</g>
|
||||
<!-- u7 -->
|
||||
<g id="node13" class="node">
|
||||
<title>u7</title>
|
||||
<ellipse fill="#bbffff" stroke="black" stroke-width="0" cx="828.39" cy="-197" rx="44.39" ry="18"/>
|
||||
<text text-anchor="middle" x="828.39" y="-193.3" font-family="Times-Roman" font-size="14.00">Prelude</text>
|
||||
</g>
|
||||
<!-- u5->u7 -->
|
||||
<g id="edge20" class="edge">
|
||||
<title>u5->u7</title>
|
||||
<path fill="none" stroke="black" d="M567.9,-253.71C573.85,-249.71 580.65,-245.72 587.39,-243 648.94,-218.19 724.91,-206.91 774.9,-201.88"/>
|
||||
<polygon fill="black" stroke="black" points="775.54,-205.33 785.16,-200.9 774.87,-198.36 775.54,-205.33"/>
|
||||
</g>
|
||||
<!-- u9 -->
|
||||
<g id="node8" class="node">
|
||||
<title>u9</title>
|
||||
<ellipse fill="#ffbbff" stroke="black" stroke-width="0" cx="936.39" cy="-269" rx="51.19" ry="18"/>
|
||||
<text text-anchor="middle" x="936.39" y="-265.3" font-family="Times-Roman" font-size="14.00">Common</text>
|
||||
</g>
|
||||
<!-- u12->u9 -->
|
||||
<g id="edge30" class="edge">
|
||||
<title>u12->u9</title>
|
||||
<path fill="none" stroke="black" d="M925.36,-333.82C927.2,-323.19 929.6,-309.31 931.69,-297.2"/>
|
||||
<polygon fill="black" stroke="black" points="935.17,-297.6 933.42,-287.15 928.27,-296.41 935.17,-297.6"/>
|
||||
</g>
|
||||
<!-- u9->u7 -->
|
||||
<g id="edge31" class="edge">
|
||||
<title>u9->u7</title>
|
||||
<path fill="none" stroke="black" d="M912.96,-252.81C897.32,-242.68 876.58,-229.24 859.56,-218.2"/>
|
||||
<polygon fill="black" stroke="black" points="861.33,-215.18 851.04,-212.68 857.53,-221.06 861.33,-215.18"/>
|
||||
</g>
|
||||
<!-- u10 -->
|
||||
<g id="node9" class="node">
|
||||
<title>u10</title>
|
||||
<ellipse fill="#77ff77" stroke="black" stroke-width="0" cx="828.39" cy="-50" rx="27" ry="18"/>
|
||||
<text text-anchor="middle" x="828.39" y="-46.3" font-family="Times-Roman" font-size="14.00">QQ</text>
|
||||
</g>
|
||||
<!-- u16 -->
|
||||
<g id="node10" class="node">
|
||||
<title>u16</title>
|
||||
<ellipse fill="#ffff77" stroke="black" stroke-width="0" cx="1001.39" cy="-435" rx="27" ry="18"/>
|
||||
<text text-anchor="middle" x="1001.39" y="-431.3" font-family="Times-Roman" font-size="14.00">QQ</text>
|
||||
</g>
|
||||
<!-- u15 -->
|
||||
<g id="node11" class="node">
|
||||
<title>u15</title>
|
||||
<ellipse fill="#ffffbb" stroke="black" stroke-width="2" cx="1103.39" cy="-435" rx="30.59" ry="18"/>
|
||||
<text text-anchor="middle" x="1103.39" y="-431.3" font-family="Times-Roman" font-size="14.00">Utils</text>
|
||||
</g>
|
||||
<!-- u15->u12 -->
|
||||
<g id="edge22" class="edge">
|
||||
<title>u15->u12</title>
|
||||
<path fill="none" stroke="black" d="M1080.91,-422.68C1072.07,-418.31 1061.8,-413.33 1052.39,-409 1019.33,-393.79 981.02,-377.44 954.59,-366.35"/>
|
||||
<polygon fill="black" stroke="black" points="955.66,-363.01 945.08,-362.38 952.96,-369.47 955.66,-363.01"/>
|
||||
</g>
|
||||
<!-- u15->u11 -->
|
||||
<g id="edge21" class="edge">
|
||||
<title>u15->u11</title>
|
||||
<path fill="none" stroke="black" d="M1082.81,-421.48C1073.8,-416.65 1062.9,-411.66 1052.39,-409 1009.49,-398.14 893.64,-419.41 853.39,-401 842.1,-395.84 832.28,-386.4 824.72,-377.25"/>
|
||||
<polygon fill="black" stroke="black" points="827.3,-374.87 818.44,-369.07 821.75,-379.13 827.3,-374.87"/>
|
||||
</g>
|
||||
<!-- u6->u3 -->
|
||||
<g id="edge23" class="edge">
|
||||
<title>u6->u3</title>
|
||||
<path fill="none" stroke="black" d="M817.86,-420.3C799.34,-413.36 779.12,-405.48 770.39,-401 716.1,-373.14 711.12,-350.84 655.39,-326 642.79,-320.38 635.87,-326.98 625.39,-318 597.74,-294.3 614.8,-271.71 592.39,-243 584.81,-233.29 574.68,-224.49 565.01,-217.31"/>
|
||||
<polygon fill="black" stroke="black" points="566.89,-214.35 556.71,-211.43 562.85,-220.06 566.89,-214.35"/>
|
||||
</g>
|
||||
<!-- u8 -->
|
||||
<g id="node14" class="node">
|
||||
<title>u8</title>
|
||||
<ellipse fill="#bbffff" stroke="black" stroke-width="0" cx="828.39" cy="-125" rx="42.49" ry="18"/>
|
||||
<text text-anchor="middle" x="828.39" y="-121.3" font-family="Times-Roman" font-size="14.00">Logger</text>
|
||||
</g>
|
||||
<!-- u7->u8 -->
|
||||
<g id="edge25" class="edge">
|
||||
<title>u7->u8</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M828.39,-178.7C828.39,-170.98 828.39,-161.71 828.39,-153.11"/>
|
||||
<polygon fill="black" stroke="black" points="831.89,-153.1 828.39,-143.1 824.89,-153.1 831.89,-153.1"/>
|
||||
</g>
|
||||
<!-- u2 -->
|
||||
<g id="node17" class="node">
|
||||
<title>u2</title>
|
||||
<ellipse fill="#ffffbb" stroke="black" stroke-width="0" cx="696.39" cy="-269" rx="37.89" ry="18"/>
|
||||
<text text-anchor="middle" x="696.39" y="-265.3" font-family="Times-Roman" font-size="14.00">Errors</text>
|
||||
</g>
|
||||
<!-- u7->u2 -->
|
||||
<g id="edge24" class="edge">
|
||||
<title>u7->u2</title>
|
||||
<path fill="none" stroke="black" d="M802.53,-211.71C781.65,-222.79 752.12,-238.45 729.51,-250.44"/>
|
||||
<polygon fill="black" stroke="black" points="727.8,-247.38 720.6,-255.16 731.07,-253.57 727.8,-247.38"/>
|
||||
</g>
|
||||
<!-- u8->u4 -->
|
||||
<g id="edge26" class="edge">
|
||||
<title>u8->u4</title>
|
||||
<path fill="none" stroke="black" d="M786.3,-127.22C706.73,-130.23 537.84,-140.15 489.39,-171 463.54,-187.46 446.42,-218.99 436.84,-241.64"/>
|
||||
<polygon fill="black" stroke="black" points="433.54,-240.45 433.08,-251.04 440.04,-243.06 433.54,-240.45"/>
|
||||
</g>
|
||||
<!-- u8->u9 -->
|
||||
<g id="edge27" class="edge">
|
||||
<title>u8->u9</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M849.03,-140.76C859.52,-148.9 872,-159.65 881.39,-171 899.5,-192.89 914.92,-221.56 924.79,-242.04"/>
|
||||
<polygon fill="black" stroke="black" points="921.62,-243.54 929.04,-251.1 927.96,-240.56 921.62,-243.54"/>
|
||||
</g>
|
||||
<!-- u8->u10 -->
|
||||
<g id="edge28" class="edge">
|
||||
<title>u8->u10</title>
|
||||
<path fill="none" stroke="black" d="M828.39,-106.7C828.39,-98.25 828.39,-87.87 828.39,-78.37"/>
|
||||
<polygon fill="black" stroke="black" points="831.89,-78.18 828.39,-68.18 824.89,-78.18 831.89,-78.18"/>
|
||||
</g>
|
||||
<!-- u11->u5 -->
|
||||
<g id="edge29" class="edge">
|
||||
<title>u11->u5</title>
|
||||
<path fill="none" stroke="black" d="M781.07,-346.57C749.06,-341.43 694.42,-332.79 647.39,-326 620.76,-322.16 610.78,-331.29 587.39,-318 577.83,-312.56 569.78,-303.68 563.6,-295.02"/>
|
||||
<polygon fill="black" stroke="black" points="566.46,-293 558.04,-286.57 560.61,-296.85 566.46,-293"/>
|
||||
</g>
|
||||
<!-- u0 -->
|
||||
<g id="node16" class="node">
|
||||
<title>u0</title>
|
||||
<ellipse fill="#bbffbb" stroke="black" stroke-width="2" cx="840.39" cy="-541" rx="42.49" ry="18"/>
|
||||
<text text-anchor="middle" x="840.39" y="-537.3" font-family="Times-Roman" font-size="14.00">GHCup</text>
|
||||
</g>
|
||||
<!-- u0->u1 -->
|
||||
<g id="edge4" class="edge">
|
||||
<title>u0->u1</title>
|
||||
<path fill="none" stroke="black" d="M798.15,-540.08C733.62,-539.53 614.12,-535.65 577.39,-515 556.17,-503.07 540.32,-480.02 530.42,-461.88"/>
|
||||
<polygon fill="black" stroke="black" points="533.49,-460.2 525.79,-452.93 527.27,-463.42 533.49,-460.2"/>
|
||||
</g>
|
||||
<!-- u0->u16 -->
|
||||
<g id="edge6" class="edge">
|
||||
<title>u0->u16</title>
|
||||
<path fill="none" stroke="black" d="M881.32,-536.43C914.21,-532.8 957.04,-526.09 970.39,-515 985.87,-502.13 993.66,-480.49 997.55,-463.11"/>
|
||||
<polygon fill="black" stroke="black" points="1001.06,-463.44 999.51,-452.96 994.18,-462.12 1001.06,-463.44"/>
|
||||
</g>
|
||||
<!-- u0->u15 -->
|
||||
<g id="edge5" class="edge">
|
||||
<title>u0->u15</title>
|
||||
<path fill="none" stroke="black" d="M882.83,-539.21C936.42,-537.51 1024.95,-532.11 1052.39,-515 1071.91,-502.83 1085.39,-480.12 1093.57,-462.17"/>
|
||||
<polygon fill="black" stroke="black" points="1096.87,-463.35 1097.57,-452.78 1090.43,-460.6 1096.87,-463.35"/>
|
||||
</g>
|
||||
<!-- u14 -->
|
||||
<g id="node19" class="node">
|
||||
<title>u14</title>
|
||||
<ellipse fill="#ffffbb" stroke="black" stroke-width="0" cx="680.39" cy="-435" rx="48.19" ry="18"/>
|
||||
<text text-anchor="middle" x="680.39" y="-431.3" font-family="Times-Roman" font-size="14.00">Platform</text>
|
||||
</g>
|
||||
<!-- u0->u14 -->
|
||||
<g id="edge3" class="edge">
|
||||
<title>u0->u14</title>
|
||||
<path fill="none" stroke="black" d="M801.74,-533.4C786.24,-529.61 768.7,-523.78 754.39,-515 731.68,-501.06 711.42,-478.33 697.87,-460.82"/>
|
||||
<polygon fill="black" stroke="black" points="700.58,-458.59 691.78,-452.7 694.98,-462.8 700.58,-458.59"/>
|
||||
</g>
|
||||
<!-- u2->u3 -->
|
||||
<g id="edge7" class="edge">
|
||||
<title>u2->u3</title>
|
||||
<path fill="none" stroke="black" d="M669.27,-256.28C642.05,-244.52 599.95,-226.33 570.04,-213.4"/>
|
||||
<polygon fill="black" stroke="black" points="571.35,-210.16 560.79,-209.41 568.58,-216.59 571.35,-210.16"/>
|
||||
</g>
|
||||
<!-- u13->u3 -->
|
||||
<g id="edge8" class="edge">
|
||||
<title>u13->u3</title>
|
||||
<path fill="none" stroke="black" d="M186.09,-260.84C259.14,-247.66 414.32,-219.66 490.43,-205.93"/>
|
||||
<polygon fill="black" stroke="black" points="491.41,-209.31 500.63,-204.09 490.17,-202.42 491.41,-209.31"/>
|
||||
</g>
|
||||
<!-- u14->u5 -->
|
||||
<g id="edge9" class="edge">
|
||||
<title>u14->u5</title>
|
||||
<path fill="none" stroke="black" d="M656.5,-419.22C649.64,-414.1 642.62,-407.9 637.39,-401 615.71,-372.38 627.41,-355.8 607.39,-326 598.66,-313.01 586.48,-300.68 575.54,-290.91"/>
|
||||
<polygon fill="black" stroke="black" points="577.72,-288.16 567.86,-284.28 573.14,-293.46 577.72,-288.16"/>
|
||||
</g>
|
||||
<!-- u14->u12 -->
|
||||
<g id="edge10" class="edge">
|
||||
<title>u14->u12</title>
|
||||
<path fill="none" stroke="black" d="M711.94,-421.27C724.88,-416.59 740.15,-411.77 754.39,-409 784.33,-403.18 865.04,-416.36 891.39,-401 900.07,-395.94 906.74,-387.36 911.63,-378.84"/>
|
||||
<polygon fill="black" stroke="black" points="914.82,-380.3 916.24,-369.8 908.58,-377.12 914.82,-380.3"/>
|
||||
</g>
|
||||
<!-- u18 -->
|
||||
<g id="node20" class="node">
|
||||
<title>u18</title>
|
||||
<ellipse fill="#ffffbb" stroke="black" stroke-width="0" cx="146.39" cy="-352" rx="73.39" ry="18"/>
|
||||
<text text-anchor="middle" x="146.39" y="-348.3" font-family="Times-Roman" font-size="14.00">Requirements</text>
|
||||
</g>
|
||||
<!-- u18->u5 -->
|
||||
<g id="edge12" class="edge">
|
||||
<title>u18->u5</title>
|
||||
<path fill="none" stroke="black" d="M192.35,-337.85C210.3,-333.27 231.16,-328.62 250.39,-326 300.18,-319.2 428.51,-333.26 476.39,-318 493.93,-312.41 511.26,-301.32 524.62,-291.22"/>
|
||||
<polygon fill="black" stroke="black" points="527.1,-293.72 532.79,-284.78 522.77,-288.22 527.1,-293.72"/>
|
||||
</g>
|
||||
<!-- u18->u13 -->
|
||||
<g id="edge11" class="edge">
|
||||
<title>u18->u13</title>
|
||||
<path fill="none" stroke="black" d="M146.39,-333.82C146.39,-323.19 146.39,-309.31 146.39,-297.2"/>
|
||||
<polygon fill="black" stroke="black" points="149.89,-297.15 146.39,-287.15 142.89,-297.15 149.89,-297.15"/>
|
||||
</g>
|
||||
<!-- u20 -->
|
||||
<g id="node21" class="node">
|
||||
<title>u20</title>
|
||||
<ellipse fill="#bbffbb" stroke="black" stroke-width="0" cx="840.39" cy="-688" rx="32.49" ry="18"/>
|
||||
<text text-anchor="middle" x="840.39" y="-684.3" font-family="Times-Roman" font-size="14.00">Main</text>
|
||||
</g>
|
||||
<!-- u21 -->
|
||||
<g id="node22" class="node">
|
||||
<title>u21</title>
|
||||
<ellipse fill="#bbffbb" stroke="black" stroke-width="0" cx="840.39" cy="-616" rx="46.29" ry="18"/>
|
||||
<text text-anchor="middle" x="840.39" y="-612.3" font-family="Times-Roman" font-size="14.00">Validate</text>
|
||||
</g>
|
||||
<!-- u20->u21 -->
|
||||
<g id="edge1" class="edge">
|
||||
<title>u20->u21</title>
|
||||
<path fill="none" stroke="black" d="M840.39,-669.7C840.39,-661.98 840.39,-652.71 840.39,-644.11"/>
|
||||
<polygon fill="black" stroke="black" points="843.89,-644.1 840.39,-634.1 836.89,-644.1 843.89,-644.1"/>
|
||||
</g>
|
||||
<!-- u21->u0 -->
|
||||
<g id="edge2" class="edge">
|
||||
<title>u21->u0</title>
|
||||
<path fill="none" stroke="black" d="M840.39,-597.7C840.39,-589.25 840.39,-578.87 840.39,-569.37"/>
|
||||
<polygon fill="black" stroke="black" points="843.89,-569.18 840.39,-559.18 836.89,-569.18 843.89,-569.18"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 19 KiB |
7
docs/os-freebsd.svg
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Svg Vector Icons : http://www.onlinewebfonts.com/icon -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 1000 1000" enable-background="new 0 0 1000 1000" xml:space="preserve">
|
||||
<metadata> Svg Vector Icons : http://www.onlinewebfonts.com/icon </metadata>
|
||||
<g><path d="M81.5,647.7C11,409.2,148.6,158.9,388.6,88.9c106.5-31.1,215.5-21.4,309.8,19.8c-4.9,6.9-9.5,14-13.7,21c-46.1-10.7-81.4,3.8-90.2,43.3c-13.9,62.1,42.9,162.8,126.6,224.7c83.7,61.9,162.9,61.7,176.8-0.4c3.5-15.9,2.5-34.4-2.5-54.1c9.7-5.8,19.2-12.3,28.6-19.3c10.9,22.2,20,45.6,27.3,70.1c70.5,238.4-67.1,488.8-307.1,558.8C403.9,1022.8,151.9,886.1,81.5,647.7L81.5,647.7z M667.1,204.7c0.4-0.4,0.7-0.7,1-1.1C776.9,92.3,912.3,26.4,970.4,56.4c58.1,30.1-25.5,176.7-91.7,256.3c-20.1,20.6-41.2,39.7-62.5,56.8C742.2,343.2,686.1,282.8,667.1,204.7L667.1,204.7z M11,108.5C0.7,28.8,68.9,4.9,163.2,55.2c22.4,11.9,44.3,27,64.7,44.1c-56.2,38.6-104.5,90.4-139.5,154C46.4,206.7,16.9,153.5,11,108.5L11,108.5z"/></g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
69
docs/os-linux.svg
Normal file
|
After Width: | Height: | Size: 14 KiB |
143
docs/os-osx.svg
Normal file
@@ -0,0 +1,143 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
version="1.0"
|
||||
width="800"
|
||||
height="950"
|
||||
id="svg2">
|
||||
<defs
|
||||
id="defs4">
|
||||
<linearGradient
|
||||
id="linearGradient3784">
|
||||
<stop
|
||||
id="stop3786"
|
||||
style="stop-color:#ffffff;stop-opacity:1"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop3788"
|
||||
style="stop-color:#888888;stop-opacity:1"
|
||||
offset="1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3776">
|
||||
<stop
|
||||
id="stop3778"
|
||||
style="stop-color:#ffffff;stop-opacity:1"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop3780"
|
||||
style="stop-color:#ffffff;stop-opacity:0"
|
||||
offset="1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3754">
|
||||
<stop
|
||||
id="stop3756"
|
||||
style="stop-color:#ffffff;stop-opacity:1"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop3758"
|
||||
style="stop-color:#ffffff;stop-opacity:0"
|
||||
offset="1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3734">
|
||||
<stop
|
||||
id="stop3736"
|
||||
style="stop-color:#6c6d6f;stop-opacity:1"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop3738"
|
||||
style="stop-color:#010101;stop-opacity:1"
|
||||
offset="1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
x1="581.96649"
|
||||
y1="409.16061"
|
||||
x2="544.40381"
|
||||
y2="311.21347"
|
||||
id="linearGradient3760"
|
||||
xlink:href="#linearGradient3754"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
x1="591.31964"
|
||||
y1="593.75946"
|
||||
x2="587.03571"
|
||||
y2="434.31064"
|
||||
id="linearGradient3764"
|
||||
xlink:href="#linearGradient3734"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
x1="591.31964"
|
||||
y1="593.75946"
|
||||
x2="587.03571"
|
||||
y2="434.31064"
|
||||
id="linearGradient3773"
|
||||
xlink:href="#linearGradient3734"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(-2.7999999e-6,-5.0000001e-6)" />
|
||||
<linearGradient
|
||||
x1="592.88464"
|
||||
y1="409.21036"
|
||||
x2="572.06653"
|
||||
y2="317.52728"
|
||||
id="linearGradient3782"
|
||||
xlink:href="#linearGradient3776"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(4.1074798,0,0,4.1074798,-2012.1445,-1474.6712)" />
|
||||
<linearGradient
|
||||
x1="621.8504"
|
||||
y1="527.79108"
|
||||
x2="575.15466"
|
||||
y2="358.30902"
|
||||
id="linearGradient3790"
|
||||
xlink:href="#linearGradient3784"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
x1="591.31964"
|
||||
y1="593.75946"
|
||||
x2="587.03571"
|
||||
y2="434.31064"
|
||||
id="linearGradient3796"
|
||||
xlink:href="#linearGradient3734"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
x1="591.31964"
|
||||
y1="593.75946"
|
||||
x2="587.03571"
|
||||
y2="434.31064"
|
||||
id="linearGradient3813"
|
||||
xlink:href="#linearGradient3734"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(4.1074798,0,0,4.1074798,-2012.1445,-1474.6712)" />
|
||||
<linearGradient
|
||||
x1="621.8504"
|
||||
y1="527.79108"
|
||||
x2="575.15466"
|
||||
y2="358.30902"
|
||||
id="linearGradient3815"
|
||||
xlink:href="#linearGradient3784"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(4.1074798,0,0,4.1074798,-2012.1445,-1474.6712)" />
|
||||
</defs>
|
||||
<path
|
||||
d="M -1763.2143,1058.9693 L -1763.2143,950.04075 L -1724.2857,1040.5765 L -1685.3571,950.04075 L -1685.3571,1058.9693"
|
||||
id="path3199"
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
d="M 9.2490229,7.8722656 C 9.0747426,10.220019 9.5551534,12.587324 10.789328,14.675279 L 283.03823,474.32796 L 15.153526,926.66418 C 13.0537,930.26743 13.090092,934.72063 15.153526,938.34483 C 17.216918,941.9691 20.995183,944.21594 25.165508,944.24933 L 230.41114,944.24933 C 234.53312,944.22267 238.33677,942.02829 240.42312,938.47319 L 399.07452,670.58848 L 557.72593,938.47319 C 559.81228,942.02829 563.61593,944.22267 567.73791,944.24933 L 773.1119,944.24933 C 777.28223,944.21594 781.06049,941.96906 783.12389,938.34483 C 785.18744,934.72067 785.22371,930.26743 783.12389,926.66418 L 515.23918,474.32796 L 787.35972,14.675279 C 788.58462,12.5734 788.96226,10.218047 788.77167,7.8722656 L 559.13787,7.8722656 L 399.07452,278.19578 L 239.01118,7.8722656 L 9.2490229,7.8722656 z"
|
||||
id="path3762"
|
||||
style="fill:url(#linearGradient3815);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1" />
|
||||
<path
|
||||
d="M 20.80131,8.7707768 L 296.51589,474.32796 L 25.165508,932.56868 L 230.41114,932.56868 L 399.07452,647.74063 L 567.73791,932.56868 L 773.1119,932.56868 L 501.76152,474.32796 L 777.34774,8.7707768 L 572.10211,8.7707768 L 399.07452,301.04364 L 226.04694,8.7707768 L 20.80131,8.7707768 z"
|
||||
id="path3705"
|
||||
style="fill:url(#linearGradient3813);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
d="M 20.80131,8.7707768 L 201.9155,314.64967 C 251.61658,285.27827 303.41256,257.12462 357.61466,230.95977 L 226.04694,8.7707768 L 20.80131,8.7707768 z M 572.10211,8.7707768 L 470.05691,181.15657 C 548.90117,149.37671 632.73447,122.22713 722.53856,101.31743 L 777.34774,8.7707768 L 572.10211,8.7707768 z"
|
||||
id="path3771"
|
||||
style="opacity:0.47619048;fill:url(#linearGradient3782);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.0 KiB |
18
docs/os-windows.svg
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) by Marsupilami -->
|
||||
<svg
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
version="1.1"
|
||||
width="766"
|
||||
height="768"
|
||||
viewBox="-2.61977004 -2.61977004 92.56520808 92.83416708"
|
||||
id="svg8375">
|
||||
<defs
|
||||
id="defs8377" />
|
||||
<path
|
||||
d="M 0,12.40183 35.68737,7.5416 35.70297,41.96435 0.03321,42.16748 z m 35.67037,33.52906 0.0277,34.45332 -35.66989,-4.9041 -0.002,-29.77972 z M 39.99644,6.90595 87.31462,0 l 0,41.527 -47.31818,0.37565 z M 87.32567,46.25471 87.31457,87.59463 39.9964,80.91625 39.9301,46.17767 z"
|
||||
id="path13" />
|
||||
</svg>
|
||||
<!-- version: 20110311, original size: 87.325668 87.594627, border: 3% -->
|
||||
|
After Width: | Height: | Size: 861 B |
121
ghcup.cabal
@@ -1,28 +1,32 @@
|
||||
cabal-version: 3.0
|
||||
name: ghcup
|
||||
version: 0.1.15.2
|
||||
license: LGPL-3.0-only
|
||||
license-file: LICENSE
|
||||
copyright: Julian Ospald 2020
|
||||
maintainer: hasufell@posteo.de
|
||||
author: Julian Ospald
|
||||
homepage: https://gitlab.haskell.org/haskell/ghcup-hs
|
||||
bug-reports: https://gitlab.haskell.org/haskell/ghcup-hs/issues
|
||||
synopsis: ghc toolchain installer
|
||||
cabal-version: 3.0
|
||||
name: ghcup
|
||||
version: 0.1.17.2
|
||||
license: LGPL-3.0-only
|
||||
license-file: LICENSE
|
||||
copyright: Julian Ospald 2020
|
||||
maintainer: hasufell@posteo.de
|
||||
author: Julian Ospald
|
||||
homepage: https://gitlab.haskell.org/haskell/ghcup-hs
|
||||
bug-reports: https://gitlab.haskell.org/haskell/ghcup-hs/issues
|
||||
synopsis: ghc toolchain installer
|
||||
description:
|
||||
A rewrite of the shell script ghcup, for providing
|
||||
a more stable user experience and exposing an API.
|
||||
|
||||
category: System
|
||||
build-type: Simple
|
||||
category: System
|
||||
build-type: Simple
|
||||
extra-doc-files:
|
||||
data/config.yaml
|
||||
data/metadata/ghcup-0.0.4.yaml
|
||||
data/metadata/ghcup-0.0.5.yaml
|
||||
data/metadata/ghcup-0.0.6.yaml
|
||||
CHANGELOG.md
|
||||
config.yaml
|
||||
ghcup-0.0.4.yaml
|
||||
ghcup-0.0.5.yaml
|
||||
HACKING.md
|
||||
README.md
|
||||
RELEASING.md
|
||||
|
||||
extra-source-files:
|
||||
data/build_mk/cross
|
||||
data/build_mk/default
|
||||
test/golden/GHCupInfo.json
|
||||
|
||||
source-repository head
|
||||
type: git
|
||||
@@ -42,13 +46,6 @@ flag internal-downloader
|
||||
default: False
|
||||
manual: True
|
||||
|
||||
flag tar
|
||||
description:
|
||||
Use tar-bytestring instead of libarchive.
|
||||
|
||||
default: False
|
||||
manual: True
|
||||
|
||||
library
|
||||
exposed-modules:
|
||||
GHCup
|
||||
@@ -84,7 +81,6 @@ library
|
||||
QuasiQuotes
|
||||
RecordWildCards
|
||||
ScopedTypeVariables
|
||||
Strict
|
||||
StrictData
|
||||
TupleSections
|
||||
TypeApplications
|
||||
@@ -102,27 +98,24 @@ library
|
||||
, base16-bytestring >=0.1.1.6 && <1.1
|
||||
, binary ^>=0.8.6.0
|
||||
, bytestring ^>=0.10
|
||||
, Cabal ^>=3.6.2.0
|
||||
, case-insensitive ^>=1.2.1.0
|
||||
, casing ^>=0.1.4.1
|
||||
, concurrent-output ^>=1.10.11
|
||||
, containers ^>=0.6
|
||||
, cryptohash-sha256 ^>=0.11.101.0
|
||||
, deepseq ^>=1.4.4.0
|
||||
, directory ^>=1.3.6.0
|
||||
, disk-free-space ^>=0.1.0.1
|
||||
, extra ^>=1.7.9
|
||||
, filepath ^>=1.4.2.1
|
||||
, generics-sop ^>=0.5
|
||||
, haskus-utils-types ^>=1.5
|
||||
, haskus-utils-variant >=3.0 && <3.2
|
||||
, HsYAML-aeson ^>=0.2.0.0
|
||||
, libarchive ^>=3.0.3.0
|
||||
, lzma-static ^>=5.2.5.3
|
||||
, megaparsec >=8.0.0 && <9.1
|
||||
, monad-logger ^>=0.3.31
|
||||
, mtl ^>=2.2
|
||||
, optics >=0.2 && <0.5
|
||||
, optics-vl ^>=0.2
|
||||
, optics ^>=0.4
|
||||
, os-release ^>=1.0.0
|
||||
, parsec ^>=3.1
|
||||
, pretty ^>=1.1.3.1
|
||||
, pretty-terminal ^>=0.1.0.0
|
||||
, regex-posix ^>=0.96
|
||||
@@ -131,7 +124,6 @@ library
|
||||
, safe-exceptions ^>=0.1
|
||||
, split ^>=0.2.3.4
|
||||
, strict-base ^>=0.4
|
||||
, string-interpolate >=0.2.0.0 && <0.4
|
||||
, template-haskell >=2.7 && <2.18
|
||||
, temporary ^>=1.3
|
||||
, text ^>=1.2.4.0
|
||||
@@ -140,12 +132,9 @@ library
|
||||
, unliftio-core ^>=0.2.0.1
|
||||
, unordered-containers ^>=0.2.10.0
|
||||
, uri-bytestring ^>=0.3.2.2
|
||||
, utf8-string ^>=1.0
|
||||
, vector ^>=0.12
|
||||
, versions ^>=4.0.1
|
||||
, versions >=4.0.1 && <5.1
|
||||
, word8 ^>=0.1.3
|
||||
, yaml ^>=0.11.4.0
|
||||
, zip ^>=1.7.1
|
||||
, zlib ^>=0.6.2.2
|
||||
|
||||
if (flag(internal-downloader) && !os(windows))
|
||||
@@ -157,13 +146,6 @@ library
|
||||
, io-streams >=1.5.2.1
|
||||
, terminal-progress-bar >=0.4.1
|
||||
|
||||
if flag(tar)
|
||||
cpp-options: -DTAR
|
||||
build-depends: tar
|
||||
|
||||
else
|
||||
build-depends: libarchive ^>=3.0.0.0
|
||||
|
||||
if os(windows)
|
||||
cpp-options: -DIS_WINDOWS
|
||||
other-modules: GHCup.Utils.File.Windows
|
||||
@@ -174,11 +156,13 @@ library
|
||||
, Win32 ^>=2.10
|
||||
|
||||
else
|
||||
other-modules: GHCup.Utils.File.Posix
|
||||
other-modules:
|
||||
GHCup.Utils.File.Posix
|
||||
System.Console.Terminal.Common
|
||||
System.Console.Terminal.Posix
|
||||
|
||||
build-depends:
|
||||
, bz2 >=0.5.0.5 && <1.1
|
||||
, hpath-posix ^>=0.13.3
|
||||
, process ^>=1.6.9
|
||||
, unix ^>=2.7
|
||||
, unix-bytestring ^>=0.3.7.3
|
||||
|
||||
@@ -197,7 +181,6 @@ executable ghcup
|
||||
PackageImports
|
||||
RecordWildCards
|
||||
ScopedTypeVariables
|
||||
Strict
|
||||
StrictData
|
||||
TupleSections
|
||||
|
||||
@@ -206,14 +189,20 @@ executable ghcup
|
||||
-fwarn-incomplete-record-updates -threaded
|
||||
|
||||
build-depends:
|
||||
, aeson >=1.4 && <1.6
|
||||
, aeson-pretty ^>=0.8.8
|
||||
, async ^>=2.2.3
|
||||
, base >=4.13 && <5
|
||||
, bytestring ^>=0.10
|
||||
, cabal-plan ^>=0.7.2
|
||||
, containers ^>=0.6
|
||||
, deepseq ^>=1.4
|
||||
, filepath ^>=1.4.2.1
|
||||
, ghcup
|
||||
, haskus-utils-variant >=3.0 && <3.2
|
||||
, HsYAML-aeson ^>=0.2.0.0
|
||||
, libarchive ^>=3.0.3.0
|
||||
, megaparsec >=8.0.0 && <9.1
|
||||
, monad-logger ^>=0.3.31
|
||||
, mtl ^>=2.2
|
||||
, optparse-applicative >=0.15.1.0 && <0.17
|
||||
, pretty ^>=1.1.3.1
|
||||
@@ -221,12 +210,11 @@ executable ghcup
|
||||
, resourcet ^>=1.2.2
|
||||
, safe ^>=0.3.18
|
||||
, safe-exceptions ^>=0.1
|
||||
, string-interpolate >=0.2.0.0 && <0.4
|
||||
, template-haskell >=2.7 && <2.18
|
||||
, text ^>=1.2.4.0
|
||||
, uri-bytestring ^>=0.3.2.2
|
||||
, utf8-string ^>=1.0
|
||||
, versions ^>=4.0.1
|
||||
, versions >=4.0.1 && <5.1
|
||||
|
||||
if flag(internal-downloader)
|
||||
cpp-options: -DINTERNAL_DOWNLOADER
|
||||
@@ -235,7 +223,7 @@ executable ghcup
|
||||
cpp-options: -DBRICK
|
||||
other-modules: BrickMain
|
||||
build-depends:
|
||||
, brick >=0.5 && <0.62
|
||||
, brick ^>=0.64
|
||||
, transformers ^>=0.5
|
||||
, vector ^>=0.12
|
||||
, vty >=5.28.2 && <5.34
|
||||
@@ -243,12 +231,6 @@ executable ghcup
|
||||
if os(windows)
|
||||
cpp-options: -DIS_WINDOWS
|
||||
|
||||
if flag(tar)
|
||||
cpp-options: -DTAR
|
||||
|
||||
else
|
||||
build-depends: libarchive ^>=3.0.0.0
|
||||
|
||||
executable ghcup-gen
|
||||
main-is: Main.hs
|
||||
hs-source-dirs: app/ghcup-gen
|
||||
@@ -263,7 +245,6 @@ executable ghcup-gen
|
||||
QuasiQuotes
|
||||
RecordWildCards
|
||||
ScopedTypeVariables
|
||||
Strict
|
||||
StrictData
|
||||
TupleSections
|
||||
TypeApplications
|
||||
@@ -281,32 +262,24 @@ executable ghcup-gen
|
||||
, filepath ^>=1.4.2.1
|
||||
, ghcup
|
||||
, haskus-utils-variant >=3.0 && <3.2
|
||||
, monad-logger ^>=0.3.31
|
||||
, HsYAML-aeson ^>=0.2.0.0
|
||||
, libarchive ^>=3.0.3.0
|
||||
, mtl ^>=2.2
|
||||
, optics >=0.2 && <0.5
|
||||
, optics ^>=0.4
|
||||
, optparse-applicative >=0.15.1.0 && <0.17
|
||||
, pretty ^>=1.1.3.1
|
||||
, pretty-terminal ^>=0.1.0.0
|
||||
, regex-posix ^>=0.96
|
||||
, resourcet ^>=1.2.2
|
||||
, safe-exceptions ^>=0.1
|
||||
, string-interpolate >=0.2.0.0 && <0.4
|
||||
, text ^>=1.2.4.0
|
||||
, transformers ^>=0.5
|
||||
, uri-bytestring ^>=0.3.2.2
|
||||
, versions ^>=4.0.1
|
||||
, yaml ^>=0.11.4.0
|
||||
|
||||
if flag(tar)
|
||||
cpp-options: -DTAR
|
||||
build-depends: tar
|
||||
|
||||
else
|
||||
build-depends: libarchive ^>=3.0.0.0
|
||||
, versions >=4.0.1 && <5.1
|
||||
|
||||
test-suite ghcup-test
|
||||
type: exitcode-stdio-1.0
|
||||
main-is: Main.hs
|
||||
build-tool-depends: hspec-discover:hspec-discover -any
|
||||
hs-source-dirs: test
|
||||
other-modules:
|
||||
GHCup.ArbitraryTypes
|
||||
@@ -338,4 +311,4 @@ test-suite ghcup-test
|
||||
, quickcheck-arbitrary-adt ^>=0.3.1.0
|
||||
, text ^>=1.2.4.0
|
||||
, uri-bytestring ^>=0.3.2.2
|
||||
, versions ^>=4.0.1
|
||||
, versions >=4.0.1 && <5.1
|
||||
|
||||
2105
lib/GHCup.hs
@@ -1,10 +1,7 @@
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE DeriveGeneric #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE QuasiQuotes #-}
|
||||
{-# LANGUAGE TemplateHaskell #-}
|
||||
{-# LANGUAGE TypeApplications #-}
|
||||
{-# LANGUAGE TypeFamilies #-}
|
||||
|
||||
@@ -34,10 +31,11 @@ import GHCup.Download.Utils
|
||||
#endif
|
||||
import GHCup.Errors
|
||||
import GHCup.Types
|
||||
import GHCup.Types.JSON ( )
|
||||
import GHCup.Types.Optics
|
||||
import GHCup.Types.JSON ( )
|
||||
import GHCup.Utils.Dirs
|
||||
import GHCup.Utils.File
|
||||
import GHCup.Utils.Logger
|
||||
import GHCup.Utils.Prelude
|
||||
import GHCup.Version
|
||||
|
||||
@@ -47,7 +45,6 @@ import Control.Monad
|
||||
#if !MIN_VERSION_base(4,13,0)
|
||||
import Control.Monad.Fail ( MonadFail )
|
||||
#endif
|
||||
import Control.Monad.Logger
|
||||
import Control.Monad.Reader
|
||||
import Control.Monad.Trans.Resource
|
||||
hiding ( throwM )
|
||||
@@ -55,29 +52,31 @@ import Data.Aeson
|
||||
import Data.Bifunctor
|
||||
import Data.ByteString ( ByteString )
|
||||
#if defined(INTERNAL_DOWNLOADER)
|
||||
import Data.CaseInsensitive ( CI )
|
||||
import Data.CaseInsensitive ( mk )
|
||||
#endif
|
||||
import Data.List.Extra
|
||||
import Data.Maybe
|
||||
import Data.String.Interpolate
|
||||
import Data.List
|
||||
import Data.Time.Clock
|
||||
import Data.Time.Clock.POSIX
|
||||
#if defined(INTERNAL_DOWNLOADER)
|
||||
import Data.Time.Format
|
||||
#endif
|
||||
import Data.Versions
|
||||
import Data.Word8
|
||||
import GHC.IO.Exception
|
||||
import Data.Word8 hiding ( isSpace )
|
||||
import Haskus.Utils.Variant.Excepts
|
||||
#if defined(INTERNAL_DOWNLOADER)
|
||||
import Network.Http.Client hiding ( URL )
|
||||
#endif
|
||||
import Optics
|
||||
import Prelude hiding ( abs
|
||||
, readFile
|
||||
, writeFile
|
||||
)
|
||||
import Safe
|
||||
import System.Directory
|
||||
import System.Environment
|
||||
import System.Exit
|
||||
import System.FilePath
|
||||
import System.IO.Error
|
||||
import System.IO.Temp
|
||||
import Text.PrettyPrint.HughesPJClass ( prettyShow )
|
||||
import URI.ByteString
|
||||
|
||||
import qualified Crypto.Hash.SHA256 as SHA256
|
||||
@@ -85,12 +84,10 @@ import qualified Data.ByteString as B
|
||||
import qualified Data.ByteString.Base16 as B16
|
||||
import qualified Data.ByteString.Lazy as L
|
||||
import qualified Data.Map.Strict as M
|
||||
#if defined(INTERNAL_DOWNLOADER)
|
||||
import qualified Data.CaseInsensitive as CI
|
||||
#endif
|
||||
import qualified Data.Text as T
|
||||
import qualified Data.Text.IO as T
|
||||
import qualified Data.Text.Encoding as E
|
||||
import qualified Data.Yaml as Y
|
||||
import qualified Data.YAML.Aeson as Y
|
||||
|
||||
|
||||
|
||||
@@ -107,32 +104,32 @@ import qualified Data.Yaml as Y
|
||||
getDownloadsF :: ( FromJSONKey Tool
|
||||
, FromJSONKey Version
|
||||
, FromJSON VersionInfo
|
||||
, MonadReader env m
|
||||
, HasSettings env
|
||||
, HasDirs env
|
||||
, MonadIO m
|
||||
, MonadCatch m
|
||||
, MonadLogger m
|
||||
, HasLog env
|
||||
, MonadThrow m
|
||||
, MonadFail m
|
||||
, MonadMask m
|
||||
)
|
||||
=> Settings
|
||||
-> Dirs
|
||||
-> Excepts
|
||||
'[JSONError , DownloadFailed , FileDoesNotExistError]
|
||||
=> Excepts
|
||||
'[DigestError, GPGError, JSONError , DownloadFailed , FileDoesNotExistError]
|
||||
m
|
||||
GHCupInfo
|
||||
getDownloadsF settings@Settings{ urlSource } dirs = do
|
||||
getDownloadsF = do
|
||||
Settings { urlSource } <- lift getSettings
|
||||
case urlSource of
|
||||
GHCupURL -> liftE $ getBase dirs settings
|
||||
(OwnSource url) -> do
|
||||
bs <- reThrowAll DownloadFailed $ downloadBS (downloader settings) url
|
||||
lE' JSONDecodeError $ first show $ Y.decodeEither' (L.toStrict bs)
|
||||
GHCupURL -> liftE $ getBase ghcupURL
|
||||
(OwnSource url) -> liftE $ getBase url
|
||||
(OwnSpec av) -> pure av
|
||||
(AddSource (Left ext)) -> do
|
||||
base <- liftE $ getBase dirs settings
|
||||
base <- liftE $ getBase ghcupURL
|
||||
pure (mergeGhcupInfo base ext)
|
||||
(AddSource (Right uri)) -> do
|
||||
base <- liftE $ getBase dirs settings
|
||||
bsExt <- reThrowAll DownloadFailed $ downloadBS (downloader settings) uri
|
||||
ext <- lE' JSONDecodeError $ first show $ Y.decodeEither' (L.toStrict bsExt)
|
||||
base <- liftE $ getBase ghcupURL
|
||||
ext <- liftE $ getBase uri
|
||||
pure (mergeGhcupInfo base ext)
|
||||
|
||||
where
|
||||
@@ -149,169 +146,165 @@ getDownloadsF settings@Settings{ urlSource } dirs = do
|
||||
in GHCupInfo tr newDownloads newGlobalTools
|
||||
|
||||
|
||||
readFromCache :: (MonadIO m, MonadCatch m, MonadLogger m)
|
||||
=> Dirs
|
||||
-> Excepts '[JSONError, FileDoesNotExistError] m GHCupInfo
|
||||
readFromCache Dirs {..} = do
|
||||
lift $ $(logWarn)
|
||||
[i|Could not get download info, trying cached version (this may not be recent!)|]
|
||||
let path = view pathL' ghcupURL
|
||||
let yaml_file = cacheDir </> (T.unpack . decUTF8Safe . urlBaseName $ path)
|
||||
bs <-
|
||||
handleIO' NoSuchThing
|
||||
(\_ -> throwE $ FileDoesNotExistError yaml_file)
|
||||
$ liftIO
|
||||
$ L.readFile yaml_file
|
||||
lE' JSONDecodeError $ first show $ Y.decodeEither' (L.toStrict bs)
|
||||
yamlFromCache :: (MonadReader env m, HasDirs env) => URI -> m FilePath
|
||||
yamlFromCache uri = do
|
||||
Dirs{..} <- getDirs
|
||||
pure (cacheDir </> (T.unpack . decUTF8Safe . urlBaseName . view pathL' $ uri))
|
||||
|
||||
|
||||
getBase :: (MonadFail m, MonadIO m, MonadCatch m, MonadLogger m)
|
||||
=> Dirs
|
||||
-> Settings
|
||||
-> Excepts '[JSONError , FileDoesNotExistError] m GHCupInfo
|
||||
getBase dirs@Dirs{..} Settings{ downloader } =
|
||||
handleIO (\_ -> readFromCache dirs)
|
||||
$ catchE @_ @'[JSONError, FileDoesNotExistError]
|
||||
(\(DownloadFailed _) -> readFromCache dirs)
|
||||
(reThrowAll @_ @_ @'[JSONError, DownloadFailed] DownloadFailed (smartDl ghcupURL)
|
||||
>>= (liftE . lE' @_ @_ @'[JSONError] JSONDecodeError . first show . Y.decodeEither' . L.toStrict))
|
||||
where
|
||||
etagsFile :: FilePath -> FilePath
|
||||
etagsFile = (<.> "etags")
|
||||
|
||||
|
||||
getBase :: ( MonadReader env m
|
||||
, HasDirs env
|
||||
, HasSettings env
|
||||
, MonadFail m
|
||||
, MonadIO m
|
||||
, MonadCatch m
|
||||
, HasLog env
|
||||
, MonadMask m
|
||||
)
|
||||
=> URI
|
||||
-> Excepts '[GPGError, DigestError, JSONError, FileDoesNotExistError] m GHCupInfo
|
||||
getBase uri = do
|
||||
Settings { noNetwork, downloader } <- lift getSettings
|
||||
|
||||
-- try to download yaml... usually this writes it into cache dir,
|
||||
-- but in some cases not (e.g. when using file://), so we honour
|
||||
-- the return filepath, if any
|
||||
mYaml <- if noNetwork && view (uriSchemeL' % schemeBSL') uri /= "file" -- for file://, let it fall through
|
||||
then pure Nothing
|
||||
else handleIO (\e -> lift (warnCache (displayException e) downloader) >> pure Nothing)
|
||||
. catchE @_ @_ @'[] (\e@(DownloadFailed _) -> lift (warnCache (prettyShow e) downloader) >> pure Nothing)
|
||||
. fmap Just
|
||||
. smartDl
|
||||
$ uri
|
||||
|
||||
-- if we didn't get a filepath from the download, use the cached yaml
|
||||
actualYaml <- maybe (lift $ yamlFromCache uri) pure mYaml
|
||||
yamlContents <- liftIOException doesNotExistErrorType (FileDoesNotExistError actualYaml) $ liftIO $ L.readFile actualYaml
|
||||
lift $ logDebug $ "Decoding yaml at: " <> T.pack actualYaml
|
||||
|
||||
liftE
|
||||
. onE_ (onError actualYaml)
|
||||
. lE' @_ @_ @'[JSONError] JSONDecodeError
|
||||
. first (\(_, e) -> unlines [e, "Consider removing " <> actualYaml <> " manually."])
|
||||
. Y.decode1
|
||||
$ yamlContents
|
||||
where
|
||||
-- On error, remove the etags file and set access time to 0. This should ensure the next invocation
|
||||
-- may re-download and succeed.
|
||||
onError :: (MonadReader env m, HasLog env, MonadMask m, MonadCatch m, MonadIO m) => FilePath -> m ()
|
||||
onError fp = do
|
||||
let efp = etagsFile fp
|
||||
handleIO (\e -> logWarn $ "Couldn't remove file " <> T.pack efp <> ", error was: " <> T.pack (displayException e))
|
||||
(hideError doesNotExistErrorType $ rmFile efp)
|
||||
liftIO $ hideError doesNotExistErrorType $ setAccessTime fp (posixSecondsToUTCTime (fromIntegral @Int 0))
|
||||
|
||||
warnCache :: (MonadReader env m, HasLog env, MonadMask m, MonadCatch m, MonadIO m) => FilePath -> Downloader -> m ()
|
||||
warnCache s downloader' = do
|
||||
let tryDownloder = case downloader' of
|
||||
Curl -> "Wget"
|
||||
Wget -> "Curl"
|
||||
#if defined(INTERNAL_DOWNLOADER)
|
||||
Internal -> "Curl"
|
||||
#endif
|
||||
logWarn $ "Could not get download info, trying cached version (this may not be recent!)" <> "\n" <>
|
||||
"If this problem persists, consider switching downloader via: " <> "\n " <>
|
||||
"ghcup config set downloader " <> tryDownloder
|
||||
logDebug $ "Error was: " <> T.pack s
|
||||
|
||||
-- First check if the json file is in the ~/.ghcup/cache dir
|
||||
-- and check it's access time. If it has been accessed within the
|
||||
-- last 5 minutes, just reuse it.
|
||||
--
|
||||
-- If not, then send a HEAD request and check for modification time.
|
||||
-- Only download the file if the modification time is newer
|
||||
-- than the local file.
|
||||
--
|
||||
-- Always save the local file with the mod time of the remote file.
|
||||
smartDl :: forall m1
|
||||
. ( MonadCatch m1
|
||||
smartDl :: forall m1 env1
|
||||
. ( MonadReader env1 m1
|
||||
, HasDirs env1
|
||||
, HasSettings env1
|
||||
, MonadCatch m1
|
||||
, MonadIO m1
|
||||
, MonadFail m1
|
||||
, MonadLogger m1
|
||||
, HasLog env1
|
||||
, MonadMask m1
|
||||
)
|
||||
=> URI
|
||||
-> Excepts
|
||||
'[ FileDoesNotExistError
|
||||
, HTTPStatusError
|
||||
, URIParseError
|
||||
, UnsupportedScheme
|
||||
, NoLocationHeader
|
||||
, TooManyRedirs
|
||||
, ProcessError
|
||||
'[ DownloadFailed
|
||||
, DigestError
|
||||
, GPGError
|
||||
]
|
||||
m1
|
||||
L.ByteString
|
||||
FilePath
|
||||
smartDl uri' = do
|
||||
let path = view pathL' uri'
|
||||
let json_file = cacheDir </> (T.unpack . decUTF8Safe . urlBaseName $ path)
|
||||
e <- liftIO $ doesFileExist json_file
|
||||
if e
|
||||
then do
|
||||
accessTime <- liftIO $ getAccessTime json_file
|
||||
currentTime <- liftIO getCurrentTime
|
||||
json_file <- lift $ yamlFromCache uri'
|
||||
let scheme = view (uriSchemeL' % schemeBSL') uri'
|
||||
e <- liftIO $ doesFileExist json_file
|
||||
currentTime <- liftIO getCurrentTime
|
||||
Dirs { cacheDir } <- lift getDirs
|
||||
|
||||
-- access time won't work on most linuxes, but we can try regardless
|
||||
if (utcTimeToPOSIXSeconds currentTime - utcTimeToPOSIXSeconds accessTime) > 300
|
||||
then do -- no access in last 5 minutes, re-check upstream mod time
|
||||
getModTime >>= \case
|
||||
Just modTime -> do
|
||||
fileMod <- liftIO $ getModificationTime json_file
|
||||
if modTime > fileMod
|
||||
then dlWithMod modTime json_file
|
||||
else liftIO $ L.readFile json_file
|
||||
Nothing -> do
|
||||
lift $ $(logDebug) [i|Unable to get/parse Last-Modified header|]
|
||||
dlWithoutMod json_file
|
||||
else -- access in less than 5 minutes, re-use file
|
||||
liftIO $ L.readFile json_file
|
||||
else do
|
||||
getModTime >>= \case
|
||||
Just modTime -> dlWithMod modTime json_file
|
||||
Nothing -> do
|
||||
-- although we don't know last-modified, we still save
|
||||
-- it to a file, so we might use it in offline mode
|
||||
lift $ $(logDebug) [i|Unable to get/parse Last-Modified header|]
|
||||
dlWithoutMod json_file
|
||||
-- for local files, let's short-circuit and ignore access time
|
||||
if | scheme == "file" -> liftE $ download uri' Nothing Nothing cacheDir Nothing True
|
||||
| e -> do
|
||||
accessTime <- liftIO $ getAccessTime json_file
|
||||
|
||||
-- access time won't work on most linuxes, but we can try regardless
|
||||
if | ((utcTimeToPOSIXSeconds currentTime - utcTimeToPOSIXSeconds accessTime) > 300) ->
|
||||
-- no access in last 5 minutes, re-check upstream mod time
|
||||
dlWithMod currentTime json_file
|
||||
| otherwise -> pure json_file
|
||||
| otherwise -> dlWithMod currentTime json_file
|
||||
where
|
||||
dlWithMod modTime json_file = do
|
||||
bs <- liftE $ downloadBS downloader uri'
|
||||
liftIO $ writeFileWithModTime modTime json_file bs
|
||||
pure bs
|
||||
dlWithoutMod json_file = do
|
||||
bs <- liftE $ downloadBS downloader uri'
|
||||
liftIO $ hideError doesNotExistErrorType $ rmFile json_file
|
||||
liftIO $ L.writeFile json_file bs
|
||||
liftIO $ setModificationTime json_file (posixSecondsToUTCTime (fromIntegral @Int 0))
|
||||
pure bs
|
||||
let (dir, fn) = splitFileName json_file
|
||||
f <- liftE $ download uri' (Just $ over pathL' (<> ".sig") uri') Nothing dir (Just fn) True
|
||||
liftIO $ setModificationTime f modTime
|
||||
liftIO $ setAccessTime f modTime
|
||||
pure f
|
||||
|
||||
|
||||
getModTime = do
|
||||
#if !defined(INTERNAL_DOWNLOADER)
|
||||
pure Nothing
|
||||
#else
|
||||
headers <-
|
||||
handleIO (\_ -> pure mempty)
|
||||
$ liftE
|
||||
$ ( catchAllE
|
||||
(\_ ->
|
||||
pure mempty :: Excepts '[] m1 (M.Map (CI ByteString) ByteString)
|
||||
)
|
||||
$ getHead uri'
|
||||
)
|
||||
pure $ parseModifiedHeader headers
|
||||
|
||||
parseModifiedHeader :: (M.Map (CI ByteString) ByteString) -> Maybe UTCTime
|
||||
parseModifiedHeader headers =
|
||||
(M.lookup (CI.mk "Last-Modified") headers) >>= \h -> parseTimeM
|
||||
True
|
||||
defaultTimeLocale
|
||||
"%a, %d %b %Y %H:%M:%S %Z"
|
||||
(T.unpack . decUTF8Safe $ h)
|
||||
|
||||
#endif
|
||||
|
||||
writeFileWithModTime :: UTCTime -> FilePath -> L.ByteString -> IO ()
|
||||
writeFileWithModTime utctime path content = do
|
||||
L.writeFile path content
|
||||
setModificationTime path utctime
|
||||
|
||||
|
||||
getDownloadInfo :: Tool
|
||||
getDownloadInfo :: ( MonadReader env m
|
||||
, HasPlatformReq env
|
||||
, HasGHCupInfo env
|
||||
)
|
||||
=> Tool
|
||||
-> Version
|
||||
-- ^ tool version
|
||||
-> PlatformRequest
|
||||
-> GHCupDownloads
|
||||
-> Either NoDownload DownloadInfo
|
||||
getDownloadInfo t v (PlatformRequest a p mv) dls = maybe
|
||||
(Left NoDownload)
|
||||
Right
|
||||
(case p of
|
||||
-- non-musl won't work on alpine
|
||||
Linux Alpine -> with_distro <|> without_distro_ver
|
||||
_ -> with_distro <|> without_distro_ver <|> without_distro
|
||||
)
|
||||
-> Excepts
|
||||
'[NoDownload]
|
||||
m
|
||||
DownloadInfo
|
||||
getDownloadInfo t v = do
|
||||
(PlatformRequest a p mv) <- lift getPlatformReq
|
||||
GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo
|
||||
|
||||
where
|
||||
with_distro = distro_preview id id
|
||||
without_distro_ver = distro_preview id (const Nothing)
|
||||
without_distro = distro_preview (set _Linux UnknownLinux) (const Nothing)
|
||||
let distro_preview f g =
|
||||
let platformVersionSpec =
|
||||
preview (ix t % ix v % viArch % ix a % ix (f p)) dls
|
||||
mv' = g mv
|
||||
in fmap snd
|
||||
. find
|
||||
(\(mverRange, _) -> maybe
|
||||
(isNothing mv')
|
||||
(\range -> maybe False (`versionRange` range) mv')
|
||||
mverRange
|
||||
)
|
||||
. M.toList
|
||||
=<< platformVersionSpec
|
||||
with_distro = distro_preview id id
|
||||
without_distro_ver = distro_preview id (const Nothing)
|
||||
without_distro = distro_preview (set _Linux UnknownLinux) (const Nothing)
|
||||
|
||||
distro_preview f g =
|
||||
let platformVersionSpec =
|
||||
preview (ix t % ix v % viArch % ix a % ix (f p)) dls
|
||||
mv' = g mv
|
||||
in fmap snd
|
||||
. find
|
||||
(\(mverRange, _) -> maybe
|
||||
(isNothing mv')
|
||||
(\range -> maybe False (`versionRange` range) mv')
|
||||
mverRange
|
||||
)
|
||||
. M.toList
|
||||
=<< platformVersionSpec
|
||||
maybe
|
||||
(throwE NoDownload)
|
||||
pure
|
||||
(case p of
|
||||
-- non-musl won't work on alpine
|
||||
Linux Alpine -> with_distro <|> without_distro_ver
|
||||
_ -> with_distro <|> without_distro_ver <|> without_distro
|
||||
)
|
||||
|
||||
|
||||
-- | Tries to download from the given http or https url
|
||||
@@ -321,114 +314,301 @@ getDownloadInfo t v (PlatformRequest a p mv) dls = maybe
|
||||
-- 2. otherwise create a random file
|
||||
--
|
||||
-- The file must not exist.
|
||||
download :: ( MonadMask m
|
||||
download :: ( MonadReader env m
|
||||
, HasSettings env
|
||||
, HasDirs env
|
||||
, MonadMask m
|
||||
, MonadThrow m
|
||||
, MonadLogger m
|
||||
, HasLog env
|
||||
, MonadIO m
|
||||
)
|
||||
=> Settings
|
||||
-> DownloadInfo
|
||||
-> FilePath -- ^ destination dir
|
||||
=> URI
|
||||
-> Maybe URI -- ^ URI for gpg sig
|
||||
-> Maybe T.Text -- ^ expected hash
|
||||
-> FilePath -- ^ destination dir (ignored for file:// scheme)
|
||||
-> Maybe FilePath -- ^ optional filename
|
||||
-> Excepts '[DigestError , DownloadFailed] m FilePath
|
||||
download settings@Settings{ downloader } dli dest mfn
|
||||
-> Bool -- ^ whether to read an write etags
|
||||
-> Excepts '[DigestError , DownloadFailed, GPGError] m FilePath
|
||||
download uri gpgUri eDigest dest mfn etags
|
||||
| scheme == "https" = dl
|
||||
| scheme == "http" = dl
|
||||
| scheme == "file" = cp
|
||||
| scheme == "file" = do
|
||||
let destFile' = T.unpack . decUTF8Safe $ view pathL' uri
|
||||
lift $ logDebug $ "using local file: " <> T.pack destFile'
|
||||
forM_ eDigest (liftE . flip checkDigest destFile')
|
||||
pure destFile'
|
||||
| otherwise = throwE $ DownloadFailed (variantFromValue UnsupportedScheme)
|
||||
|
||||
where
|
||||
scheme = view (dlUri % uriSchemeL' % schemeBSL') dli
|
||||
cp = do
|
||||
-- destination dir must exist
|
||||
liftIO $ createDirRecursive' dest
|
||||
let destFile = getDestFile
|
||||
let fromFile = T.unpack . decUTF8Safe $ path
|
||||
liftIO $ copyFile fromFile destFile
|
||||
pure destFile
|
||||
scheme = view (uriSchemeL' % schemeBSL') uri
|
||||
dl = do
|
||||
let uri' = decUTF8Safe (serializeURIRef' (view dlUri dli))
|
||||
lift $ $(logInfo) [i|downloading: #{uri'}|]
|
||||
baseDestFile <- liftE . reThrowAll @_ @_ @'[DownloadFailed] DownloadFailed $ getDestFile uri mfn
|
||||
lift $ logInfo $ "downloading: " <> (decUTF8Safe . serializeURIRef') uri <> " as file " <> T.pack baseDestFile
|
||||
|
||||
-- destination dir must exist
|
||||
liftIO $ createDirRecursive' dest
|
||||
let destFile = getDestFile
|
||||
|
||||
|
||||
-- download
|
||||
flip onException
|
||||
(liftIO $ hideError doesNotExistErrorType $ rmFile destFile)
|
||||
$ catchAllE @_ @'[ProcessError, DownloadFailed, UnsupportedScheme]
|
||||
(\e ->
|
||||
liftIO (hideError doesNotExistErrorType $ rmFile destFile)
|
||||
>> (throwE . DownloadFailed $ e)
|
||||
(lift $ hideError doesNotExistErrorType $ recycleFile (tmpFile baseDestFile))
|
||||
$ catchAllE @_ @'[GPGError, ProcessError, DownloadFailed, UnsupportedScheme, DigestError] @'[DigestError, DownloadFailed, GPGError]
|
||||
(\e' -> do
|
||||
lift $ hideError doesNotExistErrorType $ recycleFile (tmpFile baseDestFile)
|
||||
case e' of
|
||||
V e@GPGError {} -> throwE e
|
||||
V e@DigestError {} -> throwE e
|
||||
_ -> throwE (DownloadFailed e')
|
||||
) $ do
|
||||
case downloader of
|
||||
Curl -> do
|
||||
o' <- liftIO getCurlOpts
|
||||
liftE $ lEM @_ @'[ProcessError] $ exec "curl"
|
||||
(o' ++ ["-fL", "-o", destFile, (T.unpack . decUTF8Safe) $ serializeURIRef' $ view dlUri dli]) Nothing Nothing
|
||||
Wget -> do
|
||||
o' <- liftIO getWgetOpts
|
||||
liftE $ lEM @_ @'[ProcessError] $ exec "wget"
|
||||
(o' ++ ["-O", destFile , (T.unpack . decUTF8Safe) $ serializeURIRef' $ view dlUri dli]) Nothing Nothing
|
||||
Settings{ downloader, noNetwork, gpgSetting } <- lift getSettings
|
||||
when noNetwork $ throwE (DownloadFailed (V NoNetwork :: V '[NoNetwork]))
|
||||
downloadAction <- case downloader of
|
||||
Curl -> do
|
||||
o' <- liftIO getCurlOpts
|
||||
if etags
|
||||
then pure $ curlEtagsDL o'
|
||||
else pure $ curlDL o'
|
||||
Wget -> do
|
||||
o' <- liftIO getWgetOpts
|
||||
if etags
|
||||
then pure $ wgetEtagsDL o'
|
||||
else pure $ wgetDL o'
|
||||
#if defined(INTERNAL_DOWNLOADER)
|
||||
Internal -> do
|
||||
(https, host, fullPath, port) <- liftE $ uriToQuadruple (view dlUri dli)
|
||||
liftE $ downloadToFile https host fullPath port destFile
|
||||
Internal -> do
|
||||
if etags
|
||||
then pure (\fp -> liftE . internalEtagsDL fp)
|
||||
else pure (\fp -> liftE . internalDL fp)
|
||||
#endif
|
||||
liftE $ downloadAction baseDestFile uri
|
||||
case (gpgUri, gpgSetting) of
|
||||
(_, GPGNone) -> pure ()
|
||||
(Just gpgUri', _) -> do
|
||||
gpgDestFile <- liftE . reThrowAll @_ @_ @'[DownloadFailed] DownloadFailed $ getDestFile gpgUri' Nothing
|
||||
liftE $ flip onException
|
||||
(lift $ hideError doesNotExistErrorType $ recycleFile (tmpFile gpgDestFile))
|
||||
$ catchAllE @_ @'[GPGError, ProcessError, UnsupportedScheme, DownloadFailed] @'[GPGError]
|
||||
(\e -> if gpgSetting == GPGStrict then throwE (GPGError e) else lift $ logWarn $ T.pack (prettyShow (GPGError e))
|
||||
) $ do
|
||||
o' <- liftIO getGpgOpts
|
||||
lift $ logDebug $ "downloading: " <> (decUTF8Safe . serializeURIRef') gpgUri' <> " as file " <> T.pack gpgDestFile
|
||||
liftE $ downloadAction gpgDestFile gpgUri'
|
||||
lift $ logInfo $ "verifying signature of: " <> T.pack baseDestFile
|
||||
let args = o' ++ ["--batch", "--verify", "--quiet", "--no-tty", gpgDestFile, baseDestFile]
|
||||
cp <- lift $ executeOut "gpg" args Nothing
|
||||
case cp of
|
||||
CapturedProcess { _exitCode = ExitFailure i, _stdErr } -> do
|
||||
lift $ logDebug $ decUTF8Safe' _stdErr
|
||||
throwE (GPGError @'[ProcessError] (V (NonZeroExit i "gpg" args)))
|
||||
CapturedProcess { _stdErr } -> lift $ logDebug $ decUTF8Safe' _stdErr
|
||||
_ -> pure ()
|
||||
|
||||
forM_ eDigest (liftE . flip checkDigest baseDestFile)
|
||||
pure baseDestFile
|
||||
|
||||
curlDL :: (MonadCatch m, MonadMask m, MonadIO m) => [String] -> FilePath -> URI -> Excepts '[ProcessError, DownloadFailed, UnsupportedScheme] m ()
|
||||
curlDL o' destFile (decUTF8Safe . serializeURIRef' -> uri') = do
|
||||
let destFileTemp = tmpFile destFile
|
||||
flip finally (try @_ @SomeException $ rmFile destFileTemp) $ do
|
||||
liftE $ lEM @_ @'[ProcessError] $ exec "curl"
|
||||
(o' ++ ["-fL", "-o", destFileTemp, T.unpack uri']) Nothing Nothing
|
||||
liftIO $ renameFile destFileTemp destFile
|
||||
|
||||
curlEtagsDL :: (MonadReader env m, HasLog env, MonadCatch m, MonadMask m, MonadIO m)
|
||||
=> [String] -> FilePath -> URI -> Excepts '[ProcessError, DownloadFailed, UnsupportedScheme] m ()
|
||||
curlEtagsDL o' destFile (decUTF8Safe . serializeURIRef' -> uri') = do
|
||||
let destFileTemp = tmpFile destFile
|
||||
dh <- liftIO $ emptySystemTempFile "curl-header"
|
||||
flip finally (try @_ @SomeException $ rmFile dh) $
|
||||
flip finally (try @_ @SomeException $ rmFile destFileTemp) $ do
|
||||
metag <- lift $ readETag destFile
|
||||
liftE $ lEM @_ @'[ProcessError] $ exec "curl"
|
||||
(o' ++ (if etags then ["--dump-header", dh] else [])
|
||||
++ maybe [] (\t -> ["-H", "If-None-Match: " <> T.unpack t]) metag
|
||||
++ ["-fL", "-o", destFileTemp, T.unpack uri']) Nothing Nothing
|
||||
headers <- liftIO $ T.readFile dh
|
||||
|
||||
-- this nonsense is necessary, because some older versions of curl would overwrite
|
||||
-- the destination file when 304 is returned
|
||||
case fmap T.words . listToMaybe . fmap T.strip . T.lines . getLastHeader $ headers of
|
||||
Just (http':sc:_)
|
||||
| sc == "304"
|
||||
, T.pack "HTTP" `T.isPrefixOf` http' -> lift $ logDebug "Status code was 304, not overwriting"
|
||||
| T.pack "HTTP" `T.isPrefixOf` http' -> do
|
||||
lift $ logDebug $ "Status code was " <> sc <> ", overwriting"
|
||||
liftIO $ renameFile destFileTemp destFile
|
||||
_ -> liftE $ throwE @_ @'[DownloadFailed] (DownloadFailed (toVariantAt @0 (MalformedHeaders headers)
|
||||
:: V '[MalformedHeaders]))
|
||||
|
||||
lift $ writeEtags destFile (parseEtags headers)
|
||||
|
||||
wgetDL :: (MonadCatch m, MonadMask m, MonadIO m) => [String] -> FilePath -> URI -> Excepts '[ProcessError, DownloadFailed, UnsupportedScheme] m ()
|
||||
wgetDL o' destFile (decUTF8Safe . serializeURIRef' -> uri') = do
|
||||
let destFileTemp = tmpFile destFile
|
||||
flip finally (try @_ @SomeException $ rmFile destFileTemp) $ do
|
||||
let opts = o' ++ ["-O", destFileTemp , T.unpack uri']
|
||||
liftE $ lEM @_ @'[ProcessError] $ exec "wget" opts Nothing Nothing
|
||||
liftIO $ renameFile destFileTemp destFile
|
||||
|
||||
|
||||
wgetEtagsDL :: (MonadReader env m, HasLog env, MonadCatch m, MonadMask m, MonadIO m)
|
||||
=> [String] -> FilePath -> URI -> Excepts '[ProcessError, DownloadFailed, UnsupportedScheme] m ()
|
||||
wgetEtagsDL o' destFile (decUTF8Safe . serializeURIRef' -> uri') = do
|
||||
let destFileTemp = tmpFile destFile
|
||||
flip finally (try @_ @SomeException $ rmFile destFileTemp) $ do
|
||||
metag <- lift $ readETag destFile
|
||||
let opts = o' ++ maybe [] (\t -> ["--header", "If-None-Match: " <> T.unpack t]) metag
|
||||
++ ["-q", "-S", "-O", destFileTemp , T.unpack uri']
|
||||
CapturedProcess {_exitCode, _stdErr} <- lift $ executeOut "wget" opts Nothing
|
||||
case _exitCode of
|
||||
ExitSuccess -> do
|
||||
liftIO $ renameFile destFileTemp destFile
|
||||
lift $ writeEtags destFile (parseEtags (decUTF8Safe' _stdErr))
|
||||
ExitFailure i'
|
||||
| i' == 8
|
||||
, Just _ <- find (T.pack "304 Not Modified" `T.isInfixOf`) . T.lines . decUTF8Safe' $ _stdErr
|
||||
-> do
|
||||
lift $ logDebug "Not modified, skipping download"
|
||||
lift $ writeEtags destFile (parseEtags (decUTF8Safe' _stdErr))
|
||||
| otherwise -> throwE (NonZeroExit i' "wget" opts)
|
||||
|
||||
#if defined(INTERNAL_DOWNLOADER)
|
||||
internalDL :: (MonadCatch m, MonadMask m, MonadIO m)
|
||||
=> FilePath -> URI -> Excepts '[DownloadFailed, UnsupportedScheme] m ()
|
||||
internalDL destFile uri' = do
|
||||
let destFileTemp = tmpFile destFile
|
||||
flip finally (try @_ @SomeException $ rmFile destFileTemp) $ do
|
||||
(https, host, fullPath, port) <- liftE $ uriToQuadruple uri'
|
||||
void $ liftE $ catchE @HTTPNotModified
|
||||
@'[DownloadFailed]
|
||||
(\e@(HTTPNotModified _) ->
|
||||
throwE @_ @'[DownloadFailed] (DownloadFailed (toVariantAt @0 e :: V '[HTTPNotModified])))
|
||||
$ downloadToFile https host fullPath port destFileTemp mempty
|
||||
liftIO $ renameFile destFileTemp destFile
|
||||
|
||||
|
||||
internalEtagsDL :: (MonadReader env m, HasLog env, MonadCatch m, MonadMask m, MonadIO m)
|
||||
=> FilePath -> URI -> Excepts '[DownloadFailed, UnsupportedScheme] m ()
|
||||
internalEtagsDL destFile uri' = do
|
||||
let destFileTemp = tmpFile destFile
|
||||
flip finally (try @_ @SomeException $ rmFile destFileTemp) $ do
|
||||
(https, host, fullPath, port) <- liftE $ uriToQuadruple uri'
|
||||
metag <- lift $ readETag destFile
|
||||
let addHeaders = maybe mempty (\etag -> M.fromList [ (mk . E.encodeUtf8 . T.pack $ "If-None-Match"
|
||||
, E.encodeUtf8 etag)]) metag
|
||||
liftE
|
||||
$ catchE @HTTPNotModified @'[DownloadFailed] @'[] (\(HTTPNotModified etag) -> lift $ writeEtags destFile (pure $ Just etag))
|
||||
$ do
|
||||
r <- downloadToFile https host fullPath port destFileTemp addHeaders
|
||||
liftIO $ renameFile destFileTemp destFile
|
||||
lift $ writeEtags destFile (pure $ decUTF8Safe <$> getHeader r "etag")
|
||||
#endif
|
||||
|
||||
liftE $ checkDigest settings dli destFile
|
||||
pure destFile
|
||||
|
||||
-- Manage to find a file we can write the body into.
|
||||
getDestFile :: FilePath
|
||||
getDestFile = maybe (dest </> T.unpack (decUTF8Safe (urlBaseName path))) (dest </>) mfn
|
||||
getDestFile :: Monad m => URI -> Maybe FilePath -> Excepts '[NoUrlBase] m FilePath
|
||||
getDestFile uri' mfn' =
|
||||
let path = view pathL' uri'
|
||||
in case mfn' of
|
||||
Just fn -> pure (dest </> fn)
|
||||
Nothing
|
||||
| let urlBase = T.unpack (decUTF8Safe (urlBaseName path))
|
||||
, not (null urlBase) -> pure (dest </> urlBase)
|
||||
-- TODO: remove this once we use hpath again
|
||||
| otherwise -> throwE $ NoUrlBase (decUTF8Safe . serializeURIRef' $ uri')
|
||||
|
||||
path = view (dlUri % pathL') dli
|
||||
parseEtags :: (MonadReader env m, HasLog env, MonadIO m, MonadThrow m) => T.Text -> m (Maybe T.Text)
|
||||
parseEtags stderr = do
|
||||
let mEtag = find (\line -> T.pack "etag:" `T.isPrefixOf` T.toLower line) . fmap T.strip . T.lines . getLastHeader $ stderr
|
||||
case T.words <$> mEtag of
|
||||
(Just []) -> do
|
||||
logDebug "Couldn't parse etags, no input: "
|
||||
pure Nothing
|
||||
(Just [_, etag']) -> do
|
||||
logDebug $ "Parsed etag: " <> etag'
|
||||
pure (Just etag')
|
||||
(Just xs) -> do
|
||||
logDebug ("Couldn't parse etags, unexpected input: " <> T.unwords xs)
|
||||
pure Nothing
|
||||
Nothing -> do
|
||||
logDebug "No etags header found"
|
||||
pure Nothing
|
||||
|
||||
writeEtags :: (MonadReader env m, HasLog env, MonadIO m, MonadThrow m) => FilePath -> m (Maybe T.Text) -> m ()
|
||||
writeEtags destFile getTags = do
|
||||
getTags >>= \case
|
||||
Just t -> do
|
||||
logDebug $ "Writing etagsFile " <> T.pack (etagsFile destFile)
|
||||
liftIO $ T.writeFile (etagsFile destFile) t
|
||||
Nothing ->
|
||||
logDebug "No etags files written"
|
||||
|
||||
readETag :: (MonadReader env m, HasLog env, MonadCatch m, MonadIO m) => FilePath -> m (Maybe T.Text)
|
||||
readETag fp = do
|
||||
e <- liftIO $ doesFileExist fp
|
||||
if e
|
||||
then do
|
||||
rE <- try @_ @SomeException $ liftIO $ fmap stripNewline' $ T.readFile (etagsFile fp)
|
||||
case rE of
|
||||
(Right et) -> do
|
||||
logDebug $ "Read etag: " <> et
|
||||
pure (Just et)
|
||||
(Left _) -> do
|
||||
logDebug "Etag file doesn't exist (yet)"
|
||||
pure Nothing
|
||||
else do
|
||||
logDebug $ "Skipping and deleting etags file because destination file " <> T.pack fp <> " doesn't exist"
|
||||
liftIO $ hideError doesNotExistErrorType $ rmFile (etagsFile fp)
|
||||
pure Nothing
|
||||
|
||||
|
||||
-- | Download into tmpdir or use cached version, if it exists. If filename
|
||||
-- is omitted, infers the filename from the url.
|
||||
downloadCached :: ( MonadMask m
|
||||
downloadCached :: ( MonadReader env m
|
||||
, HasDirs env
|
||||
, HasSettings env
|
||||
, MonadMask m
|
||||
, MonadResource m
|
||||
, MonadThrow m
|
||||
, MonadLogger m
|
||||
, HasLog env
|
||||
, MonadIO m
|
||||
, MonadUnliftIO m
|
||||
)
|
||||
=> Settings
|
||||
-> Dirs
|
||||
-> DownloadInfo
|
||||
=> DownloadInfo
|
||||
-> Maybe FilePath -- ^ optional filename
|
||||
-> Excepts '[DigestError , DownloadFailed] m FilePath
|
||||
downloadCached settings@Settings{ cache } dirs dli mfn = do
|
||||
-> Excepts '[DigestError , DownloadFailed, GPGError] m FilePath
|
||||
downloadCached dli mfn = do
|
||||
Settings{ cache } <- lift getSettings
|
||||
case cache of
|
||||
True -> downloadCached' settings dirs dli mfn
|
||||
True -> downloadCached' dli mfn Nothing
|
||||
False -> do
|
||||
tmp <- lift withGHCupTmpDir
|
||||
liftE $ download settings dli tmp mfn
|
||||
liftE $ download (_dlUri dli) Nothing (Just (_dlHash dli)) tmp mfn False
|
||||
|
||||
|
||||
downloadCached' :: ( MonadMask m
|
||||
downloadCached' :: ( MonadReader env m
|
||||
, HasDirs env
|
||||
, HasSettings env
|
||||
, MonadMask m
|
||||
, MonadThrow m
|
||||
, MonadLogger m
|
||||
, HasLog env
|
||||
, MonadIO m
|
||||
, MonadUnliftIO m
|
||||
)
|
||||
=> Settings
|
||||
-> Dirs
|
||||
-> DownloadInfo
|
||||
=> DownloadInfo
|
||||
-> Maybe FilePath -- ^ optional filename
|
||||
-> Excepts '[DigestError , DownloadFailed] m FilePath
|
||||
downloadCached' settings Dirs{..} dli mfn = do
|
||||
-> Maybe FilePath -- ^ optional destination dir (default: cacheDir)
|
||||
-> Excepts '[DigestError , DownloadFailed, GPGError] m FilePath
|
||||
downloadCached' dli mfn mDestDir = do
|
||||
Dirs { cacheDir } <- lift getDirs
|
||||
let destDir = fromMaybe cacheDir mDestDir
|
||||
let fn = fromMaybe ((T.unpack . decUTF8Safe) $ urlBaseName $ view (dlUri % pathL') dli) mfn
|
||||
let cachfile = cacheDir </> fn
|
||||
let cachfile = destDir </> fn
|
||||
fileExists <- liftIO $ doesFileExist cachfile
|
||||
if
|
||||
| fileExists -> do
|
||||
liftE $ checkDigest settings dli cachfile
|
||||
liftE $ checkDigest (view dlHash dli) cachfile
|
||||
pure cachfile
|
||||
| otherwise -> liftE $ download settings dli cacheDir mfn
|
||||
| otherwise -> liftE $ download (_dlUri dli) Nothing (Just (_dlHash dli)) destDir mfn False
|
||||
|
||||
|
||||
|
||||
@@ -439,80 +619,25 @@ downloadCached' settings Dirs{..} dli mfn = do
|
||||
|
||||
|
||||
|
||||
|
||||
-- | This is used for downloading the JSON.
|
||||
downloadBS :: (MonadCatch m, MonadIO m, MonadLogger m)
|
||||
=> Downloader
|
||||
-> URI
|
||||
-> Excepts
|
||||
'[ FileDoesNotExistError
|
||||
, HTTPStatusError
|
||||
, URIParseError
|
||||
, UnsupportedScheme
|
||||
, NoLocationHeader
|
||||
, TooManyRedirs
|
||||
, ProcessError
|
||||
]
|
||||
m
|
||||
L.ByteString
|
||||
downloadBS downloader uri'
|
||||
| scheme == "https"
|
||||
= dl True
|
||||
| scheme == "http"
|
||||
= dl False
|
||||
| scheme == "file"
|
||||
= liftIOException doesNotExistErrorType (FileDoesNotExistError $ T.unpack $ decUTF8Safe path)
|
||||
(liftIO $ L.readFile (T.unpack $ decUTF8Safe path))
|
||||
| otherwise
|
||||
= throwE UnsupportedScheme
|
||||
|
||||
where
|
||||
scheme = view (uriSchemeL' % schemeBSL') uri'
|
||||
path = view pathL' uri'
|
||||
#if defined(INTERNAL_DOWNLOADER)
|
||||
dl https = do
|
||||
#else
|
||||
dl _ = do
|
||||
#endif
|
||||
lift $ $(logDebug) [i|downloading: #{serializeURIRef' uri'}|]
|
||||
case downloader of
|
||||
Curl -> do
|
||||
o' <- liftIO getCurlOpts
|
||||
let exe = "curl"
|
||||
args = o' ++ ["-sSfL", T.unpack $ decUTF8Safe $ serializeURIRef' uri']
|
||||
lift (executeOut exe args Nothing) >>= \case
|
||||
CapturedProcess ExitSuccess stdout _ -> do
|
||||
pure stdout
|
||||
CapturedProcess (ExitFailure i') _ _ -> throwE $ NonZeroExit i' exe args
|
||||
Wget -> do
|
||||
o' <- liftIO getWgetOpts
|
||||
let exe = "wget"
|
||||
args = o' ++ ["-qO-", T.unpack $ decUTF8Safe $ serializeURIRef' uri']
|
||||
lift (executeOut exe args Nothing) >>= \case
|
||||
CapturedProcess ExitSuccess stdout _ -> do
|
||||
pure stdout
|
||||
CapturedProcess (ExitFailure i') _ _ -> throwE $ NonZeroExit i' exe args
|
||||
#if defined(INTERNAL_DOWNLOADER)
|
||||
Internal -> do
|
||||
(_, host', fullPath', port') <- liftE $ uriToQuadruple uri'
|
||||
liftE $ downloadBS' https host' fullPath' port'
|
||||
#endif
|
||||
|
||||
|
||||
checkDigest :: (MonadIO m, MonadThrow m, MonadLogger m)
|
||||
=> Settings
|
||||
-> DownloadInfo
|
||||
checkDigest :: ( MonadReader env m
|
||||
, HasDirs env
|
||||
, HasSettings env
|
||||
, MonadIO m
|
||||
, MonadThrow m
|
||||
, HasLog env
|
||||
)
|
||||
=> T.Text -- ^ the hash
|
||||
-> FilePath
|
||||
-> Excepts '[DigestError] m ()
|
||||
checkDigest Settings{ noVerify } dli file = do
|
||||
checkDigest eDigest file = do
|
||||
Settings{ noVerify } <- lift getSettings
|
||||
let verify = not noVerify
|
||||
when verify $ do
|
||||
let p' = takeFileName file
|
||||
lift $ $(logInfo) [i|verifying digest of: #{p'}|]
|
||||
lift $ logInfo $ "verifying digest of: " <> T.pack p'
|
||||
c <- liftIO $ L.readFile file
|
||||
cDigest <- throwEither . E.decodeUtf8' . B16.encode . SHA256.hashlazy $ c
|
||||
let eDigest = view dlHash dli
|
||||
when ((cDigest /= eDigest) && verify) $ throwE (DigestError cDigest eDigest)
|
||||
when ((cDigest /= eDigest) && verify) $ throwE (DigestError file cDigest eDigest)
|
||||
|
||||
|
||||
-- | Get additional curl args from env. This is an undocumented option.
|
||||
@@ -530,8 +655,34 @@ getWgetOpts =
|
||||
Just r -> pure $ splitOn " " r
|
||||
Nothing -> pure []
|
||||
|
||||
-- | Get additional gpg args from env. This is an undocumented option.
|
||||
getGpgOpts :: IO [String]
|
||||
getGpgOpts =
|
||||
lookupEnv "GHCUP_GPG_OPTS" >>= \case
|
||||
Just r -> pure $ splitOn " " r
|
||||
Nothing -> pure []
|
||||
|
||||
-- | Get the url base name.
|
||||
--
|
||||
-- >>> urlBaseName "/foo/bar/baz"
|
||||
-- "baz"
|
||||
urlBaseName :: ByteString -- ^ the url path (without scheme and host)
|
||||
-> ByteString
|
||||
urlBaseName = snd . B.breakEnd (== _slash) . urlDecode False
|
||||
|
||||
|
||||
-- | Curl saves all intermediate connect headers as well, not just the last one, so we make an effort to take the
|
||||
-- last HTTP block only. Passing '--suppress-connect-headers' would be better, but it isn't supported by all versions,
|
||||
-- also see:
|
||||
-- https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/213
|
||||
--
|
||||
-- >>> getLastHeader "\n\nHTTP/1.0 200 Connection established\n\nHTTP/1.1 304 Not Modified\n"
|
||||
-- "HTTP/1.1 304 Not Modified\n"
|
||||
-- >>> getLastHeader "HTTP/1.1 304 Not Modified\n"
|
||||
-- "HTTP/1.1 304 Not Modified\n"
|
||||
getLastHeader :: T.Text -> T.Text
|
||||
getLastHeader = T.unlines . lastDef [] . filter (\x -> not (null x)) . splitOn [""] . fmap T.stripEnd . T.lines
|
||||
|
||||
|
||||
tmpFile :: FilePath -> FilePath
|
||||
tmpFile = (<.> "tmp")
|
||||
|
||||
@@ -9,9 +9,7 @@ module GHCup.Download.IOStreams where
|
||||
|
||||
import GHCup.Download.Utils
|
||||
import GHCup.Errors
|
||||
import GHCup.Types.Optics
|
||||
import GHCup.Types.JSON ( )
|
||||
import GHCup.Utils.File
|
||||
import GHCup.Utils.Prelude
|
||||
|
||||
import Control.Applicative
|
||||
@@ -20,7 +18,7 @@ import Control.Monad
|
||||
import Control.Monad.Reader
|
||||
import Data.ByteString ( ByteString )
|
||||
import Data.ByteString.Builder
|
||||
import Data.CaseInsensitive ( CI )
|
||||
import Data.CaseInsensitive ( CI, original, mk )
|
||||
import Data.IORef
|
||||
import Data.Maybe
|
||||
import Data.Text.Read
|
||||
@@ -32,7 +30,6 @@ import Prelude hiding ( abs
|
||||
, writeFile
|
||||
)
|
||||
import System.ProgressBar
|
||||
import System.IO
|
||||
import URI.ByteString
|
||||
|
||||
import qualified Data.ByteString as BS
|
||||
@@ -67,7 +64,7 @@ downloadBS' :: MonadIO m
|
||||
downloadBS' https host path port = do
|
||||
bref <- liftIO $ newIORef (mempty :: Builder)
|
||||
let stepper bs = modifyIORef bref (<> byteString bs)
|
||||
downloadInternal False https host path port stepper
|
||||
void $ downloadInternal False https host path port stepper (pure ()) mempty
|
||||
liftIO (readIORef bref <&> toLazyByteString)
|
||||
|
||||
|
||||
@@ -77,12 +74,17 @@ downloadToFile :: (MonadMask m, MonadIO m)
|
||||
-> ByteString -- ^ path (e.g. "/my/file") including query
|
||||
-> Maybe Int -- ^ optional port (e.g. 3000)
|
||||
-> FilePath -- ^ destination file to create and write to
|
||||
-> Excepts '[DownloadFailed] m ()
|
||||
downloadToFile https host fullPath port destFile = do
|
||||
fd <- liftIO $ openFile destFile WriteMode
|
||||
let stepper = BS.hPut fd
|
||||
flip finally (liftIO $ hClose fd)
|
||||
$ reThrowAll DownloadFailed $ downloadInternal True https host fullPath port stepper
|
||||
-> M.Map (CI ByteString) ByteString -- ^ additional headers
|
||||
-> Excepts '[DownloadFailed, HTTPNotModified] m Response
|
||||
downloadToFile https host fullPath port destFile addHeaders = do
|
||||
let stepper = BS.appendFile destFile
|
||||
setup = BS.writeFile destFile mempty
|
||||
catchAllE (\case
|
||||
(V (HTTPStatusError i headers))
|
||||
| i == 304
|
||||
, Just e <- M.lookup (mk "etag") headers -> throwE $ HTTPNotModified (decUTF8Safe e)
|
||||
v -> throwE $ DownloadFailed v
|
||||
) $ downloadInternal True https host fullPath port stepper setup addHeaders
|
||||
|
||||
|
||||
downloadInternal :: MonadIO m
|
||||
@@ -92,6 +94,8 @@ downloadInternal :: MonadIO m
|
||||
-> ByteString -- ^ path with query
|
||||
-> Maybe Int -- ^ optional port
|
||||
-> (ByteString -> IO a) -- ^ the consuming step function
|
||||
-> IO a -- ^ setup action
|
||||
-> M.Map (CI ByteString) ByteString -- ^ additional headers
|
||||
-> Excepts
|
||||
'[ HTTPStatusError
|
||||
, URIParseError
|
||||
@@ -100,19 +104,21 @@ downloadInternal :: MonadIO m
|
||||
, TooManyRedirs
|
||||
]
|
||||
m
|
||||
()
|
||||
Response
|
||||
downloadInternal = go (5 :: Int)
|
||||
|
||||
where
|
||||
go redirs progressBar https host path port consumer = do
|
||||
go redirs progressBar https host path port consumer setup addHeaders = do
|
||||
r <- liftIO $ withConnection' https host port action
|
||||
veitherToExcepts r >>= \case
|
||||
Just r' ->
|
||||
Right r' ->
|
||||
if redirs > 0 then followRedirectURL r' else throwE TooManyRedirs
|
||||
Nothing -> pure ()
|
||||
Left res -> pure res
|
||||
where
|
||||
action c = do
|
||||
let q = buildRequest1 $ http GET path
|
||||
let q = buildRequest1 $ do
|
||||
http GET path
|
||||
flip M.traverseWithKey addHeaders $ \key val -> setHeader (original key) val
|
||||
|
||||
sendRequest c q emptyBody
|
||||
|
||||
@@ -121,28 +127,30 @@ downloadInternal = go (5 :: Int)
|
||||
(\r i' -> runE $ do
|
||||
let scode = getStatusCode r
|
||||
if
|
||||
| scode >= 200 && scode < 300 -> downloadStream r i' >> pure Nothing
|
||||
| scode >= 200 && scode < 300 -> liftIO $ downloadStream r i' >> pure (Left r)
|
||||
| scode == 304 -> throwE $ HTTPStatusError scode (getHeaderMap r)
|
||||
| scode >= 300 && scode < 400 -> case getHeader r "Location" of
|
||||
Just r' -> pure $ Just r'
|
||||
Just r' -> pure $ Right r'
|
||||
Nothing -> throwE NoLocationHeader
|
||||
| otherwise -> throwE $ HTTPStatusError scode
|
||||
| otherwise -> throwE $ HTTPStatusError scode (getHeaderMap r)
|
||||
)
|
||||
|
||||
followRedirectURL bs = case parseURI strictURIParserOptions bs of
|
||||
Right uri' -> do
|
||||
(https', host', fullPath', port') <- liftE $ uriToQuadruple uri'
|
||||
go (redirs - 1) progressBar https' host' fullPath' port' consumer
|
||||
go (redirs - 1) progressBar https' host' fullPath' port' consumer setup addHeaders
|
||||
Left e -> throwE e
|
||||
|
||||
downloadStream r i' = do
|
||||
void setup
|
||||
let size = case getHeader r "Content-Length" of
|
||||
Just x' -> case decimal $ decUTF8Safe x' of
|
||||
Left _ -> 0
|
||||
Right (r', _) -> r'
|
||||
Nothing -> 0
|
||||
|
||||
mpb <- if progressBar
|
||||
then Just <$> liftIO (newProgressBar defStyle 10 (Progress 0 size ()))
|
||||
(mpb :: Maybe (ProgressBar ())) <- if progressBar
|
||||
then Just <$> newProgressBar defStyle 10 (Progress 0 size ())
|
||||
else pure Nothing
|
||||
|
||||
outStream <- liftIO $ Streams.makeOutputStream
|
||||
@@ -155,79 +163,6 @@ downloadInternal = go (5 :: Int)
|
||||
liftIO $ Streams.connect i' outStream
|
||||
|
||||
|
||||
getHead :: (MonadCatch m, MonadIO m)
|
||||
=> URI
|
||||
-> Excepts
|
||||
'[ HTTPStatusError
|
||||
, URIParseError
|
||||
, UnsupportedScheme
|
||||
, NoLocationHeader
|
||||
, TooManyRedirs
|
||||
, ProcessError
|
||||
]
|
||||
m
|
||||
(M.Map (CI ByteString) ByteString)
|
||||
getHead uri' | scheme == "https" = head' True
|
||||
| scheme == "http" = head' False
|
||||
| otherwise = throwE UnsupportedScheme
|
||||
|
||||
where
|
||||
scheme = view (uriSchemeL' % schemeBSL') uri'
|
||||
head' https = do
|
||||
(_, host', fullPath', port') <- liftE $ uriToQuadruple uri'
|
||||
liftE $ headInternal https host' fullPath' port'
|
||||
|
||||
|
||||
headInternal :: MonadIO m
|
||||
=> Bool -- ^ https?
|
||||
-> ByteString -- ^ host
|
||||
-> ByteString -- ^ path with query
|
||||
-> Maybe Int -- ^ optional port
|
||||
-> Excepts
|
||||
'[ HTTPStatusError
|
||||
, URIParseError
|
||||
, UnsupportedScheme
|
||||
, TooManyRedirs
|
||||
, NoLocationHeader
|
||||
]
|
||||
m
|
||||
(M.Map (CI ByteString) ByteString)
|
||||
headInternal = go (5 :: Int)
|
||||
|
||||
where
|
||||
go redirs https host path port = do
|
||||
r <- liftIO $ withConnection' https host port action
|
||||
veitherToExcepts r >>= \case
|
||||
Left r' ->
|
||||
if redirs > 0 then followRedirectURL r' else throwE TooManyRedirs
|
||||
Right hs -> pure hs
|
||||
where
|
||||
|
||||
action c = do
|
||||
let q = buildRequest1 $ http HEAD path
|
||||
|
||||
sendRequest c q emptyBody
|
||||
|
||||
unsafeReceiveResponse
|
||||
c
|
||||
(\r _ -> runE $ do
|
||||
let scode = getStatusCode r
|
||||
if
|
||||
| scode >= 200 && scode < 300 -> do
|
||||
let headers = getHeaderMap r
|
||||
pure $ Right headers
|
||||
| scode >= 300 && scode < 400 -> case getHeader r "Location" of
|
||||
Just r' -> pure $ Left r'
|
||||
Nothing -> throwE NoLocationHeader
|
||||
| otherwise -> throwE $ HTTPStatusError scode
|
||||
)
|
||||
|
||||
followRedirectURL bs = case parseURI strictURIParserOptions bs of
|
||||
Right uri' -> do
|
||||
(https', host', fullPath', port') <- liftE $ uriToQuadruple uri'
|
||||
go (redirs - 1) https' host' fullPath' port'
|
||||
Left e -> throwE e
|
||||
|
||||
|
||||
withConnection' :: Bool
|
||||
-> ByteString
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
{-# LANGUAGE ExistentialQuantification #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE StandaloneDeriving #-}
|
||||
{-# LANGUAGE QuasiQuotes #-}
|
||||
{-# LANGUAGE TypeOperators #-}
|
||||
{-# LANGUAGE FlexibleInstances #-}
|
||||
|
||||
@@ -21,20 +20,20 @@ module GHCup.Errors where
|
||||
|
||||
import GHCup.Types
|
||||
|
||||
#if !defined(TAR)
|
||||
import Codec.Archive
|
||||
#else
|
||||
import qualified Codec.Archive.Tar as Tar
|
||||
#endif
|
||||
import Control.Exception.Safe
|
||||
import Data.String.Interpolate
|
||||
import Data.ByteString ( ByteString )
|
||||
import Data.CaseInsensitive ( CI )
|
||||
import Data.Text ( Text )
|
||||
import Data.Versions
|
||||
import Haskus.Utils.Variant
|
||||
import Text.PrettyPrint
|
||||
import Text.PrettyPrint.HughesPJClass
|
||||
import Text.PrettyPrint hiding ( (<>) )
|
||||
import Text.PrettyPrint.HughesPJClass hiding ( (<>) )
|
||||
import URI.ByteString
|
||||
|
||||
import qualified Data.Map.Strict as M
|
||||
import qualified Data.Text as T
|
||||
|
||||
|
||||
|
||||
------------------------
|
||||
@@ -51,7 +50,7 @@ instance Pretty NoCompatiblePlatform where
|
||||
pPrint (NoCompatiblePlatform str') =
|
||||
text ("Could not find a compatible platform. Got: " ++ str')
|
||||
|
||||
-- | Unable to find a download for the requested versio/distro.
|
||||
-- | Unable to find a download for the requested version/distro.
|
||||
data NoDownload = NoDownload
|
||||
deriving Show
|
||||
|
||||
@@ -88,7 +87,7 @@ data UnknownArchive = UnknownArchive FilePath
|
||||
|
||||
instance Pretty UnknownArchive where
|
||||
pPrint (UnknownArchive file) =
|
||||
text [i|The archive format is unknown. We don't know how to extract the file "#{file}"|]
|
||||
text $ "The archive format is unknown. We don't know how to extract the file " <> file
|
||||
|
||||
-- | The scheme is not supported (such as ftp).
|
||||
data UnsupportedScheme = UnsupportedScheme
|
||||
@@ -111,7 +110,7 @@ data TagNotFound = TagNotFound Tag Tool
|
||||
|
||||
instance Pretty TagNotFound where
|
||||
pPrint (TagNotFound tag tool) =
|
||||
text "Unable to find tag" <+> pPrint tag <+> text [i|of tool "#{tool}"|]
|
||||
text "Unable to find tag" <+> pPrint tag <+> text "of tool" <+> pPrint tool
|
||||
|
||||
-- | Unable to find the next version of a tool (the one after the currently
|
||||
-- set one).
|
||||
@@ -120,7 +119,7 @@ data NextVerNotFound = NextVerNotFound Tool
|
||||
|
||||
instance Pretty NextVerNotFound where
|
||||
pPrint (NextVerNotFound tool) =
|
||||
text [i|Unable to find next (the one after the currently set one) version of tool "#{tool}"|]
|
||||
text "Unable to find next (the one after the currently set one) version of tool" <+> pPrint tool
|
||||
|
||||
-- | The tool (such as GHC) is already installed with that version.
|
||||
data AlreadyInstalled = AlreadyInstalled Tool Version
|
||||
@@ -128,7 +127,14 @@ data AlreadyInstalled = AlreadyInstalled Tool Version
|
||||
|
||||
instance Pretty AlreadyInstalled where
|
||||
pPrint (AlreadyInstalled tool ver') =
|
||||
text [i|#{tool}-#{prettyShow ver'} is already installed|]
|
||||
pPrint tool <+> text "-" <+> pPrint ver' <+> text "is already installed"
|
||||
|
||||
-- | The Directory is supposed to be empty, but wasn't.
|
||||
data DirNotEmpty = DirNotEmpty {path :: FilePath}
|
||||
|
||||
instance Pretty DirNotEmpty where
|
||||
pPrint (DirNotEmpty path) = do
|
||||
text $ "The directory was expected to be empty, but isn't: " <> path
|
||||
|
||||
-- | The tool is not installed. Some operations rely on a tool
|
||||
-- to be installed (such as setting the current GHC version).
|
||||
@@ -137,15 +143,17 @@ data NotInstalled = NotInstalled Tool GHCTargetVersion
|
||||
|
||||
instance Pretty NotInstalled where
|
||||
pPrint (NotInstalled tool ver) =
|
||||
text [i|The version "#{prettyShow ver}" of the tool "#{tool}" is not installed.|]
|
||||
text "The version" <+> pPrint ver <+> text "of the tool" <+> pPrint tool <+> text "is not installed."
|
||||
|
||||
-- | An executable was expected to be in PATH, but was not found.
|
||||
data NotFoundInPATH = NotFoundInPATH FilePath
|
||||
deriving Show
|
||||
|
||||
instance Exception NotFoundInPATH
|
||||
|
||||
instance Pretty NotFoundInPATH where
|
||||
pPrint (NotFoundInPATH exe) =
|
||||
text [i|The exe "#{exe}" was not found in PATH.|]
|
||||
text $ "The exe " <> exe <> " was not found in PATH."
|
||||
|
||||
-- | JSON decoding failed.
|
||||
data JSONError = JSONDecodeError String
|
||||
@@ -153,7 +161,7 @@ data JSONError = JSONDecodeError String
|
||||
|
||||
instance Pretty JSONError where
|
||||
pPrint (JSONDecodeError err) =
|
||||
text [i|JSON decoding failed with: #{err}|]
|
||||
text $ "JSON decoding failed with: " <> err
|
||||
|
||||
-- | A file that is supposed to exist does not exist
|
||||
-- (e.g. when we use file scheme to "download" something).
|
||||
@@ -162,7 +170,17 @@ data FileDoesNotExistError = FileDoesNotExistError FilePath
|
||||
|
||||
instance Pretty FileDoesNotExistError where
|
||||
pPrint (FileDoesNotExistError file) =
|
||||
text [i|File "#{file}" does not exist.|]
|
||||
text $ "File " <> file <> " does not exist."
|
||||
|
||||
-- | The file already exists
|
||||
-- (e.g. when we use isolated installs with the same path).
|
||||
-- (e.g. This is done to prevent any overwriting)
|
||||
data FileAlreadyExistsError = FileAlreadyExistsError FilePath
|
||||
deriving Show
|
||||
|
||||
instance Pretty FileAlreadyExistsError where
|
||||
pPrint (FileAlreadyExistsError file) =
|
||||
text $ "File " <> file <> " Already exists."
|
||||
|
||||
data TarDirDoesNotExist = TarDirDoesNotExist TarDir
|
||||
deriving Show
|
||||
@@ -172,20 +190,46 @@ instance Pretty TarDirDoesNotExist where
|
||||
text "Tar directory does not exist:" <+> pPrint dir
|
||||
|
||||
-- | File digest verification failed.
|
||||
data DigestError = DigestError Text Text
|
||||
data DigestError = DigestError FilePath Text Text
|
||||
deriving Show
|
||||
|
||||
instance Pretty DigestError where
|
||||
pPrint (DigestError currentDigest expectedDigest) =
|
||||
text [i|Digest error: expected "#{expectedDigest}", but got "#{currentDigest}"|]
|
||||
pPrint (DigestError fp currentDigest expectedDigest) =
|
||||
text "Digest error for" <+> text (fp <> ": expected")
|
||||
<+> text (T.unpack expectedDigest) <+> text "but got" <+> pPrint currentDigest <+> text
|
||||
"\nConsider removing the file in case it's cached and try again."
|
||||
|
||||
-- | File digest verification failed.
|
||||
data GPGError = forall xs . (ToVariantMaybe DownloadFailed xs, PopVariant DownloadFailed xs, Show (V xs), Pretty (V xs)) => GPGError (V xs)
|
||||
|
||||
deriving instance Show GPGError
|
||||
|
||||
instance Pretty GPGError where
|
||||
pPrint (GPGError reason) = text "GPG verify failed:" <+> pPrint reason
|
||||
|
||||
-- | Unexpected HTTP status.
|
||||
data HTTPStatusError = HTTPStatusError Int
|
||||
data HTTPStatusError = HTTPStatusError Int (M.Map (CI ByteString) ByteString)
|
||||
deriving Show
|
||||
|
||||
instance Pretty HTTPStatusError where
|
||||
pPrint (HTTPStatusError status) =
|
||||
text [i|Unexpected HTTP status: #{status}|]
|
||||
pPrint (HTTPStatusError status _) =
|
||||
text "Unexpected HTTP status:" <+> pPrint status
|
||||
|
||||
-- | Malformed headers.
|
||||
data MalformedHeaders = MalformedHeaders Text
|
||||
deriving Show
|
||||
|
||||
instance Pretty MalformedHeaders where
|
||||
pPrint (MalformedHeaders h) =
|
||||
text "Headers are malformed: " <+> pPrint h
|
||||
|
||||
-- | Unexpected HTTP status.
|
||||
data HTTPNotModified = HTTPNotModified Text
|
||||
deriving Show
|
||||
|
||||
instance Pretty HTTPNotModified where
|
||||
pPrint (HTTPNotModified etag) =
|
||||
text "Remote resource not modifed, etag was:" <+> pPrint etag
|
||||
|
||||
-- | The 'Location' header was expected during a 3xx redirect, but not found.
|
||||
data NoLocationHeader = NoLocationHeader
|
||||
@@ -193,7 +237,7 @@ data NoLocationHeader = NoLocationHeader
|
||||
|
||||
instance Pretty NoLocationHeader where
|
||||
pPrint NoLocationHeader =
|
||||
text [i|The 'Location' header was expected during a 3xx redirect, but not found.|]
|
||||
text "The 'Location' header was expected during a 3xx redirect, but not found."
|
||||
|
||||
-- | Too many redirects.
|
||||
data TooManyRedirs = TooManyRedirs
|
||||
@@ -201,7 +245,7 @@ data TooManyRedirs = TooManyRedirs
|
||||
|
||||
instance Pretty TooManyRedirs where
|
||||
pPrint TooManyRedirs =
|
||||
text [i|Too many redirections.|]
|
||||
text "Too many redirections."
|
||||
|
||||
-- | A patch could not be applied.
|
||||
data PatchFailed = PatchFailed
|
||||
@@ -209,7 +253,7 @@ data PatchFailed = PatchFailed
|
||||
|
||||
instance Pretty PatchFailed where
|
||||
pPrint PatchFailed =
|
||||
text [i|A patch could not be applied.|]
|
||||
text "A patch could not be applied."
|
||||
|
||||
-- | The tool requirements could not be found.
|
||||
data NoToolRequirements = NoToolRequirements
|
||||
@@ -217,21 +261,35 @@ data NoToolRequirements = NoToolRequirements
|
||||
|
||||
instance Pretty NoToolRequirements where
|
||||
pPrint NoToolRequirements =
|
||||
text [i|The Tool requirements could not be found.|]
|
||||
text "The Tool requirements could not be found."
|
||||
|
||||
data InvalidBuildConfig = InvalidBuildConfig Text
|
||||
deriving Show
|
||||
|
||||
instance Pretty InvalidBuildConfig where
|
||||
pPrint (InvalidBuildConfig reason) =
|
||||
text [i|The build config is invalid. Reason was: #{reason}|]
|
||||
text "The build config is invalid. Reason was:" <+> pPrint reason
|
||||
|
||||
data NoToolVersionSet = NoToolVersionSet Tool
|
||||
deriving Show
|
||||
|
||||
instance Pretty NoToolVersionSet where
|
||||
pPrint (NoToolVersionSet tool) =
|
||||
text [i|No version is set for tool "#{tool}".|]
|
||||
text "No version is set for tool" <+> pPrint tool <+> text "."
|
||||
|
||||
data NoNetwork = NoNetwork
|
||||
deriving Show
|
||||
|
||||
instance Pretty NoNetwork where
|
||||
pPrint NoNetwork =
|
||||
text "A download was required or requested, but '--offline' was specified."
|
||||
|
||||
data HadrianNotFound = HadrianNotFound
|
||||
deriving Show
|
||||
|
||||
instance Pretty HadrianNotFound where
|
||||
pPrint HadrianNotFound =
|
||||
text "Could not find Hadrian build files. Does this GHC version support Hadrian builds?"
|
||||
|
||||
|
||||
-------------------------
|
||||
@@ -239,31 +297,37 @@ instance Pretty NoToolVersionSet where
|
||||
-------------------------
|
||||
|
||||
-- | A download failed. The underlying error is encapsulated.
|
||||
data DownloadFailed = forall x xs . (Show x, Show (V xs), Pretty x, Pretty (V xs)) => DownloadFailed (V (x ': xs))
|
||||
data DownloadFailed = forall xs . (ToVariantMaybe DownloadFailed xs, PopVariant DownloadFailed xs, Show (V xs), Pretty (V xs)) => DownloadFailed (V xs)
|
||||
|
||||
instance Pretty DownloadFailed where
|
||||
pPrint (DownloadFailed reason) =
|
||||
text "Download failed:" <+> pPrint reason
|
||||
case reason of
|
||||
VMaybe (_ :: DownloadFailed) -> pPrint reason
|
||||
_ -> text "Download failed:" <+> pPrint reason
|
||||
|
||||
deriving instance Show DownloadFailed
|
||||
|
||||
|
||||
-- | A build failed.
|
||||
data BuildFailed = forall es . Show (V es) => BuildFailed FilePath (V es)
|
||||
data BuildFailed = forall es . (ToVariantMaybe BuildFailed es, PopVariant BuildFailed es, Pretty (V es), Show (V es)) => BuildFailed FilePath (V es)
|
||||
|
||||
instance Pretty BuildFailed where
|
||||
pPrint (BuildFailed path reason) =
|
||||
text [i|BuildFailed failed in dir "#{path}": #{reason}|]
|
||||
case reason of
|
||||
VMaybe (_ :: BuildFailed) -> pPrint reason
|
||||
_ -> text "BuildFailed failed in dir" <+> text (path <> ":") <+> pPrint reason
|
||||
|
||||
deriving instance Show BuildFailed
|
||||
|
||||
|
||||
-- | Setting the current GHC version failed.
|
||||
data GHCupSetError = forall es . Show (V es) => GHCupSetError (V es)
|
||||
data GHCupSetError = forall es . (ToVariantMaybe GHCupSetError es, PopVariant GHCupSetError es, Show (V es), Pretty (V es)) => GHCupSetError (V es)
|
||||
|
||||
instance Pretty GHCupSetError where
|
||||
pPrint (GHCupSetError reason) =
|
||||
text [i|Setting the current GHC version failed: #{reason}|]
|
||||
case reason of
|
||||
VMaybe (_ :: GHCupSetError) -> pPrint reason
|
||||
_ -> text "Setting the current GHC version failed:" <+> pPrint reason
|
||||
|
||||
deriving instance Show GHCupSetError
|
||||
|
||||
@@ -279,7 +343,7 @@ data ParseError = ParseError String
|
||||
|
||||
instance Pretty ParseError where
|
||||
pPrint (ParseError reason) =
|
||||
text [i|Parsing failed: #{reason}|]
|
||||
text "Parsing failed:" <+> pPrint reason
|
||||
|
||||
instance Exception ParseError
|
||||
|
||||
@@ -289,10 +353,19 @@ data UnexpectedListLength = UnexpectedListLength String
|
||||
|
||||
instance Pretty UnexpectedListLength where
|
||||
pPrint (UnexpectedListLength reason) =
|
||||
text [i|List length unexpected: #{reason}|]
|
||||
text "List length unexpected:" <+> pPrint reason
|
||||
|
||||
instance Exception UnexpectedListLength
|
||||
|
||||
data NoUrlBase = NoUrlBase Text
|
||||
deriving Show
|
||||
|
||||
instance Pretty NoUrlBase where
|
||||
pPrint (NoUrlBase url) =
|
||||
text "Couldn't get a base filename from url" <+> pPrint url
|
||||
|
||||
instance Exception NoUrlBase
|
||||
|
||||
|
||||
|
||||
------------------------
|
||||
@@ -314,23 +387,22 @@ instance
|
||||
|
||||
instance Pretty URIParseError where
|
||||
pPrint (MalformedScheme reason) =
|
||||
text [i|Failed to parse URI. Malformed scheme: #{reason}|]
|
||||
text "Failed to parse URI. Malformed scheme:" <+> text (show reason)
|
||||
pPrint MalformedUserInfo =
|
||||
text [i|Failed to parse URI. Malformed user info.|]
|
||||
text "Failed to parse URI. Malformed user info."
|
||||
pPrint MalformedQuery =
|
||||
text [i|Failed to parse URI. Malformed query.|]
|
||||
text "Failed to parse URI. Malformed query."
|
||||
pPrint MalformedFragment =
|
||||
text [i|Failed to parse URI. Malformed fragment.|]
|
||||
text "Failed to parse URI. Malformed fragment."
|
||||
pPrint MalformedHost =
|
||||
text [i|Failed to parse URI. Malformed host.|]
|
||||
text "Failed to parse URI. Malformed host."
|
||||
pPrint MalformedPort =
|
||||
text [i|Failed to parse URI. Malformed port.|]
|
||||
text "Failed to parse URI. Malformed port."
|
||||
pPrint MalformedPath =
|
||||
text [i|Failed to parse URI. Malformed path.|]
|
||||
text "Failed to parse URI. Malformed path."
|
||||
pPrint (OtherError err) =
|
||||
text [i|Failed to parse URI: #{err}|]
|
||||
text "Failed to parse URI:" <+> pPrint err
|
||||
|
||||
#if !defined(TAR)
|
||||
instance Pretty ArchiveResult where
|
||||
pPrint ArchiveFatal = text "Archive result: fatal"
|
||||
pPrint ArchiveFailed = text "Archive result: failed"
|
||||
@@ -338,14 +410,6 @@ instance Pretty ArchiveResult where
|
||||
pPrint ArchiveRetry = text "Archive result: retry"
|
||||
pPrint ArchiveOk = text "Archive result: Ok"
|
||||
pPrint ArchiveEOF = text "Archive result: EOF"
|
||||
#else
|
||||
instance Pretty Tar.FormatError where
|
||||
pPrint Tar.TruncatedArchive = text "Truncated archive"
|
||||
pPrint Tar.ShortTrailer = text "Short trailer"
|
||||
pPrint Tar.BadTrailer = text "Bad trailer"
|
||||
pPrint Tar.TrailingJunk = text "Trailing junk"
|
||||
pPrint Tar.ChecksumIncorrect = text "Checksum incorrect"
|
||||
pPrint Tar.NotTarFormat = text "Not a tar format"
|
||||
pPrint Tar.UnrecognisedTarFormat = text "Unrecognised tar format"
|
||||
pPrint Tar.HeaderBadNumericEncoding = text "Header has bad numeric encoding"
|
||||
#endif
|
||||
|
||||
instance Pretty T.Text where
|
||||
pPrint = text . T.unpack
|
||||
|
||||
@@ -20,20 +20,20 @@ module GHCup.Platform where
|
||||
|
||||
import GHCup.Errors
|
||||
import GHCup.Types
|
||||
import GHCup.Types.Optics
|
||||
import GHCup.Types.JSON ( )
|
||||
import GHCup.Utils.File
|
||||
import GHCup.Utils.Logger
|
||||
import GHCup.Utils.Prelude
|
||||
import GHCup.Utils.String.QQ
|
||||
|
||||
import Control.Applicative
|
||||
import Control.Exception.Safe
|
||||
import Control.Monad
|
||||
import Control.Monad.Logger
|
||||
import Control.Monad.Reader
|
||||
import Data.ByteString ( ByteString )
|
||||
import Data.Foldable
|
||||
import Data.Maybe
|
||||
import Data.String.Interpolate
|
||||
import Data.Text ( Text )
|
||||
import Data.Versions
|
||||
import Haskus.Utils.Variant.Excepts
|
||||
@@ -58,7 +58,7 @@ import qualified Data.Text.IO as T
|
||||
|
||||
|
||||
-- | Get the full platform request, consisting of architecture, distro, ...
|
||||
platformRequest :: (Alternative m, MonadFail m, MonadLogger m, MonadCatch m, MonadIO m)
|
||||
platformRequest :: (MonadReader env m, Alternative m, MonadFail m, HasLog env, MonadCatch m, MonadIO m)
|
||||
=> Excepts
|
||||
'[NoCompatiblePlatform, NoCompatibleArch, DistroNotFound]
|
||||
m
|
||||
@@ -83,7 +83,7 @@ getArchitecture = case arch of
|
||||
what -> Left (NoCompatibleArch what)
|
||||
|
||||
|
||||
getPlatform :: (Alternative m, MonadLogger m, MonadCatch m, MonadIO m, MonadFail m)
|
||||
getPlatform :: (Alternative m, MonadReader env m, HasLog env, MonadCatch m, MonadIO m, MonadFail m)
|
||||
=> Excepts
|
||||
'[NoCompatiblePlatform, DistroNotFound]
|
||||
m
|
||||
@@ -108,7 +108,7 @@ getPlatform = do
|
||||
pure $ PlatformResult { _platform = FreeBSD, _distroVersion = ver }
|
||||
"mingw32" -> pure PlatformResult { _platform = Windows, _distroVersion = Nothing }
|
||||
what -> throwE $ NoCompatiblePlatform what
|
||||
lift $ $(logDebug) [i|Identified Platform as: #{prettyShow pfr}|]
|
||||
lift $ logDebug $ "Identified Platform as: " <> T.pack (prettyShow pfr)
|
||||
pure pfr
|
||||
where
|
||||
getFreeBSDVersion = lift $ fmap _stdOut $ executeOut "freebsd-version" [] Nothing
|
||||
@@ -142,9 +142,7 @@ getLinuxDistro = do
|
||||
| otherwise -> UnknownLinux
|
||||
pure (distro, parsedVer)
|
||||
where
|
||||
hasWord t matches = foldr (\x y -> match (regex x) (T.unpack t) || y)
|
||||
False
|
||||
matches
|
||||
hasWord t = any (\x -> match (regex x) (T.unpack t))
|
||||
where
|
||||
regex x = makeRegexOpts compIgnoreCase execBlank ([s|\<|] ++ x ++ [s|\>|])
|
||||
|
||||
|
||||
@@ -60,9 +60,10 @@ getCommonRequirements pr tr =
|
||||
prettyRequirements :: Requirements -> T.Text
|
||||
prettyRequirements Requirements {..} =
|
||||
let d = if not . null $ _distroPKGs
|
||||
then
|
||||
"\n Please install the following distro packages: "
|
||||
<> T.intercalate " " _distroPKGs
|
||||
then "\n Please ensure the following distro packages "
|
||||
<> "are installed before continuing (you can exit ghcup "
|
||||
<> "and return at any time): "
|
||||
<> T.intercalate " " _distroPKGs
|
||||
else ""
|
||||
n = if not . T.null $ _notes then "\n Note: " <> _notes else ""
|
||||
in "System requirements " <> d <> n
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
{-# OPTIONS_GHC -Wno-orphans #-}
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE BangPatterns #-}
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE DeriveGeneric #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE FlexibleInstances #-}
|
||||
{-# LANGUAGE DuplicateRecordFields #-}
|
||||
|
||||
{-|
|
||||
Module : GHCup.Types
|
||||
@@ -20,20 +25,17 @@ module GHCup.Types
|
||||
)
|
||||
where
|
||||
|
||||
import Control.Applicative
|
||||
import Control.Monad.Logger
|
||||
import Control.DeepSeq ( NFData, rnf )
|
||||
import Data.Map.Strict ( Map )
|
||||
import Data.List.NonEmpty ( NonEmpty (..) )
|
||||
import Data.Text ( Text )
|
||||
import Data.Versions
|
||||
import Haskus.Utils.Variant.Excepts
|
||||
import Text.PrettyPrint.HughesPJClass (Pretty, pPrint, text)
|
||||
import URI.ByteString
|
||||
#if defined(BRICK)
|
||||
import Graphics.Vty ( Key(..) )
|
||||
#endif
|
||||
|
||||
import qualified Control.Monad.Trans.Class as Trans
|
||||
import qualified Data.Text as T
|
||||
import qualified GHC.Generics as GHC
|
||||
|
||||
@@ -60,6 +62,8 @@ data GHCupInfo = GHCupInfo
|
||||
}
|
||||
deriving (Show, GHC.Generic)
|
||||
|
||||
instance NFData GHCupInfo
|
||||
|
||||
|
||||
|
||||
-------------------------
|
||||
@@ -79,6 +83,8 @@ data Requirements = Requirements
|
||||
}
|
||||
deriving (Show, GHC.Generic)
|
||||
|
||||
instance NFData Requirements
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -105,9 +111,20 @@ data Tool = GHC
|
||||
| Stack
|
||||
deriving (Eq, GHC.Generic, Ord, Show, Enum, Bounded)
|
||||
|
||||
instance Pretty Tool where
|
||||
pPrint GHC = text "ghc"
|
||||
pPrint Cabal = text "cabal"
|
||||
pPrint GHCup = text "ghcup"
|
||||
pPrint HLS = text "hls"
|
||||
pPrint Stack = text "stack"
|
||||
|
||||
instance NFData Tool
|
||||
|
||||
data GlobalTool = ShimGen
|
||||
deriving (Eq, GHC.Generic, Ord, Show, Enum, Bounded)
|
||||
|
||||
instance NFData GlobalTool
|
||||
|
||||
|
||||
-- | All necessary information of a tool version, including
|
||||
-- source download and per-architecture downloads.
|
||||
@@ -123,16 +140,20 @@ data VersionInfo = VersionInfo
|
||||
}
|
||||
deriving (Eq, GHC.Generic, Show)
|
||||
|
||||
instance NFData VersionInfo
|
||||
|
||||
|
||||
-- | A tag. These are currently attached to a version of a tool.
|
||||
data Tag = Latest
|
||||
| Recommended
|
||||
| Prerelease
|
||||
| Base PVP
|
||||
| Old -- ^ old version are hidden by default in TUI
|
||||
| Old -- ^ old versions are hidden by default in TUI
|
||||
| UnknownTag String -- ^ used for upwardscompat
|
||||
deriving (Ord, Eq, GHC.Generic, Show) -- FIXME: manual JSON instance
|
||||
|
||||
instance NFData Tag
|
||||
|
||||
tagToString :: Tag -> String
|
||||
tagToString Recommended = "recommended"
|
||||
tagToString Latest = "latest"
|
||||
@@ -159,6 +180,8 @@ data Architecture = A_64
|
||||
| A_ARM64
|
||||
deriving (Eq, GHC.Generic, Ord, Show)
|
||||
|
||||
instance NFData Architecture
|
||||
|
||||
archToString :: Architecture -> String
|
||||
archToString A_64 = "x86_64"
|
||||
archToString A_32 = "i386"
|
||||
@@ -181,6 +204,8 @@ data Platform = Linux LinuxDistro
|
||||
-- ^ must exit
|
||||
deriving (Eq, GHC.Generic, Ord, Show)
|
||||
|
||||
instance NFData Platform
|
||||
|
||||
platformToString :: Platform -> String
|
||||
platformToString (Linux distro) = "linux-" ++ distroToString distro
|
||||
platformToString Darwin = "darwin"
|
||||
@@ -206,10 +231,12 @@ data LinuxDistro = Debian
|
||||
-- ^ must exit
|
||||
deriving (Eq, GHC.Generic, Ord, Show)
|
||||
|
||||
instance NFData LinuxDistro
|
||||
|
||||
distroToString :: LinuxDistro -> String
|
||||
distroToString Debian = "debian"
|
||||
distroToString Ubuntu = "ubuntu"
|
||||
distroToString Mint= "mint"
|
||||
distroToString Mint = "mint"
|
||||
distroToString Fedora = "fedora"
|
||||
distroToString CentOS = "centos"
|
||||
distroToString RedHat = "redhat"
|
||||
@@ -232,6 +259,7 @@ data DownloadInfo = DownloadInfo
|
||||
}
|
||||
deriving (Eq, Ord, GHC.Generic, Show)
|
||||
|
||||
instance NFData DownloadInfo
|
||||
|
||||
|
||||
|
||||
@@ -245,6 +273,8 @@ data TarDir = RealDir FilePath
|
||||
| RegexDir String -- ^ will be compiled to regex, the first match will "win"
|
||||
deriving (Eq, Ord, GHC.Generic, Show)
|
||||
|
||||
instance NFData TarDir
|
||||
|
||||
instance Pretty TarDir where
|
||||
pPrint (RealDir path) = text path
|
||||
pPrint (RegexDir regex) = text regex
|
||||
@@ -257,6 +287,10 @@ data URLSource = GHCupURL
|
||||
| AddSource (Either GHCupInfo URI) -- ^ merge with GHCupURL
|
||||
deriving (GHC.Generic, Show)
|
||||
|
||||
instance NFData URLSource
|
||||
instance NFData (URIRef Absolute) where
|
||||
rnf (URI !_ !_ !_ !_ !_) = ()
|
||||
|
||||
|
||||
data UserSettings = UserSettings
|
||||
{ uCache :: Maybe Bool
|
||||
@@ -266,11 +300,50 @@ data UserSettings = UserSettings
|
||||
, uDownloader :: Maybe Downloader
|
||||
, uKeyBindings :: Maybe UserKeyBindings
|
||||
, uUrlSource :: Maybe URLSource
|
||||
, uNoNetwork :: Maybe Bool
|
||||
, uGPGSetting :: Maybe GPGSetting
|
||||
}
|
||||
deriving (Show, GHC.Generic)
|
||||
|
||||
defaultUserSettings :: UserSettings
|
||||
defaultUserSettings = UserSettings Nothing Nothing Nothing Nothing Nothing Nothing Nothing
|
||||
defaultUserSettings = UserSettings Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing
|
||||
|
||||
fromSettings :: Settings -> Maybe KeyBindings -> UserSettings
|
||||
fromSettings Settings{..} Nothing =
|
||||
UserSettings {
|
||||
uCache = Just cache
|
||||
, uNoVerify = Just noVerify
|
||||
, uVerbose = Just verbose
|
||||
, uKeepDirs = Just keepDirs
|
||||
, uDownloader = Just downloader
|
||||
, uNoNetwork = Just noNetwork
|
||||
, uKeyBindings = Nothing
|
||||
, uUrlSource = Just urlSource
|
||||
, uGPGSetting = Just gpgSetting
|
||||
}
|
||||
fromSettings Settings{..} (Just KeyBindings{..}) =
|
||||
let ukb = UserKeyBindings
|
||||
{ kUp = Just bUp
|
||||
, kDown = Just bDown
|
||||
, kQuit = Just bQuit
|
||||
, kInstall = Just bInstall
|
||||
, kUninstall = Just bUninstall
|
||||
, kSet = Just bSet
|
||||
, kChangelog = Just bChangelog
|
||||
, kShowAll = Just bShowAllVersions
|
||||
, kShowAllTools = Just bShowAllTools
|
||||
}
|
||||
in UserSettings {
|
||||
uCache = Just cache
|
||||
, uNoVerify = Just noVerify
|
||||
, uVerbose = Just verbose
|
||||
, uKeepDirs = Just keepDirs
|
||||
, uDownloader = Just downloader
|
||||
, uNoNetwork = Just noNetwork
|
||||
, uKeyBindings = Just ukb
|
||||
, uUrlSource = Just urlSource
|
||||
, uGPGSetting = Just gpgSetting
|
||||
}
|
||||
|
||||
data UserKeyBindings = UserKeyBindings
|
||||
{ kUp :: Maybe Key
|
||||
@@ -298,6 +371,9 @@ data KeyBindings = KeyBindings
|
||||
}
|
||||
deriving (Show, GHC.Generic)
|
||||
|
||||
instance NFData KeyBindings
|
||||
instance NFData Key
|
||||
|
||||
defaultKeyBindings :: KeyBindings
|
||||
defaultKeyBindings = KeyBindings
|
||||
{ bUp = KUp
|
||||
@@ -317,7 +393,20 @@ data AppState = AppState
|
||||
, keyBindings :: KeyBindings
|
||||
, ghcupInfo :: GHCupInfo
|
||||
, pfreq :: PlatformRequest
|
||||
} deriving (Show)
|
||||
, loggerConfig :: LoggerConfig
|
||||
} deriving (Show, GHC.Generic)
|
||||
|
||||
instance NFData AppState
|
||||
|
||||
data LeanAppState = LeanAppState
|
||||
{ settings :: Settings
|
||||
, dirs :: Dirs
|
||||
, keyBindings :: KeyBindings
|
||||
, loggerConfig :: LoggerConfig
|
||||
} deriving (Show, GHC.Generic)
|
||||
|
||||
instance NFData LeanAppState
|
||||
|
||||
|
||||
data Settings = Settings
|
||||
{ cache :: Bool
|
||||
@@ -326,29 +415,48 @@ data Settings = Settings
|
||||
, downloader :: Downloader
|
||||
, verbose :: Bool
|
||||
, urlSource :: URLSource
|
||||
, noNetwork :: Bool
|
||||
, gpgSetting :: GPGSetting
|
||||
, noColor :: Bool -- this also exists in LoggerConfig
|
||||
}
|
||||
deriving (Show, GHC.Generic)
|
||||
|
||||
instance NFData Settings
|
||||
|
||||
data Dirs = Dirs
|
||||
{ baseDir :: FilePath
|
||||
, binDir :: FilePath
|
||||
, cacheDir :: FilePath
|
||||
, logsDir :: FilePath
|
||||
, confDir :: FilePath
|
||||
, recycleDir :: FilePath -- mainly used on windows
|
||||
}
|
||||
deriving Show
|
||||
deriving (Show, GHC.Generic)
|
||||
|
||||
instance NFData Dirs
|
||||
|
||||
data KeepDirs = Always
|
||||
| Errors
|
||||
| Never
|
||||
deriving (Eq, Show, Ord)
|
||||
deriving (Eq, Show, Ord, GHC.Generic)
|
||||
|
||||
instance NFData KeepDirs
|
||||
|
||||
data Downloader = Curl
|
||||
| Wget
|
||||
#if defined(INTERNAL_DOWNLOADER)
|
||||
| Internal
|
||||
#endif
|
||||
deriving (Eq, Show, Ord)
|
||||
deriving (Eq, Show, Ord, GHC.Generic)
|
||||
|
||||
instance NFData Downloader
|
||||
|
||||
data GPGSetting = GPGStrict
|
||||
| GPGLax
|
||||
| GPGNone
|
||||
deriving (Eq, Show, Ord, GHC.Generic)
|
||||
|
||||
instance NFData GPGSetting
|
||||
|
||||
data DebugInfo = DebugInfo
|
||||
{ diBaseDir :: FilePath
|
||||
@@ -371,7 +479,9 @@ data PlatformResult = PlatformResult
|
||||
{ _platform :: Platform
|
||||
, _distroVersion :: Maybe Versioning
|
||||
}
|
||||
deriving (Eq, Show)
|
||||
deriving (Eq, Show, GHC.Generic)
|
||||
|
||||
instance NFData PlatformResult
|
||||
|
||||
platResToString :: PlatformResult -> String
|
||||
platResToString PlatformResult { _platform = plat, _distroVersion = Just v' }
|
||||
@@ -387,7 +497,9 @@ data PlatformRequest = PlatformRequest
|
||||
, _rPlatform :: Platform
|
||||
, _rVersion :: Maybe Versioning
|
||||
}
|
||||
deriving (Eq, Show)
|
||||
deriving (Eq, Show, GHC.Generic)
|
||||
|
||||
instance NFData PlatformRequest
|
||||
|
||||
pfReqToString :: PlatformRequest -> String
|
||||
pfReqToString (PlatformRequest arch plat ver) =
|
||||
@@ -434,6 +546,8 @@ data VersionCmp = VR_gt Versioning
|
||||
| VR_eq Versioning
|
||||
deriving (Eq, GHC.Generic, Ord, Show)
|
||||
|
||||
instance NFData VersionCmp
|
||||
|
||||
|
||||
-- | A version range. Supports && and ||, but not arbitrary
|
||||
-- combinations. This is a little simplified.
|
||||
@@ -441,6 +555,7 @@ data VersionRange = SimpleRange (NonEmpty VersionCmp) -- And
|
||||
| OrRange (NonEmpty VersionCmp) VersionRange
|
||||
deriving (Eq, GHC.Generic, Ord, Show)
|
||||
|
||||
instance NFData VersionRange
|
||||
|
||||
instance Pretty Versioning where
|
||||
pPrint = text . T.unpack . prettyV
|
||||
@@ -448,15 +563,26 @@ instance Pretty Versioning where
|
||||
instance Pretty Version where
|
||||
pPrint = text . T.unpack . prettyVer
|
||||
|
||||
instance Show (a -> b) where
|
||||
show _ = "<function>"
|
||||
|
||||
instance (Monad m, Alternative m) => Alternative (LoggingT m) where
|
||||
empty = Trans.lift empty
|
||||
{-# INLINE empty #-}
|
||||
m <|> n = LoggingT $ \ r -> runLoggingT m r <|> runLoggingT n r
|
||||
{-# INLINE (<|>) #-}
|
||||
instance Show (IO ()) where
|
||||
show _ = "<io>"
|
||||
|
||||
|
||||
instance MonadLogger m => MonadLogger (Excepts e m) where
|
||||
monadLoggerLog a b c d = Trans.lift $ monadLoggerLog a b c d
|
||||
data LogLevel = Warn
|
||||
| Info
|
||||
| Debug
|
||||
| Error
|
||||
deriving (Eq, Ord, Show)
|
||||
|
||||
data LoggerConfig = LoggerConfig
|
||||
{ lcPrintDebug :: Bool -- ^ whether to print debug in colorOutter
|
||||
, consoleOutter :: T.Text -> IO () -- ^ how to write the console output
|
||||
, fileOutter :: T.Text -> IO () -- ^ how to write the file output
|
||||
, fancyColors :: Bool
|
||||
}
|
||||
deriving Show
|
||||
|
||||
instance NFData LoggerConfig where
|
||||
rnf (LoggerConfig !lcPrintDebug !_ !_ !fancyColors) = rnf (lcPrintDebug, fancyColors)
|
||||
|
||||
@@ -24,6 +24,8 @@ module GHCup.Types.JSON where
|
||||
import GHCup.Types
|
||||
import GHCup.Utils.MegaParsec
|
||||
import GHCup.Utils.Prelude
|
||||
import GHCup.Utils.Logger () -- TH is broken shite and needs GHCup.Utils.Logger for linking, although we don't depend on the file.
|
||||
-- This is due to the boot file.
|
||||
|
||||
import Control.Applicative ( (<|>) )
|
||||
import Data.Aeson
|
||||
@@ -42,7 +44,7 @@ import qualified Text.Megaparsec as MP
|
||||
import qualified Text.Megaparsec.Char as MPC
|
||||
|
||||
|
||||
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } { fieldLabelModifier = removeLensFieldLabel } ''Architecture
|
||||
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''Architecture
|
||||
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''LinuxDistro
|
||||
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''VSep
|
||||
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''VUnit
|
||||
@@ -54,6 +56,7 @@ deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''Tool
|
||||
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''GlobalTool
|
||||
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''KeepDirs
|
||||
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''Downloader
|
||||
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''GPGSetting
|
||||
|
||||
instance ToJSON Tag where
|
||||
toJSON Latest = String "Latest"
|
||||
@@ -316,3 +319,6 @@ deriveJSON defaultOptions { sumEncoding = ObjectWithSingleField } ''URLSource
|
||||
deriveJSON defaultOptions { sumEncoding = ObjectWithSingleField } ''Key
|
||||
deriveJSON defaultOptions { fieldLabelModifier = \str' -> maybe str' T.unpack . T.stripPrefix (T.pack "k-") . T.pack . kebab $ str' } ''UserKeyBindings
|
||||
deriveJSON defaultOptions { fieldLabelModifier = \str' -> maybe str' T.unpack . T.stripPrefix (T.pack "u-") . T.pack . kebab $ str' } ''UserSettings
|
||||
|
||||
deriveToJSON defaultOptions { fieldLabelModifier = kebab } ''Settings
|
||||
deriveToJSON defaultOptions { fieldLabelModifier = drop 2 . kebab } ''KeyBindings -- move under key-bindings key
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
{-# LANGUAGE TemplateHaskell #-}
|
||||
{-# OPTIONS_GHC -Wno-orphans #-}
|
||||
{-# LANGUAGE TemplateHaskell #-}
|
||||
{-# LANGUAGE ConstraintKinds #-}
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE DuplicateRecordFields #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE AllowAmbiguousTypes #-}
|
||||
{-# LANGUAGE MultiParamTypeClasses #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
|
||||
{-|
|
||||
Module : GHCup.Types.Optics
|
||||
@@ -13,10 +21,12 @@ module GHCup.Types.Optics where
|
||||
|
||||
import GHCup.Types
|
||||
|
||||
import Data.ByteString ( ByteString )
|
||||
import Control.Monad.Reader
|
||||
import Data.ByteString ( ByteString )
|
||||
import Optics
|
||||
import URI.ByteString
|
||||
|
||||
|
||||
makePrisms ''Tool
|
||||
makePrisms ''Architecture
|
||||
makePrisms ''LinuxDistro
|
||||
@@ -58,3 +68,95 @@ pathL' = lensVL pathL
|
||||
|
||||
queryL' :: Lens' (URIRef a) Query
|
||||
queryL' = lensVL queryL
|
||||
|
||||
|
||||
|
||||
----------------------
|
||||
--[ Lens utilities ]--
|
||||
----------------------
|
||||
|
||||
|
||||
gets :: forall f a env m . (MonadReader env m, LabelOptic' f A_Lens env a)
|
||||
=> m a
|
||||
gets = asks (^. labelOptic @f)
|
||||
|
||||
|
||||
getAppState :: MonadReader AppState m => m AppState
|
||||
getAppState = ask
|
||||
|
||||
|
||||
getLeanAppState :: ( MonadReader env m
|
||||
, LabelOptic' "settings" A_Lens env Settings
|
||||
, LabelOptic' "dirs" A_Lens env Dirs
|
||||
, LabelOptic' "keyBindings" A_Lens env KeyBindings
|
||||
, LabelOptic' "loggerConfig" A_Lens env LoggerConfig
|
||||
)
|
||||
=> m LeanAppState
|
||||
getLeanAppState = do
|
||||
s <- gets @"settings"
|
||||
d <- gets @"dirs"
|
||||
k <- gets @"keyBindings"
|
||||
l <- gets @"loggerConfig"
|
||||
pure (LeanAppState s d k l)
|
||||
|
||||
|
||||
getSettings :: ( MonadReader env m
|
||||
, LabelOptic' "settings" A_Lens env Settings
|
||||
)
|
||||
=> m Settings
|
||||
getSettings = gets @"settings"
|
||||
|
||||
|
||||
getDirs :: ( MonadReader env m
|
||||
, LabelOptic' "dirs" A_Lens env Dirs
|
||||
)
|
||||
=> m Dirs
|
||||
getDirs = gets @"dirs"
|
||||
|
||||
|
||||
getLogCleanup :: ( MonadReader env m
|
||||
, LabelOptic' "logCleanup" A_Lens env (IO ())
|
||||
)
|
||||
=> m (IO ())
|
||||
getLogCleanup = gets @"logCleanup"
|
||||
|
||||
|
||||
getKeyBindings :: ( MonadReader env m
|
||||
, LabelOptic' "keyBindings" A_Lens env KeyBindings
|
||||
)
|
||||
=> m KeyBindings
|
||||
getKeyBindings = gets @"keyBindings"
|
||||
|
||||
|
||||
getGHCupInfo :: ( MonadReader env m
|
||||
, LabelOptic' "ghcupInfo" A_Lens env GHCupInfo
|
||||
)
|
||||
=> m GHCupInfo
|
||||
getGHCupInfo = gets @"ghcupInfo"
|
||||
|
||||
|
||||
getPlatformReq :: ( MonadReader env m
|
||||
, LabelOptic' "pfreq" A_Lens env PlatformRequest
|
||||
)
|
||||
=> m PlatformRequest
|
||||
getPlatformReq = gets @"pfreq"
|
||||
|
||||
|
||||
type HasSettings env = (LabelOptic' "settings" A_Lens env Settings)
|
||||
type HasDirs env = (LabelOptic' "dirs" A_Lens env Dirs)
|
||||
type HasKeyBindings env = (LabelOptic' "keyBindings" A_Lens env KeyBindings)
|
||||
type HasGHCupInfo env = (LabelOptic' "ghcupInfo" A_Lens env GHCupInfo)
|
||||
type HasPlatformReq env = (LabelOptic' "pfreq" A_Lens env PlatformRequest)
|
||||
type HasLog env = (LabelOptic' "loggerConfig" A_Lens env LoggerConfig)
|
||||
|
||||
|
||||
getCache :: (MonadReader env m, HasSettings env) => m Bool
|
||||
getCache = getSettings <&> cache
|
||||
|
||||
|
||||
getDownloader :: (MonadReader env m, HasSettings env) => m Downloader
|
||||
getDownloader = getSettings <&> downloader
|
||||
|
||||
|
||||
instance LabelOptic "dirs" A_Lens Dirs Dirs Dirs Dirs where
|
||||
labelOptic = lens id (\_ d -> d)
|
||||
|
||||
@@ -2,9 +2,7 @@
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE QuasiQuotes #-}
|
||||
{-# LANGUAGE ViewPatterns #-}
|
||||
{-# LANGUAGE TemplateHaskell #-}
|
||||
|
||||
{-|
|
||||
Module : GHCup.Utils.Dirs
|
||||
@@ -16,7 +14,7 @@ Stability : experimental
|
||||
Portability : portable
|
||||
-}
|
||||
module GHCup.Utils.Dirs
|
||||
( getDirs
|
||||
( getAllDirs
|
||||
, ghcupBaseDir
|
||||
, ghcupConfigFile
|
||||
, ghcupCacheDir
|
||||
@@ -26,6 +24,11 @@ module GHCup.Utils.Dirs
|
||||
, parseGHCupGHCDir
|
||||
, relativeSymlink
|
||||
, withGHCupTmpDir
|
||||
, getConfigFilePath
|
||||
#if !defined(IS_WINDOWS)
|
||||
, useXDG
|
||||
#endif
|
||||
, cleanupTrash
|
||||
)
|
||||
where
|
||||
|
||||
@@ -33,24 +36,22 @@ where
|
||||
import GHCup.Errors
|
||||
import GHCup.Types
|
||||
import GHCup.Types.JSON ( )
|
||||
import GHCup.Types.Optics
|
||||
import GHCup.Utils.MegaParsec
|
||||
import GHCup.Utils.Logger
|
||||
import GHCup.Utils.Prelude
|
||||
|
||||
import Control.Exception.Safe
|
||||
import Control.Monad
|
||||
import Control.Monad.IO.Unlift
|
||||
import Control.Monad.Logger
|
||||
import Control.Monad.Reader
|
||||
import Control.Monad.Trans.Resource hiding (throwM)
|
||||
import Data.Bifunctor
|
||||
import Data.Maybe
|
||||
import Data.String.Interpolate
|
||||
import GHC.IO.Exception ( IOErrorType(NoSuchThing) )
|
||||
import Haskus.Utils.Variant.Excepts
|
||||
import Optics
|
||||
#if !defined(IS_WINDOWS)
|
||||
import System.Directory
|
||||
#endif
|
||||
import System.DiskSpace
|
||||
import System.Environment
|
||||
import System.FilePath
|
||||
@@ -58,7 +59,7 @@ import System.IO.Temp
|
||||
|
||||
import qualified Data.ByteString as BS
|
||||
import qualified Data.Text as T
|
||||
import qualified Data.Yaml as Y
|
||||
import qualified Data.YAML.Aeson as Y
|
||||
import qualified Text.Megaparsec as MP
|
||||
import Control.Concurrent (threadDelay)
|
||||
|
||||
@@ -186,13 +187,21 @@ ghcupLogsDir = do
|
||||
#endif
|
||||
|
||||
|
||||
getDirs :: IO Dirs
|
||||
getDirs = do
|
||||
baseDir <- ghcupBaseDir
|
||||
binDir <- ghcupBinDir
|
||||
cacheDir <- ghcupCacheDir
|
||||
logsDir <- ghcupLogsDir
|
||||
confDir <- ghcupConfigDir
|
||||
-- | '~/.ghcup/trash'.
|
||||
-- Mainly used on windows to improve file removal operations
|
||||
ghcupRecycleDir :: IO FilePath
|
||||
ghcupRecycleDir = ghcupBaseDir <&> (</> "trash")
|
||||
|
||||
|
||||
|
||||
getAllDirs :: IO Dirs
|
||||
getAllDirs = do
|
||||
baseDir <- ghcupBaseDir
|
||||
binDir <- ghcupBinDir
|
||||
cacheDir <- ghcupCacheDir
|
||||
logsDir <- ghcupLogsDir
|
||||
confDir <- ghcupConfigDir
|
||||
recycleDir <- ghcupRecycleDir
|
||||
pure Dirs { .. }
|
||||
|
||||
|
||||
@@ -201,16 +210,19 @@ getDirs = do
|
||||
--[ GHCup files ]--
|
||||
-------------------
|
||||
|
||||
getConfigFilePath :: (MonadIO m) => m FilePath
|
||||
getConfigFilePath = do
|
||||
confDir <- liftIO ghcupConfigDir
|
||||
pure $ confDir </> "config.yaml"
|
||||
|
||||
ghcupConfigFile :: (MonadIO m)
|
||||
=> Excepts '[JSONError] m UserSettings
|
||||
ghcupConfigFile = do
|
||||
confDir <- liftIO ghcupConfigDir
|
||||
let file = confDir </> "config.yaml"
|
||||
contents <- liftIO $ handleIO' NoSuchThing (\_ -> pure Nothing) $ Just <$> BS.readFile file
|
||||
filepath <- getConfigFilePath
|
||||
contents <- liftIO $ handleIO' NoSuchThing (\_ -> pure Nothing) $ Just <$> BS.readFile filepath
|
||||
case contents of
|
||||
Nothing -> pure defaultUserSettings
|
||||
Just contents' -> lE' JSONDecodeError . first show . Y.decodeEither' $ contents'
|
||||
Just contents' -> lE' JSONDecodeError . first snd . Y.decode1Strict $ contents'
|
||||
|
||||
|
||||
-------------------------
|
||||
@@ -219,9 +231,9 @@ ghcupConfigFile = do
|
||||
|
||||
|
||||
-- | ~/.ghcup/ghc by default.
|
||||
ghcupGHCBaseDir :: (MonadReader AppState m) => m FilePath
|
||||
ghcupGHCBaseDir :: (MonadReader env m, HasDirs env) => m FilePath
|
||||
ghcupGHCBaseDir = do
|
||||
AppState { dirs = Dirs {..} } <- ask
|
||||
Dirs {..} <- getDirs
|
||||
pure (baseDir </> "ghc")
|
||||
|
||||
|
||||
@@ -229,7 +241,7 @@ ghcupGHCBaseDir = do
|
||||
-- The dir may be of the form
|
||||
-- * armv7-unknown-linux-gnueabihf-8.8.3
|
||||
-- * 8.8.4
|
||||
ghcupGHCDir :: (MonadReader AppState m, MonadThrow m)
|
||||
ghcupGHCDir :: (MonadReader env m, HasDirs env, MonadThrow m)
|
||||
=> GHCTargetVersion
|
||||
-> m FilePath
|
||||
ghcupGHCDir ver = do
|
||||
@@ -244,29 +256,61 @@ parseGHCupGHCDir (T.pack -> fp) =
|
||||
throwEither $ MP.parse ghcTargetVerP "" fp
|
||||
|
||||
|
||||
mkGhcupTmpDir :: (MonadUnliftIO m, MonadLogger m, MonadCatch m, MonadThrow m, MonadIO m) => m FilePath
|
||||
mkGhcupTmpDir :: ( MonadReader env m
|
||||
, HasDirs env
|
||||
, MonadUnliftIO m
|
||||
, HasLog env
|
||||
, MonadCatch m
|
||||
, MonadThrow m
|
||||
, MonadMask m
|
||||
, MonadIO m)
|
||||
=> m FilePath
|
||||
mkGhcupTmpDir = do
|
||||
tmpdir <- liftIO getCanonicalTemporaryDirectory
|
||||
|
||||
let minSpace = 5000 -- a rough guess, aight?
|
||||
space <- handleIO (\_ -> pure Nothing) $ fmap Just $ liftIO $ getAvailSpace tmpdir
|
||||
when (maybe False (toBytes minSpace >) space) $ do
|
||||
$(logWarn) [i|Possibly insufficient disk space on #{tmpdir}. At least #{minSpace} MB are recommended, but only #{toMB (fromJust space)} are free. Consider freeing up disk space or setting TMPDIR env variable.|]
|
||||
$(logWarn)
|
||||
logWarn ("Possibly insufficient disk space on "
|
||||
<> T.pack tmpdir
|
||||
<> ". At least "
|
||||
<> T.pack (show minSpace)
|
||||
<> " MB are recommended, but only "
|
||||
<> toMB (fromJust space)
|
||||
<> " are free. Consider freeing up disk space or setting TMPDIR env variable.")
|
||||
logWarn
|
||||
"...waiting for 10 seconds before continuing anyway, you can still abort..."
|
||||
liftIO $ threadDelay 10000000 -- give the user a sec to intervene
|
||||
|
||||
liftIO $ createTempDirectory tmpdir "ghcup"
|
||||
where
|
||||
toBytes mb = mb * 1024 * 1024
|
||||
toMB b = show (truncate' (fromIntegral b / (1024 * 1024) :: Double) 2)
|
||||
toMB b = T.pack $ show (truncate' (fromIntegral b / (1024 * 1024) :: Double) 2)
|
||||
truncate' :: Double -> Int -> Double
|
||||
truncate' x n = fromIntegral (floor (x * t) :: Integer) / t
|
||||
where t = 10^n
|
||||
|
||||
|
||||
withGHCupTmpDir :: (MonadUnliftIO m, MonadLogger m, MonadCatch m, MonadResource m, MonadThrow m, MonadIO m) => m FilePath
|
||||
withGHCupTmpDir = snd <$> withRunInIO (\run -> run $ allocate (run mkGhcupTmpDir) rmPath)
|
||||
withGHCupTmpDir :: ( MonadReader env m
|
||||
, HasDirs env
|
||||
, HasLog env
|
||||
, HasSettings env
|
||||
, MonadUnliftIO m
|
||||
, MonadCatch m
|
||||
, MonadResource m
|
||||
, MonadThrow m
|
||||
, MonadMask m
|
||||
, MonadIO m)
|
||||
=> m FilePath
|
||||
withGHCupTmpDir = snd <$> withRunInIO (\run ->
|
||||
run
|
||||
$ allocate
|
||||
(run mkGhcupTmpDir)
|
||||
(\fp ->
|
||||
handleIO (\e -> run
|
||||
$ logDebug ("Resource cleanup failed for " <> T.pack fp <> ", error was: " <> T.pack (displayException e)))
|
||||
. rmPathForcibly
|
||||
$ fp))
|
||||
|
||||
|
||||
|
||||
@@ -294,3 +338,22 @@ relativeSymlink p1 p2 =
|
||||
<> joinPath ([pathSeparator] : drop (length common) d2)
|
||||
|
||||
|
||||
cleanupTrash :: ( MonadIO m
|
||||
, MonadMask m
|
||||
, MonadReader env m
|
||||
, HasLog env
|
||||
, HasDirs env
|
||||
, HasSettings env
|
||||
)
|
||||
=> m ()
|
||||
cleanupTrash = do
|
||||
Dirs { recycleDir } <- getDirs
|
||||
contents <- liftIO $ listDirectory recycleDir
|
||||
if null contents
|
||||
then pure ()
|
||||
else do
|
||||
logWarn ("Removing leftover files in " <> T.pack recycleDir)
|
||||
forM_ contents (\fp -> handleIO (\e ->
|
||||
logDebug ("Resource cleanup failed for " <> T.pack fp <> ", error was: " <> T.pack (displayException e))
|
||||
) $ liftIO $ removePathForcibly (recycleDir </> fp))
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
{-# LANGUAGE QuasiQuotes #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE TemplateHaskell #-}
|
||||
@@ -8,10 +7,10 @@ module GHCup.Utils.File.Common where
|
||||
|
||||
import GHCup.Utils.Prelude
|
||||
|
||||
import Control.Monad.Extra
|
||||
import Control.Monad.Reader
|
||||
import Data.Maybe
|
||||
import Data.String.Interpolate
|
||||
import Data.Text ( Text )
|
||||
import Data.Void
|
||||
import GHC.IO.Exception
|
||||
import Optics hiding ((<|), (|>))
|
||||
import System.Directory
|
||||
@@ -19,7 +18,9 @@ import System.FilePath
|
||||
import Text.PrettyPrint.HughesPJClass hiding ( (<>) )
|
||||
import Text.Regex.Posix
|
||||
|
||||
import qualified Data.Text as T
|
||||
import qualified Data.ByteString.Lazy as BL
|
||||
import qualified Text.Megaparsec as MP
|
||||
|
||||
|
||||
|
||||
@@ -31,13 +32,13 @@ data ProcessError = NonZeroExit Int FilePath [String]
|
||||
|
||||
instance Pretty ProcessError where
|
||||
pPrint (NonZeroExit e exe args) =
|
||||
text [i|Process "#{exe}" with arguments #{args} failed with exit code #{e}.|]
|
||||
text "Process" <+> pPrint exe <+> text "with arguments" <+> pPrint args <+> text "failed with exit code" <+> text (show e <> ".")
|
||||
pPrint (PTerminated exe args) =
|
||||
text [i|Process "#{exe}" with arguments #{args} terminated.|]
|
||||
text "Process" <+> pPrint exe <+> text "with arguments" <+> pPrint args <+> text "terminated."
|
||||
pPrint (PStopped exe args) =
|
||||
text [i|Process "#{exe}" with arguments #{args} stopped.|]
|
||||
text "Process" <+> pPrint exe <+> text "with arguments" <+> pPrint args <+> text "stopped."
|
||||
pPrint (NoSuchPid exe args) =
|
||||
text [i|Could not find PID for process running "#{exe}" with arguments #{args}.|]
|
||||
text "Could not find PID for process running " <+> pPrint exe <+> text " with arguments " <+> text (show args) <+> text "."
|
||||
|
||||
data CapturedProcess = CapturedProcess
|
||||
{ _exitCode :: ExitCode
|
||||
@@ -104,3 +105,16 @@ findFiles path regex = do
|
||||
contents <- listDirectory path
|
||||
pure $ filter (match regex) contents
|
||||
|
||||
findFilesDeep :: FilePath -> Regex -> IO [FilePath]
|
||||
findFilesDeep path regex = do
|
||||
contents <- getDirectoryContentsRecursive path
|
||||
pure $ filter (match regex) contents
|
||||
|
||||
findFiles' :: FilePath -> MP.Parsec Void Text a -> IO [FilePath]
|
||||
findFiles' path parser = do
|
||||
contents <- listDirectory path
|
||||
pure $ filter (\fp -> either (const False) (const True) $ MP.parse parser "" (T.pack fp)) contents
|
||||
|
||||
|
||||
checkFileAlreadyExists :: (MonadIO m) => FilePath -> m Bool
|
||||
checkFileAlreadyExists fp = liftIO $ doesFileExist fp
|
||||
|
||||
5
lib/GHCup/Utils/File/Common.hs-boot
Normal file
@@ -0,0 +1,5 @@
|
||||
module GHCup.Utils.File.Common where
|
||||
|
||||
import Text.Regex.Posix
|
||||
|
||||
findFiles :: FilePath -> Regex -> IO [FilePath]
|
||||
@@ -1,8 +1,5 @@
|
||||
{-# LANGUAGE QuasiQuotes #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE TemplateHaskell #-}
|
||||
{-# LANGUAGE ViewPatterns #-}
|
||||
|
||||
{-|
|
||||
Module : GHCup.Utils.File.Posix
|
||||
@@ -20,26 +17,25 @@ module GHCup.Utils.File.Posix where
|
||||
|
||||
import GHCup.Utils.File.Common
|
||||
import GHCup.Utils.Prelude
|
||||
import GHCup.Utils.Logger
|
||||
import GHCup.Types
|
||||
import GHCup.Types.Optics
|
||||
|
||||
import Control.Concurrent
|
||||
import Control.Concurrent.Async
|
||||
import Control.Exception ( evaluate )
|
||||
import Control.Exception.Safe
|
||||
import Control.Monad
|
||||
import Control.Monad.Logger
|
||||
import Control.Monad.Reader
|
||||
import Control.Monad.Trans.State.Strict
|
||||
import Data.ByteString ( ByteString )
|
||||
import Data.Foldable
|
||||
import Data.IORef
|
||||
import Data.Sequence ( Seq, (|>) )
|
||||
import Data.String.Interpolate
|
||||
import Data.List
|
||||
import Data.Word8
|
||||
import GHC.IO.Exception
|
||||
import System.Console.Pretty hiding ( Pretty )
|
||||
import System.Console.Regions
|
||||
import System.Console.Terminal.Common
|
||||
import System.IO.Error
|
||||
import System.FilePath
|
||||
import System.Directory
|
||||
@@ -55,6 +51,7 @@ import qualified Data.Sequence as Sq
|
||||
import qualified Data.Text as T
|
||||
import qualified Data.Text.Encoding as E
|
||||
import qualified System.Posix.Process as SPP
|
||||
import qualified System.Console.Terminal.Posix as TP
|
||||
import qualified Data.ByteString as BS
|
||||
import qualified Data.ByteString.Lazy as BL
|
||||
import qualified "unix-bytestring" System.Posix.IO.ByteString
|
||||
@@ -74,7 +71,11 @@ executeOut path args chdir = liftIO $ captureOutStreams $ do
|
||||
SPP.executeFile path True args Nothing
|
||||
|
||||
|
||||
execLogged :: (MonadReader AppState m, MonadIO m, MonadThrow m)
|
||||
execLogged :: ( MonadReader env m
|
||||
, HasSettings env
|
||||
, HasDirs env
|
||||
, MonadIO m
|
||||
, MonadThrow m)
|
||||
=> FilePath -- ^ thing to execute
|
||||
-> [String] -- ^ args for the thing
|
||||
-> Maybe FilePath -- ^ optionally chdir into this
|
||||
@@ -82,13 +83,14 @@ execLogged :: (MonadReader AppState m, MonadIO m, MonadThrow m)
|
||||
-> Maybe [(String, String)] -- ^ optional environment
|
||||
-> m (Either ProcessError ())
|
||||
execLogged exe args chdir lfile env = do
|
||||
AppState { settings = Settings {..}, dirs = Dirs {..} } <- ask
|
||||
Settings {..} <- getSettings
|
||||
Dirs {..} <- getDirs
|
||||
let logfile = logsDir </> lfile <> ".log"
|
||||
liftIO $ bracket (openFd logfile WriteOnly (Just newFilePerms) defaultFileFlags{ append = True })
|
||||
closeFd
|
||||
(action verbose)
|
||||
(action verbose noColor)
|
||||
where
|
||||
action verbose fd = do
|
||||
action verbose no_color fd = do
|
||||
actionWithPipes $ \(stdoutRead, stdoutWrite) -> do
|
||||
-- start the thread that logs to stdout
|
||||
pState <- newEmptyMVar
|
||||
@@ -99,7 +101,7 @@ execLogged exe args chdir lfile env = do
|
||||
$ EX.finally
|
||||
(if verbose
|
||||
then tee fd stdoutRead
|
||||
else printToRegion fd stdoutRead 6 pState
|
||||
else printToRegion fd stdoutRead 6 pState no_color
|
||||
)
|
||||
(putMVar done ())
|
||||
|
||||
@@ -126,7 +128,7 @@ execLogged exe args chdir lfile env = do
|
||||
pure e
|
||||
|
||||
tee :: Fd -> Fd -> IO ()
|
||||
tee fileFd fdIn = readTilEOF lineAction fdIn
|
||||
tee fileFd = readTilEOF lineAction
|
||||
|
||||
where
|
||||
lineAction :: ByteString -> IO ()
|
||||
@@ -136,46 +138,57 @@ execLogged exe args chdir lfile env = do
|
||||
|
||||
-- Reads fdIn and logs the output in a continous scrolling area
|
||||
-- of 'size' terminal lines. Also writes to a log file.
|
||||
printToRegion :: Fd -> Fd -> Int -> MVar Bool -> IO ()
|
||||
printToRegion fileFd fdIn size pState = do
|
||||
void $ displayConsoleRegions $ do
|
||||
rs <-
|
||||
liftIO
|
||||
. fmap Sq.fromList
|
||||
. sequence
|
||||
. replicate size
|
||||
. openConsoleRegion
|
||||
$ Linear
|
||||
flip runStateT mempty
|
||||
$ handle
|
||||
(\(ex :: SomeException) -> do
|
||||
ps <- liftIO $ takeMVar pState
|
||||
when ps (forM_ rs (liftIO . closeConsoleRegion))
|
||||
throw ex
|
||||
)
|
||||
$ readTilEOF (lineAction rs) fdIn
|
||||
printToRegion :: Fd -> Fd -> Int -> MVar Bool -> Bool -> IO ()
|
||||
printToRegion fileFd fdIn size pState no_color = do
|
||||
-- init region
|
||||
forM_ [1..size] $ \_ -> BS.putStr "\n"
|
||||
|
||||
void $ flip runStateT mempty
|
||||
$ do
|
||||
handle
|
||||
(\(ex :: SomeException) -> do
|
||||
ps <- liftIO $ takeMVar pState
|
||||
when ps (liftIO $ BS.putStr (pos1 <> moveLineUp size <> clearScreen))
|
||||
throw ex
|
||||
) $ readTilEOF lineAction fdIn
|
||||
|
||||
where
|
||||
clearScreen :: ByteString
|
||||
clearScreen = "\x1b[0J"
|
||||
clearLine :: ByteString
|
||||
clearLine = "\x1b[2K"
|
||||
moveLineUp :: Int -> ByteString
|
||||
moveLineUp n = "\x1b[" <> E.encodeUtf8 (T.pack (show n)) <> "A"
|
||||
moveLineDown :: Int -> ByteString
|
||||
moveLineDown n = "\x1b[" <> E.encodeUtf8 (T.pack (show n)) <> "B"
|
||||
pos1 :: ByteString
|
||||
pos1 = "\r"
|
||||
overwriteNthLine :: Int -> ByteString -> ByteString
|
||||
overwriteNthLine n str = pos1 <> moveLineUp n <> clearLine <> str <> moveLineDown n <> pos1
|
||||
|
||||
blue :: ByteString -> ByteString
|
||||
blue bs
|
||||
| no_color = bs
|
||||
| otherwise = "\x1b[0;34m" <> bs <> "\x1b[0m"
|
||||
|
||||
-- action to perform line by line
|
||||
-- TODO: do this with vty for efficiency
|
||||
lineAction :: (MonadMask m, MonadIO m)
|
||||
=> Seq ConsoleRegion
|
||||
-> ByteString
|
||||
=> ByteString
|
||||
-> StateT (Seq ByteString) m ()
|
||||
lineAction rs = \bs' -> do
|
||||
lineAction = \bs' -> do
|
||||
void $ liftIO $ SPIB.fdWrite fileFd (bs' <> "\n")
|
||||
modify (swapRegs bs')
|
||||
regs <- get
|
||||
liftIO $ forM_ (Sq.zip regs rs) $ \(bs, r) -> setConsoleRegion r $ do
|
||||
w <- consoleWidth
|
||||
return
|
||||
. T.pack
|
||||
. color Blue
|
||||
. T.unpack
|
||||
. decUTF8Safe
|
||||
. trim w
|
||||
. (\b -> "[ " <> E.encodeUtf8 (T.pack lfile) <> " ] " <> b)
|
||||
$ bs
|
||||
liftIO TP.size >>= \case
|
||||
Nothing -> pure ()
|
||||
Just (Window _ w) -> do
|
||||
regs <- get
|
||||
liftIO $ forM_ (Sq.zip regs (Sq.fromList [0..(Sq.length regs - 1)])) $ \(bs, i) -> do
|
||||
BS.putStr
|
||||
. overwriteNthLine (size - i)
|
||||
. trim w
|
||||
. blue
|
||||
. (\b -> "[ " <> E.encodeUtf8 (T.pack lfile) <> " ] " <> b)
|
||||
$ bs
|
||||
|
||||
swapRegs :: a -> Seq a -> Seq a
|
||||
swapRegs bs = \regs -> if
|
||||
@@ -345,7 +358,7 @@ toProcessError exe args mps = case mps of
|
||||
|
||||
|
||||
|
||||
chmod_755 :: (MonadLogger m, MonadIO m) => FilePath -> m ()
|
||||
chmod_755 :: (MonadReader env m, HasLog env, MonadIO m) => FilePath -> m ()
|
||||
chmod_755 fp = do
|
||||
let exe_mode =
|
||||
nullFileMode
|
||||
@@ -356,7 +369,7 @@ chmod_755 fp = do
|
||||
`unionFileModes` groupReadMode
|
||||
`unionFileModes` otherExecuteMode
|
||||
`unionFileModes` otherReadMode
|
||||
$(logDebug) [i|chmod 755 #{fp}|]
|
||||
logDebug ("chmod 755 " <> T.pack fp)
|
||||
liftIO $ setFileMode fp exe_mode
|
||||
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ import {-# SOURCE #-} GHCup.Utils ( getLinkTarget, pathIsLink )
|
||||
import GHCup.Utils.Dirs
|
||||
import GHCup.Utils.File.Common
|
||||
import GHCup.Types
|
||||
import GHCup.Types.Optics
|
||||
|
||||
import Control.Concurrent
|
||||
import Control.DeepSeq
|
||||
@@ -146,7 +147,11 @@ executeOut path args chdir = do
|
||||
pure $ CapturedProcess exit out err
|
||||
|
||||
|
||||
execLogged :: (MonadReader AppState m, MonadIO m, MonadThrow m)
|
||||
execLogged :: ( MonadReader env m
|
||||
, HasDirs env
|
||||
, HasSettings env
|
||||
, MonadIO m
|
||||
, MonadThrow m)
|
||||
=> FilePath -- ^ thing to execute
|
||||
-> [String] -- ^ args for the thing
|
||||
-> Maybe FilePath -- ^ optionally chdir into this
|
||||
@@ -154,7 +159,7 @@ execLogged :: (MonadReader AppState m, MonadIO m, MonadThrow m)
|
||||
-> Maybe [(String, String)] -- ^ optional environment
|
||||
-> m (Either ProcessError ())
|
||||
execLogged exe args chdir lfile env = do
|
||||
AppState { dirs = Dirs {..} } <- ask
|
||||
Dirs {..} <- getDirs
|
||||
let stdoutLogfile = logsDir </> lfile <> ".stdout.log"
|
||||
stderrLogfile = logsDir </> lfile <> ".stderr.log"
|
||||
cp <- createProcessWithMingwPath ((proc exe args)
|
||||
@@ -204,6 +209,20 @@ exec exe args chdir env = do
|
||||
pure $ toProcessError exe args exit_code
|
||||
|
||||
|
||||
-- | Thin wrapper around `executeFile`.
|
||||
execShell :: MonadIO m
|
||||
=> FilePath -- ^ thing to execute
|
||||
-> [FilePath] -- ^ args for the thing
|
||||
-> Maybe FilePath -- ^ optionally chdir into this
|
||||
-> Maybe [(String, String)] -- ^ optional environment
|
||||
-> m (Either ProcessError ())
|
||||
execShell exe args chdir env = do
|
||||
let cmd = exe <> " " <> concatMap (' ':) args
|
||||
cp <- createProcessWithMingwPath ((shell cmd) { cwd = chdir, env = env })
|
||||
exit_code <- liftIO $ withCreateProcess cp $ \_ _ _ p -> waitForProcess p
|
||||
pure $ toProcessError cmd [] exit_code
|
||||
|
||||
|
||||
chmod_755 :: MonadIO m => FilePath -> m ()
|
||||
chmod_755 fp =
|
||||
let perm = setOwnerWritable True emptyPermissions
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE QuasiQuotes #-}
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
|
||||
{-|
|
||||
Module : GHCup.Utils.Logger
|
||||
@@ -14,12 +16,17 @@ Here we define our main logger.
|
||||
-}
|
||||
module GHCup.Utils.Logger where
|
||||
|
||||
import GHCup.Utils.File
|
||||
import GHCup.Types
|
||||
import GHCup.Types.Optics
|
||||
import {-# SOURCE #-} GHCup.Utils.File.Common
|
||||
import GHCup.Utils.String.QQ
|
||||
|
||||
import Control.Exception.Safe
|
||||
import Control.Monad
|
||||
import Control.Monad.IO.Class
|
||||
import Control.Monad.Logger
|
||||
import Control.Monad.Reader
|
||||
import Data.Text ( Text )
|
||||
import Optics
|
||||
import Prelude hiding ( appendFile )
|
||||
import System.Console.Pretty
|
||||
import System.FilePath
|
||||
@@ -28,54 +35,97 @@ import Text.Regex.Posix
|
||||
|
||||
import qualified Data.ByteString as B
|
||||
import GHCup.Utils.Prelude
|
||||
import qualified Data.Text as T
|
||||
|
||||
logInfo :: ( MonadReader env m
|
||||
, LabelOptic' "loggerConfig" A_Lens env LoggerConfig
|
||||
, MonadIO m
|
||||
)
|
||||
=> Text
|
||||
-> m ()
|
||||
logInfo = logInternal Info
|
||||
|
||||
logWarn :: ( MonadReader env m
|
||||
, LabelOptic' "loggerConfig" A_Lens env LoggerConfig
|
||||
, MonadIO m
|
||||
)
|
||||
=> Text
|
||||
-> m ()
|
||||
logWarn = logInternal Warn
|
||||
|
||||
logDebug :: ( MonadReader env m
|
||||
, LabelOptic' "loggerConfig" A_Lens env LoggerConfig
|
||||
, MonadIO m
|
||||
)
|
||||
=> Text
|
||||
-> m ()
|
||||
logDebug = logInternal Debug
|
||||
|
||||
logError :: ( MonadReader env m
|
||||
, LabelOptic' "loggerConfig" A_Lens env LoggerConfig
|
||||
, MonadIO m
|
||||
)
|
||||
=> Text
|
||||
-> m ()
|
||||
logError = logInternal Error
|
||||
|
||||
|
||||
data LoggerConfig = LoggerConfig
|
||||
{ lcPrintDebug :: Bool -- ^ whether to print debug in colorOutter
|
||||
, colorOutter :: B.ByteString -> IO () -- ^ how to write the color output
|
||||
, rawOutter :: B.ByteString -> IO () -- ^ how to write the full raw output
|
||||
}
|
||||
logInternal :: ( MonadReader env m
|
||||
, LabelOptic' "loggerConfig" A_Lens env LoggerConfig
|
||||
, MonadIO m
|
||||
) => LogLevel
|
||||
-> Text
|
||||
-> m ()
|
||||
logInternal logLevel msg = do
|
||||
LoggerConfig {..} <- gets @"loggerConfig"
|
||||
let color' c = if fancyColors then color c else id
|
||||
let style' = case logLevel of
|
||||
Debug -> style Bold . color' Blue
|
||||
Info -> style Bold . color' Green
|
||||
Warn -> style Bold . color' Yellow
|
||||
Error -> style Bold . color' Red
|
||||
let l = case logLevel of
|
||||
Debug -> style' "[ Debug ]"
|
||||
Info -> style' "[ Info ]"
|
||||
Warn -> style' "[ Warn ]"
|
||||
Error -> style' "[ Error ]"
|
||||
let strs = T.split (== '\n') msg
|
||||
let out = case strs of
|
||||
[] -> T.empty
|
||||
(x:xs) ->
|
||||
foldr (\a b -> a <> "\n" <> b) mempty
|
||||
. ((l <> " " <> x) :)
|
||||
. fmap (\line' -> style' "[ ... ] " <> line' )
|
||||
$ xs
|
||||
|
||||
when (lcPrintDebug || (not lcPrintDebug && (logLevel /= Debug)))
|
||||
$ liftIO $ consoleOutter out
|
||||
|
||||
-- raw output
|
||||
let lr = case logLevel of
|
||||
Debug -> "Debug:"
|
||||
Info -> "Info:"
|
||||
Warn -> "Warn:"
|
||||
Error -> "Error:"
|
||||
let outr = lr <> " " <> msg <> "\n"
|
||||
liftIO $ fileOutter outr
|
||||
|
||||
|
||||
myLoggerT :: LoggerConfig -> LoggingT m a -> m a
|
||||
myLoggerT LoggerConfig {..} loggingt = runLoggingT loggingt mylogger
|
||||
where
|
||||
mylogger :: Loc -> LogSource -> LogLevel -> LogStr -> IO ()
|
||||
mylogger _ _ level str' = do
|
||||
-- color output
|
||||
let l = case level of
|
||||
LevelDebug -> toLogStr (style Bold $ color Blue "[ Debug ]")
|
||||
LevelInfo -> toLogStr (style Bold $ color Green "[ Info ]")
|
||||
LevelWarn -> toLogStr (style Bold $ color Yellow "[ Warn ]")
|
||||
LevelError -> toLogStr (style Bold $ color Red "[ Error ]")
|
||||
LevelOther t -> toLogStr "[ " <> toLogStr t <> toLogStr " ]"
|
||||
let out = fromLogStr (l <> toLogStr " " <> str' <> toLogStr "\n")
|
||||
|
||||
when (lcPrintDebug || (not lcPrintDebug && (level /= LevelDebug)))
|
||||
$ colorOutter out
|
||||
|
||||
-- raw output
|
||||
let lr = case level of
|
||||
LevelDebug -> toLogStr "Debug: "
|
||||
LevelInfo -> toLogStr "Info:"
|
||||
LevelWarn -> toLogStr "Warn:"
|
||||
LevelError -> toLogStr "Error:"
|
||||
LevelOther t -> toLogStr t <> toLogStr ":"
|
||||
let outr = fromLogStr (lr <> toLogStr " " <> str' <> toLogStr "\n")
|
||||
rawOutter outr
|
||||
|
||||
|
||||
initGHCupFileLogging :: (MonadIO m) => FilePath -> m FilePath
|
||||
initGHCupFileLogging logsDir = do
|
||||
initGHCupFileLogging :: ( MonadReader env m
|
||||
, HasDirs env
|
||||
, MonadIO m
|
||||
, MonadMask m
|
||||
) => m FilePath
|
||||
initGHCupFileLogging = do
|
||||
Dirs { logsDir } <- getDirs
|
||||
let logfile = logsDir </> "ghcup.log"
|
||||
liftIO $ do
|
||||
logFiles <- findFiles
|
||||
logsDir
|
||||
(makeRegexOpts compExtended
|
||||
execBlank
|
||||
([s|^.*\.log$|] :: B.ByteString)
|
||||
)
|
||||
forM_ logFiles $ hideError doesNotExistErrorType . rmFile . (logsDir </>)
|
||||
logFiles <- liftIO $ findFiles
|
||||
logsDir
|
||||
(makeRegexOpts compExtended
|
||||
execBlank
|
||||
([s|^.*\.log$|] :: B.ByteString)
|
||||
)
|
||||
forM_ logFiles $ hideError doesNotExistErrorType . recycleFile . (logsDir </>)
|
||||
|
||||
writeFile logfile ""
|
||||
pure logfile
|
||||
liftIO $ writeFile logfile ""
|
||||
pure logfile
|
||||
|
||||
21
lib/GHCup/Utils/Logger.hs-boot
Normal file
@@ -0,0 +1,21 @@
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE QuasiQuotes #-}
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
|
||||
module GHCup.Utils.Logger where
|
||||
|
||||
import GHCup.Types
|
||||
|
||||
import Control.Monad.IO.Class
|
||||
import Control.Monad.Reader
|
||||
import Data.Text ( Text )
|
||||
import Optics
|
||||
|
||||
logWarn :: ( MonadReader env m
|
||||
, LabelOptic' "loggerConfig" A_Lens env LoggerConfig
|
||||
, MonadIO m
|
||||
)
|
||||
=> Text
|
||||
-> m ()
|
||||
|
||||
@@ -19,22 +19,35 @@ GHCup specific prelude. Lots of Excepts functionality.
|
||||
-}
|
||||
module GHCup.Utils.Prelude where
|
||||
|
||||
#if defined(IS_WINDOWS)
|
||||
import GHCup.Types
|
||||
#endif
|
||||
import GHCup.Errors
|
||||
import GHCup.Types.Optics
|
||||
import {-# SOURCE #-} GHCup.Utils.Logger
|
||||
|
||||
import Control.Applicative
|
||||
import Control.Exception.Safe
|
||||
import Control.Monad
|
||||
import Control.Monad.IO.Class
|
||||
import Control.Monad.Trans.Class ( lift )
|
||||
import Control.Monad.Reader
|
||||
import Data.Bifunctor
|
||||
import Data.ByteString ( ByteString )
|
||||
import Data.List ( nub )
|
||||
import Data.List ( nub, intercalate, stripPrefix, isPrefixOf, dropWhileEnd )
|
||||
import Data.Maybe
|
||||
import Data.Foldable
|
||||
import Data.List.NonEmpty ( NonEmpty( (:|) ))
|
||||
import Data.String
|
||||
import Data.Text ( Text )
|
||||
import Data.Versions
|
||||
import Data.Word8
|
||||
import Data.Word8 hiding ( isDigit )
|
||||
import Haskus.Utils.Types.List
|
||||
import Haskus.Utils.Variant.Excepts
|
||||
import Text.PrettyPrint.HughesPJClass ( prettyShow, Pretty )
|
||||
import System.IO.Error
|
||||
#if defined(IS_WINDOWS)
|
||||
import System.IO.Temp
|
||||
#endif
|
||||
import System.IO.Unsafe
|
||||
import System.Directory
|
||||
import System.FilePath
|
||||
@@ -47,6 +60,8 @@ import GHC.IO.Exception
|
||||
import qualified Data.ByteString as B
|
||||
import qualified Data.ByteString.Lazy as L
|
||||
import qualified Data.Strict.Maybe as S
|
||||
import qualified Data.List.Split as Split
|
||||
import qualified Data.List.NonEmpty as NE
|
||||
import qualified Data.Text as T
|
||||
import qualified Data.Text.Encoding as E
|
||||
import qualified Data.Text.Encoding.Error as E
|
||||
@@ -54,8 +69,20 @@ import qualified Data.Text.Lazy as TL
|
||||
import qualified Data.Text.Lazy.Builder as B
|
||||
import qualified Data.Text.Lazy.Builder.Int as B
|
||||
import qualified Data.Text.Lazy.Encoding as TLE
|
||||
#if defined(IS_WINDOWS)
|
||||
import qualified System.Win32.File as Win32
|
||||
#endif
|
||||
|
||||
|
||||
-- $setup
|
||||
-- >>> import Data.ByteString.Internal (c2w, w2c)
|
||||
-- >>> import Test.QuickCheck
|
||||
-- >>> import Data.Word8
|
||||
-- >>> import qualified Data.Text as T
|
||||
-- >>> import qualified Data.Char as C
|
||||
-- >>> import Data.List
|
||||
-- >>> instance Arbitrary T.Text where arbitrary = T.pack <$> arbitrary
|
||||
|
||||
|
||||
fS :: IsString a => String -> a
|
||||
fS = fromString
|
||||
@@ -150,6 +177,14 @@ lEM' :: forall e' e es a m
|
||||
-> Excepts es m a
|
||||
lEM' f em = lift em >>= lE . first f
|
||||
|
||||
-- for some obscure reason... this won't type-check if we move it to a different module
|
||||
catchWarn :: forall es m env . ( Pretty (V es)
|
||||
, MonadReader env m
|
||||
, HasLog env
|
||||
, MonadIO m
|
||||
, Monad m) => Excepts es m () -> Excepts '[] m ()
|
||||
catchWarn = catchAllE @_ @es (\v -> lift $ logWarn (T.pack . prettyShow $ v))
|
||||
|
||||
fromEither :: Either a b -> VEither '[a] b
|
||||
fromEither = either (VLeft . V) VRight
|
||||
|
||||
@@ -190,14 +225,14 @@ hideError :: (MonadIO m, MonadCatch m) => IOErrorType -> m () -> m ()
|
||||
hideError err = handleIO (\e -> if err == ioeGetErrorType e then pure () else liftIO . ioError $ e)
|
||||
|
||||
|
||||
hideErrorDef :: [IOErrorType] -> a -> IO a -> IO a
|
||||
hideErrorDef :: (MonadIO m, MonadCatch m) => [IOErrorType] -> a -> m a -> m a
|
||||
hideErrorDef errs def =
|
||||
handleIO (\e -> if ioeGetErrorType e `elem` errs then pure def else ioError e)
|
||||
handleIO (\e -> if ioeGetErrorType e `elem` errs then pure def else liftIO $ ioError e)
|
||||
|
||||
|
||||
hideErrorDefM :: [IOErrorType] -> IO a -> IO a -> IO a
|
||||
hideErrorDefM :: (MonadIO m, MonadCatch m) => [IOErrorType] -> m a -> m a -> m a
|
||||
hideErrorDefM errs def =
|
||||
handleIO (\e -> if ioeGetErrorType e `elem` errs then def else ioError e)
|
||||
handleIO (\e -> if ioeGetErrorType e `elem` errs then def else liftIO $ ioError e)
|
||||
|
||||
|
||||
-- TODO: does this work?
|
||||
@@ -248,6 +283,16 @@ throwEither' e eth = case eth of
|
||||
Left _ -> throwM e
|
||||
Right r -> pure r
|
||||
|
||||
throwMaybe :: (Exception a, MonadThrow m) => a -> Maybe b -> m b
|
||||
throwMaybe a m = case m of
|
||||
Nothing -> throwM a
|
||||
Just r -> pure r
|
||||
|
||||
throwMaybeM :: (Exception a, MonadThrow m) => a -> m (Maybe b) -> m b
|
||||
throwMaybeM a am = do
|
||||
m <- am
|
||||
throwMaybe a m
|
||||
|
||||
|
||||
verToBS :: Version -> ByteString
|
||||
verToBS = E.encodeUtf8 . prettyVer
|
||||
@@ -264,12 +309,28 @@ removeLensFieldLabel str' =
|
||||
maybe str' T.unpack . T.stripPrefix (T.pack "_") . T.pack $ str'
|
||||
|
||||
|
||||
pvpToVersion :: PVP -> Version
|
||||
pvpToVersion :: MonadThrow m => PVP -> m Version
|
||||
pvpToVersion =
|
||||
either (\_ -> error "Couldn't convert PVP to Version") id
|
||||
. version
|
||||
. prettyPVP
|
||||
either (\_ -> throwM $ ParseError "Couldn't convert PVP to Version") pure . version . prettyPVP
|
||||
|
||||
versionToPVP :: MonadThrow m => Version -> m PVP
|
||||
versionToPVP v = either (\_ -> alternative v) pure . pvp . prettyVer $ v
|
||||
where
|
||||
alternative :: MonadThrow m => Version -> m PVP
|
||||
alternative v' = case NE.takeWhile isDigit (_vChunks v') of
|
||||
[] -> throwM $ ParseError "Couldn't convert Version to PVP"
|
||||
xs -> pure $ pvpFromList (unsafeDigit <$> xs)
|
||||
|
||||
isDigit :: VChunk -> Bool
|
||||
isDigit (Digits _ :| []) = True
|
||||
isDigit _ = False
|
||||
|
||||
unsafeDigit :: VChunk -> Int
|
||||
unsafeDigit (Digits x :| []) = fromIntegral x
|
||||
unsafeDigit _ = error "unsafeDigit: wrong input"
|
||||
|
||||
pvpFromList :: [Int] -> PVP
|
||||
pvpFromList = PVP . NE.fromList . fmap fromIntegral
|
||||
|
||||
-- | Safe 'decodeUtf8With'. Replaces an invalid input byte with
|
||||
-- the Unicode replacement character U+FFFD.
|
||||
@@ -312,17 +373,16 @@ createDirRecursive' p =
|
||||
-- | Recursively copy the contents of one directory to another path.
|
||||
--
|
||||
-- This is a rip-off of Cabal library.
|
||||
copyDirectoryRecursive :: FilePath -> FilePath -> IO ()
|
||||
copyDirectoryRecursive srcDir destDir = do
|
||||
copyDirectoryRecursive :: FilePath -> FilePath -> (FilePath -> FilePath -> IO ()) -> IO ()
|
||||
copyDirectoryRecursive srcDir destDir doCopy = do
|
||||
srcFiles <- getDirectoryContentsRecursive srcDir
|
||||
copyFilesWith copyFile destDir [ (srcDir, f)
|
||||
| f <- srcFiles ]
|
||||
copyFilesWith destDir [ (srcDir, f)
|
||||
| f <- srcFiles ]
|
||||
where
|
||||
-- | Common implementation of 'copyFiles', 'installOrdinaryFiles',
|
||||
-- 'installExecutableFiles' and 'installMaybeExecutableFiles'.
|
||||
copyFilesWith :: (FilePath -> FilePath -> IO ())
|
||||
-> FilePath -> [(FilePath, FilePath)] -> IO ()
|
||||
copyFilesWith doCopy targetDir srcFiles = do
|
||||
copyFilesWith :: FilePath -> [(FilePath, FilePath)] -> IO ()
|
||||
copyFilesWith targetDir srcFiles = do
|
||||
|
||||
-- Create parent directories for everything
|
||||
let dirs = map (targetDir </>) . nub . map (takeDirectory . snd) $ srcFiles
|
||||
@@ -334,75 +394,162 @@ copyDirectoryRecursive srcDir destDir = do
|
||||
in doCopy src dest
|
||||
| (srcBase, srcFile) <- srcFiles ]
|
||||
|
||||
-- | List all the files in a directory and all subdirectories.
|
||||
--
|
||||
-- The order places files in sub-directories after all the files in their
|
||||
-- parent directories. The list is generated lazily so is not well defined if
|
||||
-- the source directory structure changes before the list is used.
|
||||
--
|
||||
getDirectoryContentsRecursive :: FilePath -> IO [FilePath]
|
||||
getDirectoryContentsRecursive topdir = recurseDirectories [""]
|
||||
|
||||
-- | List all the files in a directory and all subdirectories.
|
||||
--
|
||||
-- The order places files in sub-directories after all the files in their
|
||||
-- parent directories. The list is generated lazily so is not well defined if
|
||||
-- the source directory structure changes before the list is used.
|
||||
--
|
||||
getDirectoryContentsRecursive :: FilePath -> IO [FilePath]
|
||||
getDirectoryContentsRecursive topdir = recurseDirectories [""]
|
||||
where
|
||||
recurseDirectories :: [FilePath] -> IO [FilePath]
|
||||
recurseDirectories [] = return []
|
||||
recurseDirectories (dir:dirs) = unsafeInterleaveIO $ do
|
||||
(files, dirs') <- collect [] [] =<< getDirectoryContents (topdir </> dir)
|
||||
files' <- recurseDirectories (dirs' ++ dirs)
|
||||
return (files ++ files')
|
||||
|
||||
where
|
||||
recurseDirectories :: [FilePath] -> IO [FilePath]
|
||||
recurseDirectories [] = return []
|
||||
recurseDirectories (dir:dirs) = unsafeInterleaveIO $ do
|
||||
(files, dirs') <- collect [] [] =<< getDirectoryContents (topdir </> dir)
|
||||
files' <- recurseDirectories (dirs' ++ dirs)
|
||||
return (files ++ files')
|
||||
collect files dirs' [] = return (reverse files
|
||||
,reverse dirs')
|
||||
collect files dirs' (entry:entries) | ignore entry
|
||||
= collect files dirs' entries
|
||||
collect files dirs' (entry:entries) = do
|
||||
let dirEntry = dir </> entry
|
||||
isDirectory <- doesDirectoryExist (topdir </> dirEntry)
|
||||
if isDirectory
|
||||
then collect files (dirEntry:dirs') entries
|
||||
else collect (dirEntry:files) dirs' entries
|
||||
|
||||
where
|
||||
collect files dirs' [] = return (reverse files
|
||||
,reverse dirs')
|
||||
collect files dirs' (entry:entries) | ignore entry
|
||||
= collect files dirs' entries
|
||||
collect files dirs' (entry:entries) = do
|
||||
let dirEntry = dir </> entry
|
||||
isDirectory <- doesDirectoryExist (topdir </> dirEntry)
|
||||
if isDirectory
|
||||
then collect files (dirEntry:dirs') entries
|
||||
else collect (dirEntry:files) dirs' entries
|
||||
ignore ['.'] = True
|
||||
ignore ['.', '.'] = True
|
||||
ignore _ = False
|
||||
|
||||
ignore ['.'] = True
|
||||
ignore ['.', '.'] = True
|
||||
ignore _ = False
|
||||
|
||||
-- https://github.com/haskell/directory/issues/110
|
||||
-- https://github.com/haskell/directory/issues/96
|
||||
-- https://www.sqlite.org/src/info/89f1848d7f
|
||||
rmPath :: (MonadIO m, MonadMask m)
|
||||
=> FilePath
|
||||
-> m ()
|
||||
rmPath fp =
|
||||
recyclePathForcibly :: ( MonadIO m
|
||||
, MonadReader env m
|
||||
, HasDirs env
|
||||
, MonadMask m
|
||||
)
|
||||
=> FilePath
|
||||
-> m ()
|
||||
recyclePathForcibly fp = do
|
||||
#if defined(IS_WINDOWS)
|
||||
recovering (fullJitterBackoff 25000 <> limitRetries 10)
|
||||
[\_ -> Handler (\e -> pure $ isPermissionError e)
|
||||
,\_ -> Handler (\e -> pure (ioeGetErrorType e == UnsatisfiedConstraints))
|
||||
,\_ -> Handler (\e -> pure (ioeGetErrorType e == InappropriateType))
|
||||
]
|
||||
(\_ -> liftIO $ removePathForcibly fp)
|
||||
Dirs { recycleDir } <- getDirs
|
||||
tmp <- liftIO $ createTempDirectory recycleDir "recyclePathForcibly"
|
||||
let dest = tmp </> takeFileName fp
|
||||
liftIO (Win32.moveFileEx fp (Just dest) 0)
|
||||
`catch`
|
||||
(\e -> if isPermissionError e {- EXDEV on windows -} then recover (liftIO $ removePathForcibly fp) else throwIO e)
|
||||
`finally`
|
||||
(liftIO $ handleIO (\_ -> pure ()) $ removePathForcibly tmp)
|
||||
#else
|
||||
liftIO $ removeDirectoryRecursive fp
|
||||
liftIO $ removePathForcibly fp
|
||||
#endif
|
||||
|
||||
|
||||
rmPathForcibly :: ( MonadIO m
|
||||
, MonadMask m
|
||||
)
|
||||
=> FilePath
|
||||
-> m ()
|
||||
rmPathForcibly fp =
|
||||
#if defined(IS_WINDOWS)
|
||||
recover (liftIO $ removePathForcibly fp)
|
||||
#else
|
||||
liftIO $ removePathForcibly fp
|
||||
#endif
|
||||
|
||||
|
||||
rmDirectory :: (MonadIO m, MonadMask m)
|
||||
=> FilePath
|
||||
-> m ()
|
||||
rmDirectory fp =
|
||||
#if defined(IS_WINDOWS)
|
||||
recover (liftIO $ removeDirectory fp)
|
||||
#else
|
||||
liftIO $ removeDirectory fp
|
||||
#endif
|
||||
|
||||
|
||||
-- https://www.sqlite.org/src/info/89f1848d7f
|
||||
-- https://github.com/haskell/directory/issues/96
|
||||
rmFile :: (MonadIO m, MonadMask m)
|
||||
=> FilePath
|
||||
-> m ()
|
||||
rmFile fp =
|
||||
recycleFile :: ( MonadIO m
|
||||
, MonadMask m
|
||||
, MonadReader env m
|
||||
, HasDirs env
|
||||
)
|
||||
=> FilePath
|
||||
-> m ()
|
||||
recycleFile fp = do
|
||||
#if defined(IS_WINDOWS)
|
||||
recovering (fullJitterBackoff 25000 <> limitRetries 10)
|
||||
[\_ -> Handler (\e -> pure $ isPermissionError e)
|
||||
,\_ -> Handler (\e -> pure (ioeGetErrorType e == UnsatisfiedConstraints))
|
||||
]
|
||||
(\_ -> liftIO $ removeFile fp)
|
||||
Dirs { recycleDir } <- getDirs
|
||||
liftIO $ whenM (doesDirectoryExist fp) $ ioError (IOError Nothing InappropriateType "recycleFile" "" Nothing (Just fp))
|
||||
tmp <- liftIO $ createTempDirectory recycleDir "recycleFile"
|
||||
let dest = tmp </> takeFileName fp
|
||||
liftIO (Win32.moveFileEx fp (Just dest) 0)
|
||||
`catch`
|
||||
(\e -> if isPermissionError e {- EXDEV on windows -} then recover (liftIO $ removePathForcibly fp) else throwIO e)
|
||||
`finally`
|
||||
(liftIO $ handleIO (\_ -> pure ()) $ removePathForcibly tmp)
|
||||
#else
|
||||
liftIO $ removeFile fp
|
||||
#endif
|
||||
|
||||
|
||||
-- Gathering monoidal values
|
||||
rmFile :: ( MonadIO m
|
||||
, MonadMask m
|
||||
)
|
||||
=> FilePath
|
||||
-> m ()
|
||||
rmFile fp =
|
||||
#if defined(IS_WINDOWS)
|
||||
recover (liftIO $ removeFile fp)
|
||||
#else
|
||||
liftIO $ removeFile fp
|
||||
#endif
|
||||
|
||||
|
||||
rmDirectoryLink :: (MonadIO m, MonadMask m, MonadReader env m, HasDirs env)
|
||||
=> FilePath
|
||||
-> m ()
|
||||
rmDirectoryLink fp =
|
||||
#if defined(IS_WINDOWS)
|
||||
recover (liftIO $ removeDirectoryLink fp)
|
||||
#else
|
||||
liftIO $ removeDirectoryLink fp
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(IS_WINDOWS)
|
||||
recover :: (MonadIO m, MonadMask m) => m a -> m a
|
||||
recover action =
|
||||
recovering (fullJitterBackoff 25000 <> limitRetries 10)
|
||||
[\_ -> Handler (\e -> pure $ isPermissionError e)
|
||||
,\_ -> Handler (\e -> pure (ioeGetErrorType e == InappropriateType))
|
||||
,\_ -> Handler (\e -> pure (ioeGetErrorType e == UnsatisfiedConstraints))
|
||||
]
|
||||
(\_ -> action)
|
||||
#endif
|
||||
|
||||
|
||||
copyFileE :: (CopyError :< xs, MonadCatch m, MonadIO m) => FilePath -> FilePath -> Excepts xs m ()
|
||||
copyFileE from = handleIO (throwE . CopyError . show) . liftIO . copyFile from
|
||||
|
||||
|
||||
-- | Gathering monoidal values
|
||||
--
|
||||
-- >>> traverseFold (pure . (:["0"])) ["1","2"]
|
||||
-- ["1","0","2","0"]
|
||||
-- >>> traverseFold Just ["1","2","3","4","5"]
|
||||
-- Just "12345"
|
||||
--
|
||||
-- prop> \t -> traverseFold Just t === Just (mconcat t)
|
||||
traverseFold :: (Foldable t, Applicative m, Monoid b) => (a -> m b) -> t a -> m b
|
||||
traverseFold f = foldl (\mb a -> (<>) <$> mb <*> f a) (pure mempty)
|
||||
|
||||
@@ -411,16 +558,199 @@ forFold :: (Foldable t, Applicative m, Monoid b) => t a -> (a -> m b) -> m b
|
||||
forFold = \t -> (`traverseFold` t)
|
||||
|
||||
|
||||
-- | Strip @\\r@ and @\\n@ from 'ByteString's
|
||||
-- | Strip @\\r@ and @\\n@ from 'String's
|
||||
--
|
||||
-- >>> stripNewline "foo\n\n\n"
|
||||
-- "foo"
|
||||
-- >>> stripNewline "foo\n\n\nfoo"
|
||||
-- "foofoo"
|
||||
-- >>> stripNewline "foo\r"
|
||||
-- "foo"
|
||||
-- >>> stripNewline "foo"
|
||||
-- "foo"
|
||||
--
|
||||
-- prop> \t -> stripNewline (t <> "\n") === stripNewline t
|
||||
-- prop> \t -> not (any (isNewLine . c2w) t) ==> stripNewline t == t
|
||||
stripNewline :: String -> String
|
||||
stripNewline s
|
||||
| null s = []
|
||||
| head s `elem` "\n\r" = stripNewline (tail s)
|
||||
| otherwise = head s : stripNewline (tail s)
|
||||
stripNewline = filter (`notElem` "\n\r")
|
||||
|
||||
|
||||
-- | Strip @\\r@ and @\\n@ from end of 'String'.
|
||||
--
|
||||
-- >>> stripNewlineEnd "foo\n\n\n"
|
||||
-- "foo"
|
||||
-- >>> stripNewlineEnd "foo\n\n\nfoo"
|
||||
-- "foo\n\n\nfoo"
|
||||
-- >>> stripNewlineEnd "foo\r"
|
||||
-- "foo"
|
||||
-- >>> stripNewlineEnd "foo"
|
||||
-- "foo"
|
||||
--
|
||||
-- prop> \t -> stripNewlineEnd (t <> "\n") === stripNewlineEnd t
|
||||
-- prop> \t -> not (any (isNewLine . c2w) t) ==> stripNewlineEnd t == t
|
||||
stripNewlineEnd :: String -> String
|
||||
stripNewlineEnd = dropWhileEnd (`elem` "\n\r")
|
||||
|
||||
|
||||
-- | Strip @\\r@ and @\\n@ from 'Text's
|
||||
--
|
||||
-- >>> stripNewline' "foo\n\n\n"
|
||||
-- "foo"
|
||||
-- >>> stripNewline' "foo\n\n\nfoo"
|
||||
-- "foofoo"
|
||||
-- >>> stripNewline' "foo\r"
|
||||
-- "foo"
|
||||
-- >>> stripNewline' "foo"
|
||||
-- "foo"
|
||||
--
|
||||
-- prop> \t -> stripNewline' (t <> "\n") === stripNewline' t
|
||||
-- prop> \t -> not (T.any (isNewLine . c2w) t) ==> stripNewline' t == t
|
||||
stripNewline' :: T.Text -> T.Text
|
||||
stripNewline' = T.filter (`notElem` "\n\r")
|
||||
|
||||
|
||||
-- | Is the word8 a newline?
|
||||
--
|
||||
-- >>> isNewLine (c2w '\n')
|
||||
-- True
|
||||
-- >>> isNewLine (c2w '\r')
|
||||
-- True
|
||||
--
|
||||
-- prop> \w -> w /= _lf && w /= _cr ==> not (isNewLine w)
|
||||
isNewLine :: Word8 -> Bool
|
||||
isNewLine w
|
||||
| w == _lf = True
|
||||
| w == _cr = True
|
||||
| otherwise = False
|
||||
|
||||
|
||||
-- | Split on a PVP suffix.
|
||||
--
|
||||
-- >>> splitOnPVP "-" "ghc-iserv-dyn-9.3.20210706"
|
||||
-- ("ghc-iserv-dyn","9.3.20210706")
|
||||
-- >>> splitOnPVP "-" "ghc-iserv-dyn"
|
||||
-- ("ghc-iserv-dyn","")
|
||||
splitOnPVP :: String -> String -> (String, String)
|
||||
splitOnPVP c s = case Split.splitOn c s of
|
||||
[] -> def
|
||||
[_] -> def
|
||||
xs
|
||||
| let l = last xs
|
||||
, (Right _) <- pvp (T.pack l) -> (intercalate c (init xs), l)
|
||||
| otherwise -> def
|
||||
where
|
||||
def = (s, "")
|
||||
|
||||
|
||||
|
||||
-- | Like 'find', but where the test can be monadic.
|
||||
--
|
||||
-- >>> findM (Just . C.isUpper) "teST"
|
||||
-- Just (Just 'S')
|
||||
-- >>> findM (Just . C.isUpper) "test"
|
||||
-- Just Nothing
|
||||
-- >>> findM (Just . const True) ["x",undefined]
|
||||
-- Just (Just "x")
|
||||
findM :: Monad m => (a -> m Bool) -> [a] -> m (Maybe a)
|
||||
findM ~p = foldr (\x -> ifM (p x) (pure $ Just x)) (pure Nothing)
|
||||
|
||||
|
||||
-- | Drops the given suffix from a list.
|
||||
-- It returns the original sequence if the sequence doesn't end with the given suffix.
|
||||
--
|
||||
-- >>> dropSuffix "!" "Hello World!"
|
||||
-- "Hello World"
|
||||
-- >>> dropSuffix "!" "Hello World!!"
|
||||
-- "Hello World!"
|
||||
-- >>> dropSuffix "!" "Hello World."
|
||||
-- "Hello World."
|
||||
dropSuffix :: Eq a => [a] -> [a] -> [a]
|
||||
dropSuffix a b = fromMaybe b $ stripSuffix a b
|
||||
|
||||
-- | Return the prefix of the second list if its suffix
|
||||
-- matches the entire first list.
|
||||
--
|
||||
-- >>> stripSuffix "bar" "foobar"
|
||||
-- Just "foo"
|
||||
-- >>> stripSuffix "" "baz"
|
||||
-- Just "baz"
|
||||
-- >>> stripSuffix "foo" "quux"
|
||||
-- Nothing
|
||||
stripSuffix :: Eq a => [a] -> [a] -> Maybe [a]
|
||||
stripSuffix a b = reverse <$> stripPrefix (reverse a) (reverse b)
|
||||
|
||||
|
||||
-- | Drops the given prefix from a list.
|
||||
-- It returns the original sequence if the sequence doesn't start with the given prefix.
|
||||
--
|
||||
-- >>> dropPrefix "Mr. " "Mr. Men"
|
||||
-- "Men"
|
||||
-- >>> dropPrefix "Mr. " "Dr. Men"
|
||||
-- "Dr. Men"
|
||||
dropPrefix :: Eq a => [a] -> [a] -> [a]
|
||||
dropPrefix a b = fromMaybe b $ stripPrefix a b
|
||||
|
||||
|
||||
|
||||
-- | Break a list into pieces separated by the first
|
||||
-- list argument, consuming the delimiter. An empty delimiter is
|
||||
-- invalid, and will cause an error to be raised.
|
||||
--
|
||||
-- >>> splitOn "\r\n" "a\r\nb\r\nd\r\ne"
|
||||
-- ["a","b","d","e"]
|
||||
-- >>> splitOn "aaa" "aaaXaaaXaaaXaaa"
|
||||
-- ["","X","X","X",""]
|
||||
-- >>> splitOn "x" "x"
|
||||
-- ["",""]
|
||||
-- >>> splitOn "x" ""
|
||||
-- [""]
|
||||
--
|
||||
-- prop> \s x -> s /= "" ==> intercalate s (splitOn s x) == x
|
||||
-- prop> \c x -> splitOn [c] x == split (==c) x
|
||||
splitOn :: Eq a => [a] -> [a] -> [[a]]
|
||||
splitOn [] _ = error "splitOn, needle may not be empty"
|
||||
splitOn _ [] = [[]]
|
||||
splitOn needle haystack = a : if null b then [] else splitOn needle $ drop (length needle) b
|
||||
where (a,b) = breakOn needle haystack
|
||||
|
||||
|
||||
-- | Splits a list into components delimited by separators,
|
||||
-- where the predicate returns True for a separator element. The
|
||||
-- resulting components do not contain the separators. Two adjacent
|
||||
-- separators result in an empty component in the output.
|
||||
--
|
||||
-- >>> split (== 'a') "aabbaca"
|
||||
-- ["","","bb","c",""]
|
||||
-- >>> split (== 'a') ""
|
||||
-- [""]
|
||||
-- >>> split (== ':') "::xyz:abc::123::"
|
||||
-- ["","","xyz","abc","","123","",""]
|
||||
-- >>> split (== ',') "my,list,here"
|
||||
-- ["my","list","here"]
|
||||
split :: (a -> Bool) -> [a] -> [[a]]
|
||||
split _ [] = [[]]
|
||||
split f (x:xs)
|
||||
| f x = [] : split f xs
|
||||
| y:ys <- split f xs = (x:y) : ys
|
||||
| otherwise = [[]]
|
||||
|
||||
|
||||
-- | Find the first instance of @needle@ in @haystack@.
|
||||
-- The first element of the returned tuple
|
||||
-- is the prefix of @haystack@ before @needle@ is matched. The second
|
||||
-- is the remainder of @haystack@, starting with the match.
|
||||
-- If you want the remainder /without/ the match, use 'stripInfix'.
|
||||
--
|
||||
-- >>> breakOn "::" "a::b::c"
|
||||
-- ("a","::b::c")
|
||||
-- >>> breakOn "/" "foobar"
|
||||
-- ("foobar","")
|
||||
--
|
||||
-- prop> \needle haystack -> let (prefix,match) = breakOn needle haystack in prefix ++ match == haystack
|
||||
breakOn :: Eq a => [a] -> [a] -> ([a], [a])
|
||||
breakOn needle haystack | needle `isPrefixOf` haystack = ([], haystack)
|
||||
breakOn _ [] = ([], [])
|
||||
breakOn needle (x:xs) = first (x:) $ breakOn needle xs
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -44,15 +44,14 @@ import Language.Haskell.TH.Quote
|
||||
-- The pattern portion is undefined.
|
||||
s :: QuasiQuoter
|
||||
s = QuasiQuoter
|
||||
(\s' -> case and $ fmap isAscii s' of
|
||||
(\s' -> case all isAscii s' of
|
||||
True -> (\a -> [|fromString a|]) . trimLeadingNewline . removeCRs $ s'
|
||||
False -> fail "Not ascii"
|
||||
)
|
||||
(error "Cannot use q as a pattern")
|
||||
(error "Cannot use q as a type")
|
||||
(error "Cannot use q as a dec")
|
||||
(error "Cannot use s as a pattern")
|
||||
(error "Cannot use s as a type")
|
||||
(error "Cannot use s as a dec")
|
||||
where
|
||||
removeCRs = filter (/= '\r')
|
||||
trimLeadingNewline ('\n' : xs) = xs
|
||||
trimLeadingNewline xs = xs
|
||||
|
||||
|
||||
@@ -24,8 +24,11 @@ import qualified Data.List.NonEmpty as NE
|
||||
import qualified Data.Text as T
|
||||
|
||||
-- | This reflects the API version of the YAML.
|
||||
--
|
||||
-- Note that when updating this, CI requires that the file exsists AND the same file exists at
|
||||
-- 'https://www.haskell.org/ghcup/exp/ghcup-<ver>.yaml' with some newlines added.
|
||||
ghcupURL :: URI
|
||||
ghcupURL = [uri|https://www.haskell.org/ghcup/data/ghcup-0.0.5.yaml|]
|
||||
ghcupURL = [uri|https://www.haskell.org/ghcup/data/ghcup-0.0.6.yaml|]
|
||||
|
||||
-- | The current ghcup version.
|
||||
ghcUpVer :: PVP
|
||||
|
||||
43
lib/System/Console/Terminal/Common.hs
Normal file
@@ -0,0 +1,43 @@
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE DeriveDataTypeable #-}
|
||||
{-# LANGUAGE DeriveTraversable #-}
|
||||
|
||||
#if __GLASGOW_HASKELL__ >= 702
|
||||
#define LANGUAGE_DeriveGeneric
|
||||
{-# LANGUAGE DeriveGeneric #-}
|
||||
#endif
|
||||
|
||||
module System.Console.Terminal.Common
|
||||
( Window(..)
|
||||
) where
|
||||
|
||||
import Data.Data (Typeable, Data)
|
||||
|
||||
#if __GLASGOW_HASKELL__ < 710
|
||||
import Data.Foldable (Foldable)
|
||||
import Data.Traversable (Traversable)
|
||||
#endif
|
||||
|
||||
#ifdef LANGUAGE_DeriveGeneric
|
||||
import GHC.Generics
|
||||
( Generic
|
||||
#if __GLASGOW_HASKELL__ >= 706
|
||||
, Generic1
|
||||
#endif
|
||||
)
|
||||
#endif
|
||||
|
||||
-- | Terminal window width and height
|
||||
data Window a = Window
|
||||
{ height :: !a
|
||||
, width :: !a
|
||||
} deriving
|
||||
( Show, Eq, Read, Data, Typeable
|
||||
, Foldable, Functor, Traversable
|
||||
#ifdef LANGUAGE_DeriveGeneric
|
||||
, Generic
|
||||
#if __GLASGOW_HASKELL__ >= 706
|
||||
, Generic1
|
||||
#endif
|
||||
#endif
|
||||
)
|
||||
65
lib/System/Console/Terminal/Posix.hsc
Normal file
@@ -0,0 +1,65 @@
|
||||
{-# LANGUAGE CApiFFI #-}
|
||||
|
||||
module System.Console.Terminal.Posix
|
||||
( size, fdSize, hSize
|
||||
) where
|
||||
|
||||
import System.Console.Terminal.Common
|
||||
import Control.Exception (catch)
|
||||
import Data.Typeable (cast)
|
||||
import Foreign
|
||||
import Foreign.C.Error
|
||||
import Foreign.C.Types
|
||||
import GHC.IO.FD (FD(FD, fdFD))
|
||||
import GHC.IO.Handle.Internals (withHandle_)
|
||||
import GHC.IO.Handle.Types (Handle, Handle__(Handle__, haDevice))
|
||||
#if defined(__GLASGOW_HASKELL__) && (__GLASGOW_HASKELL__ < 706)
|
||||
import Prelude hiding (catch)
|
||||
#endif
|
||||
import System.Posix.Types (Fd(Fd))
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
#let alignment t = "%lu", (unsigned long)offsetof(struct {char x__; t (y__); }, y__)
|
||||
|
||||
|
||||
-- Interesting part of @struct winsize@
|
||||
data CWin = CWin CUShort CUShort
|
||||
|
||||
instance Storable CWin where
|
||||
sizeOf _ = (#size struct winsize)
|
||||
alignment _ = (#alignment struct winsize)
|
||||
peek ptr = do
|
||||
row <- (#peek struct winsize, ws_row) ptr
|
||||
col <- (#peek struct winsize, ws_col) ptr
|
||||
return $ CWin row col
|
||||
poke ptr (CWin row col) = do
|
||||
(#poke struct winsize, ws_row) ptr row
|
||||
(#poke struct winsize, ws_col) ptr col
|
||||
|
||||
|
||||
fdSize :: Integral n => Fd -> IO (Maybe (Window n))
|
||||
fdSize (Fd fd) = with (CWin 0 0) $ \ws -> do
|
||||
_ <- throwErrnoIfMinus1 "ioctl" $
|
||||
ioctl fd (#const TIOCGWINSZ) ws
|
||||
CWin row col <- peek ws
|
||||
return . Just $ Window (fromIntegral row) (fromIntegral col)
|
||||
`catch`
|
||||
handler
|
||||
where
|
||||
handler :: IOError -> IO (Maybe (Window h))
|
||||
handler _ = return Nothing
|
||||
|
||||
foreign import capi "sys/ioctl.h ioctl"
|
||||
ioctl :: CInt -> CULong -> Ptr CWin -> IO CInt
|
||||
|
||||
size :: Integral n => IO (Maybe (Window n))
|
||||
size = fdSize (Fd (#const STDOUT_FILENO))
|
||||
|
||||
hSize :: Integral n => Handle -> IO (Maybe (Window n))
|
||||
hSize h = withHandle_ "hSize" h $ \Handle__ { haDevice = dev } ->
|
||||
case cast dev of
|
||||
Nothing -> return Nothing
|
||||
Just FD { fdFD = fd } -> fdSize (Fd fd)
|
||||
33
mkdocs.yml
Normal file
@@ -0,0 +1,33 @@
|
||||
site_name: GHCup
|
||||
site_url: https://www.haskell.org/ghcup
|
||||
site_description: GHCup documentation
|
||||
site_author: GHCup Team
|
||||
site_favicon: haskell_logo.png
|
||||
|
||||
repo_url: https://gitlab.haskell.org/haskell/ghcup-hs
|
||||
|
||||
theme:
|
||||
name: mkdocs
|
||||
locale: en
|
||||
|
||||
nav:
|
||||
- Home: index.md
|
||||
- "Getting Started": install.md
|
||||
- "User Guide": guide.md
|
||||
- "Developer Guide": dev.md
|
||||
- About: about.md
|
||||
|
||||
extra_css:
|
||||
- css/extra.css
|
||||
|
||||
extra_javascript:
|
||||
- javascripts/extra.js
|
||||
|
||||
markdown_extensions:
|
||||
- toc:
|
||||
permalink:
|
||||
- admonition
|
||||
- attr_list
|
||||
- def_list
|
||||
- meta
|
||||
|
||||
9
scoop-better-shimexe/LICENSE-MIT
Normal file
@@ -0,0 +1,9 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Grégoire Geis
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
10
scoop-better-shimexe/LICENSE-UNLICENSE
Normal file
@@ -0,0 +1,10 @@
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For more information, please refer to <http://unlicense.org/>
|
||||
71
scoop-better-shimexe/README.md
Normal file
@@ -0,0 +1,71 @@
|
||||
# `shim.c`
|
||||
|
||||
[`shim.c`](./shim.c) is a simple Windows program that, when started:
|
||||
1. Looks for a file with the exact same name as the running program, but with
|
||||
the extension `shim` (e.g. `C:\bin\foo.exe` will read the file `C:\bin\foo.shim`).
|
||||
2. Reads and [parses](#shim-format) the files into a
|
||||
[Scoop](https://github.com/lukesampson/scoop) shim format.
|
||||
3. Executes the target executable with the given arguments.
|
||||
|
||||
`shim.c` was originally made to replace [Scoop](https://github.com/lukesampson/scoop)'s
|
||||
[`shim.cs`](https://github.com/lukesampson/scoop/blob/96de9c14bb483f9278e4b0a9e22b1923ee752901/supporting/shimexe/shim.cs)
|
||||
since it had several important flaws:
|
||||
1. [It was made in C#](https://github.com/lukesampson/scoop/tree/96de9c14bb483f9278e4b0a9e22b1923ee752901/supporting/shimexe),
|
||||
and thus required an instantiation of a .NET command line app everytime it was started,
|
||||
which can make a command run much slower than if it had been ran directly;
|
||||
2. [It](https://github.com/lukesampson/scoop/issues/2339) [did](https://github.com/lukesampson/scoop/issues/1896)
|
||||
[not](https://github.com/felixse/FluentTerminal/issues/221) handle Ctrl+C and other
|
||||
signals correctly, which could be quite infuriating (and essentially killing REPLs and long-running apps).
|
||||
|
||||
[`shim.c`](./shim.c) is:
|
||||
- **Faster**, because it does not use the .NET Framework, and parses the `.shim` file in a simpler way.
|
||||
- **More efficient**, because by the time the target of the shim is started, all allocated memory will have been freed.
|
||||
- And more importantly, it **works better**:
|
||||
- Signals originating from pressing `Ctrl+C` are ignored, and therefore handled directly by the spawned child.
|
||||
Your processes and REPLs will no longer close when pressing `Ctrl+C`.
|
||||
- Children are automatically killed when the shim process is killed. No more orphaned processes and weird behaviors.
|
||||
|
||||
> **Note**: This project is not affiliated with [Scoop](https://github.com/lukesampson/scoop).
|
||||
|
||||
|
||||
## Installation for Scoop
|
||||
|
||||
- In a Visual Studio command prompt, run `cl /O1 shim.c`.
|
||||
- Replace any `.exe` in `scoop\shims` by `shim.exe`.
|
||||
|
||||
An additional script, `repshims.bat`, is provided. It will replace all `.exe`s in the user's Scoop directory
|
||||
by `shim.exe`.
|
||||
|
||||
|
||||
## Example
|
||||
|
||||
Given the following shim `gs.shim`:
|
||||
```
|
||||
path = C:\Program Files\Git\git.exe
|
||||
args = status -u
|
||||
```
|
||||
|
||||
In this directory, where `gs.exe` is the compiled `shim.c`:
|
||||
```
|
||||
C:\Bin\
|
||||
gs.exe
|
||||
gs.shim
|
||||
```
|
||||
|
||||
Then calling `gs -s` will run the program `C:\Program Files\Git\git.exe status -u -s`.
|
||||
|
||||
|
||||
## Shim format
|
||||
|
||||
Shims follow the same format as Scoop's shims: line-separated `key = value` pairs.
|
||||
```
|
||||
path = C:\Program Files\Git\git.exe
|
||||
args = status -uno
|
||||
```
|
||||
|
||||
`path` is a required value, but `args` can be omitted. Also, do note that lines **must** end with a line feed.
|
||||
|
||||
|
||||
## License
|
||||
|
||||
`SPDX-License-Identifier: MIT OR Unlicense`
|
||||
15
scoop-better-shimexe/repshims.bat
Normal file
@@ -0,0 +1,15 @@
|
||||
@echo off
|
||||
|
||||
if not defined SCOOP set SCOOP=%USERPROFILE%\scoop
|
||||
|
||||
for %%x in ("%SCOOP%\shims\*.exe") do (
|
||||
echo Replacing %%x by new shim.
|
||||
copy /B /Y shim.exe "%%~x" >NUL
|
||||
)
|
||||
|
||||
if not defined SCOOP_GLOBAL set SCOOP_GLOBAL=%ProgramData%\scoop
|
||||
|
||||
for %%x in ("%SCOOP_GLOBAL%\shims\*.exe") do (
|
||||
echo Replacing %%x by new shim.
|
||||
copy /B /Y shim.exe "%%~x" >NUL
|
||||
)
|
||||
256
scoop-better-shimexe/shim.c
Normal file
@@ -0,0 +1,256 @@
|
||||
#pragma comment(lib, "SHELL32.LIB")
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <wchar.h>
|
||||
#include <Windows.h>
|
||||
|
||||
#ifndef ERROR_ELEVATION_REQUIRED
|
||||
# define ERROR_ELEVATION_REQUIRED 740
|
||||
#endif
|
||||
|
||||
#define MAX_FILENAME_SIZE 512
|
||||
|
||||
BOOL WINAPI ctrlhandler(DWORD fdwCtrlType)
|
||||
{
|
||||
switch (fdwCtrlType) {
|
||||
// Ignore all events, and let the child process
|
||||
// handle them.
|
||||
case CTRL_C_EVENT:
|
||||
case CTRL_CLOSE_EVENT:
|
||||
case CTRL_LOGOFF_EVENT:
|
||||
case CTRL_BREAK_EVENT:
|
||||
case CTRL_SHUTDOWN_EVENT:
|
||||
return TRUE;
|
||||
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
int compute_program_length(const wchar_t* commandline)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
if (commandline[0] == L'"') {
|
||||
// Wait till end of string
|
||||
i++;
|
||||
|
||||
for (;;) {
|
||||
wchar_t c = commandline[i++];
|
||||
|
||||
if (c == 0)
|
||||
return i - 1;
|
||||
else if (c == L'\\')
|
||||
i++;
|
||||
else if (c == L'"')
|
||||
return i;
|
||||
}
|
||||
} else {
|
||||
for (;;) {
|
||||
wchar_t c = commandline[i++];
|
||||
|
||||
if (c == 0)
|
||||
return i - 1;
|
||||
else if (c == L'\\')
|
||||
i++;
|
||||
else if (c == L' ')
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
DWORD exit_code = 0;
|
||||
|
||||
wchar_t* path = NULL;
|
||||
wchar_t* args = NULL;
|
||||
wchar_t* cmd = NULL;
|
||||
|
||||
// Find filename of current executable.
|
||||
wchar_t filename[MAX_FILENAME_SIZE + 2];
|
||||
const unsigned int filename_size = GetModuleFileNameW(NULL, filename, MAX_FILENAME_SIZE);
|
||||
|
||||
if (filename_size >= MAX_FILENAME_SIZE) {
|
||||
fprintf(stderr, "The filename of the program is too long to handle.\n");
|
||||
|
||||
exit_code = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// Use filename of current executable to find .shim
|
||||
filename[filename_size - 3] = L's';
|
||||
filename[filename_size - 2] = L'h';
|
||||
filename[filename_size - 1] = L'i';
|
||||
filename[filename_size - 0] = L'm';
|
||||
filename[filename_size + 1] = 0 ;
|
||||
|
||||
FILE* shim_file;
|
||||
|
||||
if ((shim_file = _wfsopen(filename, L"r,ccs=UTF-8", _SH_DENYNO)) == NULL) {
|
||||
fprintf(stderr, "Cannot open shim file for read.\n");
|
||||
|
||||
exit_code = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
size_t command_length = 256;
|
||||
size_t path_length;
|
||||
size_t args_length;
|
||||
|
||||
// Read shim
|
||||
wchar_t linebuf[8192];
|
||||
|
||||
for (;;) {
|
||||
const wchar_t* line = fgetws(linebuf, 8192, shim_file);
|
||||
|
||||
if (line == NULL)
|
||||
break;
|
||||
|
||||
if (line[4] != L' ' || line[5] != L'=' || line[6] != L' ')
|
||||
continue;
|
||||
|
||||
const int linelen = wcslen(line);
|
||||
const int len = linelen - 8 + (line[linelen - 1] != '\n');
|
||||
|
||||
if (line[0] == L'p' && line[1] == L'a' && line[2] == L't' && line[3] == L'h') {
|
||||
// Reading path
|
||||
path = calloc(len + 1, sizeof(wchar_t));
|
||||
wmemcpy(path, line + 7, len);
|
||||
|
||||
command_length += len;
|
||||
path_length = len;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line[0] == L'a' && line[1] == L'r' && line[2] == L'g' && line[3] == L's') {
|
||||
// Reading args
|
||||
args = calloc(len + 1, sizeof(wchar_t));
|
||||
wmemcpy(args, line + 7, len);
|
||||
|
||||
command_length += len + 1;
|
||||
args_length = len;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
fclose(shim_file);
|
||||
|
||||
if (path == NULL) {
|
||||
fprintf(stderr, "Could not read shim file.\n");
|
||||
|
||||
exit_code = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// Find length of command to run
|
||||
wchar_t* given_cmd = GetCommandLineW();
|
||||
const int program_length = compute_program_length(given_cmd);
|
||||
|
||||
given_cmd += program_length;
|
||||
|
||||
const int given_length = wcslen(given_cmd);
|
||||
|
||||
command_length += given_length;
|
||||
|
||||
// Start building command to run, using '[path] [args]', as given by shim.
|
||||
cmd = calloc(command_length, sizeof(wchar_t));
|
||||
int cmd_i = 0;
|
||||
|
||||
wmemcpy(cmd, path, path_length);
|
||||
cmd[path_length] = ' ';
|
||||
cmd_i += path_length + 1;
|
||||
|
||||
if (args != NULL) {
|
||||
wmemcpy(cmd + path_length + 1, args, args_length);
|
||||
cmd[path_length + args_length + 1] = ' ';
|
||||
cmd_i += args_length + 1;
|
||||
}
|
||||
|
||||
// Copy all given arguments to command
|
||||
wmemcpy(cmd + cmd_i, given_cmd, given_length);
|
||||
|
||||
// Find out if the target program is a console app
|
||||
SHFILEINFOW sfi = {0};
|
||||
const BOOL is_windows_app = HIWORD(SHGetFileInfoW(path, -1, &sfi, sizeof(sfi), SHGFI_EXETYPE));
|
||||
|
||||
if (is_windows_app)
|
||||
// Unfortunately, this technique will still show a window for a fraction of time,
|
||||
// but there's just no workaround.
|
||||
FreeConsole();
|
||||
|
||||
// Create job object, which can be attached to child processes
|
||||
// to make sure they terminate when the parent terminates as well.
|
||||
JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = {0};
|
||||
HANDLE jobHandle = CreateJobObject(NULL, NULL);
|
||||
|
||||
jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE | JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK;
|
||||
SetInformationJobObject(jobHandle, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli));
|
||||
|
||||
// Start subprocess
|
||||
STARTUPINFOW si = {0};
|
||||
PROCESS_INFORMATION pi = {0};
|
||||
|
||||
if (CreateProcessW(NULL, cmd, NULL, NULL, TRUE, CREATE_SUSPENDED, NULL, NULL, &si, &pi)) {
|
||||
AssignProcessToJobObject(jobHandle, pi.hProcess);
|
||||
ResumeThread(pi.hThread);
|
||||
} else {
|
||||
if (GetLastError() == ERROR_ELEVATION_REQUIRED) {
|
||||
// We must elevate the process, which is (basically) impossible with
|
||||
// CreateProcess, and therefore we fallback to ShellExecuteEx,
|
||||
// which CAN create elevated processes, at the cost of opening a new separate
|
||||
// window.
|
||||
// Theorically, this could be fixed (or rather, worked around) using pipes
|
||||
// and IPC, but... this is a question for another day.
|
||||
SHELLEXECUTEINFOW sei = {0};
|
||||
|
||||
sei.cbSize = sizeof(SHELLEXECUTEINFOW);
|
||||
sei.fMask = SEE_MASK_NOCLOSEPROCESS;
|
||||
sei.lpFile = path;
|
||||
sei.lpParameters = cmd + path_length + 1;
|
||||
sei.nShow = SW_SHOW;
|
||||
|
||||
if (!ShellExecuteExW(&sei)) {
|
||||
fprintf(stderr, "Unable to create elevated process: error %li.", GetLastError());
|
||||
|
||||
exit_code = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
pi.hProcess = sei.hProcess;
|
||||
} else {
|
||||
fprintf(stderr, "Could not create process with command '%ls'.\n", cmd);
|
||||
|
||||
exit_code = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
// Ignore Ctrl-C and other signals
|
||||
if (!SetConsoleCtrlHandler(ctrlhandler, TRUE))
|
||||
fprintf(stderr, "Could not set control handler; Ctrl-C behavior may be invalid.\n");
|
||||
|
||||
// Wait till end of process
|
||||
WaitForSingleObject(pi.hProcess, INFINITE);
|
||||
|
||||
GetExitCodeProcess(pi.hProcess, &exit_code);
|
||||
|
||||
// Dispose of everything
|
||||
CloseHandle(pi.hThread);
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(jobHandle);
|
||||
|
||||
cleanup:
|
||||
|
||||
// Free obsolete buffers
|
||||
free(path);
|
||||
free(args);
|
||||
free(cmd);
|
||||
|
||||
return (int)exit_code;
|
||||
}
|
||||
712
scripts/bootstrap/bootstrap-haskell
Executable file
@@ -0,0 +1,712 @@
|
||||
#!/bin/sh
|
||||
|
||||
# This script downloads the 'ghcup' binary into '~/.ghcup/bin/' and then runs an interactive
|
||||
# installation that lets you choose various options. Below is a list of environment variables
|
||||
# that affect the installation procedure.
|
||||
|
||||
# Main settings:
|
||||
# * BOOTSTRAP_HASKELL_NONINTERACTIVE - any nonzero value for noninteractive installation
|
||||
# * BOOTSTRAP_HASKELL_NO_UPGRADE - any nonzero value to not trigger the upgrade
|
||||
# * BOOTSTRAP_HASKELL_MINIMAL - any nonzero value to only install ghcup
|
||||
# * GHCUP_USE_XDG_DIRS - any nonzero value to respect The XDG Base Directory Specification
|
||||
# * BOOTSTRAP_HASKELL_VERBOSE - any nonzero value for more verbose installation
|
||||
# * BOOTSTRAP_HASKELL_GHC_VERSION - the ghc version to install
|
||||
# * BOOTSTRAP_HASKELL_CABAL_VERSION - the cabal version to install
|
||||
# * BOOTSTRAP_HASKELL_INSTALL_STACK - whether to install latest stack
|
||||
# * BOOTSTRAP_HASKELL_INSTALL_HLS - whether to install latest hls
|
||||
# * BOOTSTRAP_HASKELL_ADJUST_BASHRC - whether to adjust PATH in bashrc (prepend)
|
||||
# * BOOTSTRAP_HASKELL_ADJUST_CABAL_CONFIG - whether to adjust mingw paths in cabal.config on windows
|
||||
|
||||
# License: LGPL-3.0
|
||||
|
||||
|
||||
# safety subshell to avoid executing anything in case this script is not downloaded properly
|
||||
(
|
||||
|
||||
plat="$(uname -s)"
|
||||
arch=$(uname -m)
|
||||
ghver="0.1.17.2"
|
||||
base_url="https://downloads.haskell.org/~ghcup"
|
||||
|
||||
export GHCUP_SKIP_UPDATE_CHECK=yes
|
||||
|
||||
case "${plat}" in
|
||||
MSYS*|MINGW*)
|
||||
: "${GHCUP_INSTALL_BASE_PREFIX:=/c}"
|
||||
GHCUP_DIR=$(cygpath -u "${GHCUP_INSTALL_BASE_PREFIX}/ghcup")
|
||||
GHCUP_BIN=$(cygpath -u "${GHCUP_INSTALL_BASE_PREFIX}/ghcup/bin")
|
||||
: "${GHCUP_MSYS2:=${GHCUP_DIR}/msys64}"
|
||||
;;
|
||||
*)
|
||||
: "${GHCUP_INSTALL_BASE_PREFIX:=$HOME}"
|
||||
export GHCUP_USE_XDG_DIRS
|
||||
|
||||
if [ -n "${GHCUP_USE_XDG_DIRS}" ] ; then
|
||||
GHCUP_DIR=${XDG_DATA_HOME:=$HOME/.local/share}/ghcup
|
||||
GHCUP_BIN=${XDG_BIN_HOME:=$HOME/.local/bin}
|
||||
else
|
||||
GHCUP_DIR=${GHCUP_INSTALL_BASE_PREFIX}/.ghcup
|
||||
GHCUP_BIN=${GHCUP_INSTALL_BASE_PREFIX}/.ghcup/bin
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
: "${BOOTSTRAP_HASKELL_GHC_VERSION:=recommended}"
|
||||
: "${BOOTSTRAP_HASKELL_CABAL_VERSION:=recommended}"
|
||||
|
||||
|
||||
die() {
|
||||
if [ -n "${NO_COLOR}" ] ; then
|
||||
(>&2 printf "%s\\n" "$1")
|
||||
else
|
||||
(>&2 printf "\\033[0;31m%s\\033[0m\\n" "$1")
|
||||
fi
|
||||
exit 2
|
||||
}
|
||||
|
||||
warn() {
|
||||
if [ -n "${NO_COLOR}" ] ; then
|
||||
printf "%s\\n" "$1"
|
||||
else
|
||||
case "${plat}" in
|
||||
MSYS*|MINGW*)
|
||||
# shellcheck disable=SC3037
|
||||
echo -e "\\033[0;35m$1\\033[0m"
|
||||
;;
|
||||
*)
|
||||
printf "\\033[0;35m%s\\033[0m\\n" "$1"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
}
|
||||
|
||||
yellow() {
|
||||
if [ -n "${NO_COLOR}" ] ; then
|
||||
printf "%s\\n" "$1"
|
||||
else
|
||||
case "${plat}" in
|
||||
MSYS*|MINGW*)
|
||||
# shellcheck disable=SC3037
|
||||
echo -e "\\033[0;33m$1\\033[0m"
|
||||
;;
|
||||
*)
|
||||
printf "\\033[0;33m%s\\033[0m\\n" "$1"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
}
|
||||
|
||||
green() {
|
||||
if [ -n "${NO_COLOR}" ] ; then
|
||||
printf "%s\\n" "$1"
|
||||
else
|
||||
case "${plat}" in
|
||||
MSYS*|MINGW*)
|
||||
# shellcheck disable=SC3037
|
||||
echo -e "\\033[0;32m$1\\033[0m"
|
||||
;;
|
||||
*)
|
||||
printf "\\033[0;32m%s\\033[0m\\n" "$1"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
}
|
||||
|
||||
edo() {
|
||||
"$@" || die "\"$*\" failed!"
|
||||
}
|
||||
|
||||
eghcup() {
|
||||
edo _eghcup "$@"
|
||||
}
|
||||
|
||||
_eghcup() {
|
||||
if [ -n "${BOOTSTRAP_HASKELL_YAML}" ] ; then
|
||||
args="-s ${BOOTSTRAP_HASKELL_YAML}"
|
||||
fi
|
||||
if [ -z "${BOOTSTRAP_HASKELL_VERBOSE}" ] ; then
|
||||
# shellcheck disable=SC2086
|
||||
"${GHCUP_BIN}/ghcup" ${args} "$@"
|
||||
else
|
||||
# shellcheck disable=SC2086
|
||||
"${GHCUP_BIN}/ghcup" ${args} --verbose "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
_done() {
|
||||
echo
|
||||
echo "==============================================================================="
|
||||
case "${plat}" in
|
||||
MSYS*|MINGW*)
|
||||
green
|
||||
green "All done!"
|
||||
green
|
||||
green "In a new powershell or cmd.exe session, now you can..."
|
||||
green
|
||||
green "Start a simple repl via:"
|
||||
green " ghci"
|
||||
green
|
||||
green "Start a new haskell project in the current directory via:"
|
||||
green " cabal init --interactive"
|
||||
green
|
||||
green "Install other GHC versions and tools via:"
|
||||
green " ghcup list"
|
||||
green " ghcup install <tool> <version>"
|
||||
green
|
||||
green "To install system libraries and update msys2/mingw64,"
|
||||
green "open the \"Mingw haskell shell\""
|
||||
green "and the \"Mingw package management docs\""
|
||||
green "desktop shortcuts."
|
||||
;;
|
||||
*)
|
||||
green
|
||||
green "All done!"
|
||||
green
|
||||
green "To start a simple repl, run:"
|
||||
green " ghci"
|
||||
green
|
||||
green "To start a new haskell project in the current directory, run:"
|
||||
green " cabal init --interactive"
|
||||
green
|
||||
green "To install other GHC versions and tools, run:"
|
||||
green " ghcup tui"
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
|
||||
exit 0
|
||||
}
|
||||
|
||||
download_ghcup() {
|
||||
|
||||
case "${plat}" in
|
||||
"linux"|"Linux")
|
||||
case "${arch}" in
|
||||
x86_64|amd64)
|
||||
# we could be in a 32bit docker container, in which
|
||||
# case uname doesn't give us what we want
|
||||
if [ "$(getconf LONG_BIT)" = "32" ] ; then
|
||||
_url=${base_url}/${ghver}/i386-linux-ghcup-${ghver}
|
||||
elif [ "$(getconf LONG_BIT)" = "64" ] ; then
|
||||
_url=${base_url}/${ghver}/x86_64-linux-ghcup-${ghver}
|
||||
else
|
||||
die "Unknown long bit size: $(getconf LONG_BIT)"
|
||||
fi
|
||||
;;
|
||||
i*86)
|
||||
_url=${base_url}/${ghver}/i386-linux-ghcup-${ghver}
|
||||
;;
|
||||
armv7*)
|
||||
_url=${base_url}/${ghver}/armv7-linux-ghcup-${ghver}
|
||||
;;
|
||||
aarch64|arm64|armv8l)
|
||||
# we could be in a 32bit docker container, in which
|
||||
# case uname doesn't give us what we want
|
||||
if [ "$(getconf LONG_BIT)" = "32" ] ; then
|
||||
_url=${base_url}/${ghver}/armv7-linux-ghcup-${ghver}
|
||||
elif [ "$(getconf LONG_BIT)" = "64" ] ; then
|
||||
_url=${base_url}/${ghver}/aarch64-linux-ghcup-${ghver}
|
||||
else
|
||||
die "Unknown long bit size: $(getconf LONG_BIT)"
|
||||
fi
|
||||
;;
|
||||
*) die "Unknown architecture: ${arch}"
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
"FreeBSD"|"freebsd")
|
||||
if freebsd-version | grep -E '^12.*' ; then
|
||||
freebsd_ver=12
|
||||
elif freebsd-version | grep -E '^13.*' ; then
|
||||
freebsd_ver=13
|
||||
else
|
||||
die "Unsupported FreeBSD version! Please report a bug at https://gitlab.haskell.org/haskell/ghcup-hs/-/issues"
|
||||
fi
|
||||
|
||||
case "${arch}" in
|
||||
x86_64|amd64)
|
||||
;;
|
||||
i*86)
|
||||
die "i386 currently not supported!"
|
||||
;;
|
||||
*) die "Unknown architecture: ${arch}"
|
||||
;;
|
||||
esac
|
||||
_url=${base_url}/${ghver}/x86_64-portbld-freebsd${freebsd_ver}-ghcup-${ghver}
|
||||
;;
|
||||
"Darwin"|"darwin")
|
||||
case "${arch}" in
|
||||
x86_64|amd64)
|
||||
_url=${base_url}/${ghver}/x86_64-apple-darwin-ghcup-${ghver}
|
||||
;;
|
||||
aarch64|arm64|armv8l)
|
||||
_url=${base_url}/${ghver}/aarch64-apple-darwin-ghcup-${ghver}
|
||||
;;
|
||||
i*86)
|
||||
die "i386 currently not supported!"
|
||||
;;
|
||||
*) die "Unknown architecture: ${arch}"
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
MSYS*|MINGW*)
|
||||
case "${arch}" in
|
||||
x86_64|amd64)
|
||||
_url=${base_url}/${ghver}/x86_64-mingw64-ghcup-${ghver}.exe
|
||||
;;
|
||||
*) die "Unknown architecture: ${arch}"
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
*) die "Unknown platform: ${plat}"
|
||||
;;
|
||||
esac
|
||||
case "${plat}" in
|
||||
MSYS*|MINGW*)
|
||||
edo curl -Lf "${_url}" > "${GHCUP_BIN}"/ghcup.exe
|
||||
edo chmod +x "${GHCUP_BIN}"/ghcup.exe
|
||||
;;
|
||||
*)
|
||||
edo curl -Lf "${_url}" > "${GHCUP_BIN}"/ghcup
|
||||
edo chmod +x "${GHCUP_BIN}"/ghcup
|
||||
;;
|
||||
esac
|
||||
|
||||
edo mkdir -p "${GHCUP_DIR}"
|
||||
|
||||
# we may overwrite this in adjust_bashrc
|
||||
cat <<-EOF > "${GHCUP_DIR}"/env || die "Failed to create env file"
|
||||
export PATH="\$HOME/.cabal/bin:${GHCUP_BIN}:\$PATH"
|
||||
EOF
|
||||
|
||||
# shellcheck disable=SC1090
|
||||
edo . "${GHCUP_DIR}"/env
|
||||
eghcup upgrade
|
||||
}
|
||||
|
||||
# Figures out the users login shell and sets
|
||||
# GHCUP_PROFILE_FILE and MY_SHELL variables.
|
||||
find_shell() {
|
||||
case $SHELL in
|
||||
*/zsh) # login shell is zsh
|
||||
GHCUP_PROFILE_FILE="$HOME/.zshrc"
|
||||
MY_SHELL="zsh" ;;
|
||||
*/bash) # login shell is bash
|
||||
GHCUP_PROFILE_FILE="$HOME/.bashrc"
|
||||
MY_SHELL="bash" ;;
|
||||
*/sh) # login shell is sh, but might be a symlink to bash or zsh
|
||||
if [ -n "${BASH}" ] ; then
|
||||
GHCUP_PROFILE_FILE="$HOME/.bashrc"
|
||||
MY_SHELL="bash"
|
||||
elif [ -n "${ZSH_VERSION}" ] ; then
|
||||
GHCUP_PROFILE_FILE="$HOME/.zshrc"
|
||||
MY_SHELL="zsh"
|
||||
else
|
||||
return
|
||||
fi
|
||||
;;
|
||||
*/fish) # login shell is fish
|
||||
GHCUP_PROFILE_FILE="$HOME/.config/fish/config.fish"
|
||||
MY_SHELL="fish" ;;
|
||||
*) return ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Ask user if they want to adjust the bashrc.
|
||||
ask_bashrc() {
|
||||
if [ -n "${BOOTSTRAP_HASKELL_ADJUST_BASHRC}" ] ; then
|
||||
return 1
|
||||
elif [ -z "${MY_SHELL}" ] ; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
while true; do
|
||||
if [ -z "${BOOTSTRAP_HASKELL_NONINTERACTIVE}" ] ; then
|
||||
echo "-------------------------------------------------------------------------------"
|
||||
|
||||
warn ""
|
||||
warn "Detected ${MY_SHELL} shell on your system..."
|
||||
warn "Do you want ghcup to automatically add the required PATH variable to \"${GHCUP_PROFILE_FILE}\"?"
|
||||
warn ""
|
||||
warn "[P] Yes, prepend [A] Yes, append [N] No [?] Help (default is \"P\")."
|
||||
warn ""
|
||||
|
||||
read -r bashrc_answer </dev/tty
|
||||
else
|
||||
return 0
|
||||
fi
|
||||
case $bashrc_answer in
|
||||
[Pp]* | "")
|
||||
return 1
|
||||
;;
|
||||
[Aa]*)
|
||||
return 2
|
||||
;;
|
||||
[Nn]*)
|
||||
return 0;;
|
||||
*)
|
||||
echo "Possible choices are:"
|
||||
echo
|
||||
echo "P - Yes, prepend to PATH, taking precedence (default)"
|
||||
echo "A - Yes, append to PATH"
|
||||
echo "N - No, don't mess with my configuration"
|
||||
echo
|
||||
echo "Please make your choice and press ENTER."
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
unset bashrc_answer
|
||||
}
|
||||
|
||||
# Needs 'find_shell' to be called beforehand.
|
||||
adjust_bashrc() {
|
||||
case $1 in
|
||||
1)
|
||||
cat <<-EOF > "${GHCUP_DIR}"/env || die "Failed to create env file"
|
||||
export PATH="\$HOME/.cabal/bin:${GHCUP_BIN}:\$PATH"
|
||||
EOF
|
||||
;;
|
||||
2)
|
||||
cat <<-EOF > "${GHCUP_DIR}"/env || die "Failed to create env file"
|
||||
export PATH="\$PATH:\$HOME/.cabal/bin:${GHCUP_BIN}"
|
||||
EOF
|
||||
;;
|
||||
*) ;;
|
||||
esac
|
||||
|
||||
case $1 in
|
||||
1 | 2)
|
||||
case $MY_SHELL in
|
||||
"")
|
||||
warn_path "Couldn't figure out login shell!"
|
||||
return
|
||||
;;
|
||||
fish)
|
||||
mkdir -p "${GHCUP_PROFILE_FILE%/*}"
|
||||
sed -i -e '/# ghcup-env$/ s/^#*/#/' "${GHCUP_PROFILE_FILE}"
|
||||
case $1 in
|
||||
1)
|
||||
echo "set -q GHCUP_INSTALL_BASE_PREFIX[1]; or set GHCUP_INSTALL_BASE_PREFIX \$HOME ; set -gx PATH \$HOME/.cabal/bin $GHCUP_BIN \$PATH # ghcup-env" >> "${GHCUP_PROFILE_FILE}"
|
||||
;;
|
||||
2)
|
||||
echo "set -q GHCUP_INSTALL_BASE_PREFIX[1]; or set GHCUP_INSTALL_BASE_PREFIX \$HOME ; set -gx PATH \$HOME/.cabal/bin \$PATH $GHCUP_BIN # ghcup-env" >> "${GHCUP_PROFILE_FILE}"
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
bash)
|
||||
sed -i -e '/# ghcup-env$/ s/^#*/#/' "${GHCUP_PROFILE_FILE}"
|
||||
echo "[ -f \"${GHCUP_DIR}/env\" ] && source \"${GHCUP_DIR}/env\" # ghcup-env" >> "${GHCUP_PROFILE_FILE}"
|
||||
case "${plat}" in
|
||||
"Darwin"|"darwin")
|
||||
if ! grep -q "ghcup-env" "${HOME}/.bash_profile" ; then
|
||||
echo "[[ -f ~/.bashrc ]] && source ~/.bashrc # ghcup-env" >> "${HOME}/.bash_profile"
|
||||
fi
|
||||
;;
|
||||
MSYS*|MINGW*)
|
||||
if [ ! -e "${HOME}/.bash_profile" ] ; then
|
||||
echo '# generated by ghcup' > "${HOME}/.bash_profile"
|
||||
echo 'test -f ~/.profile && . ~/.profile' >> "${HOME}/.bash_profile"
|
||||
echo 'test -f ~/.bashrc && . ~/.bashrc' >> "${HOME}/.bash_profile"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
|
||||
zsh)
|
||||
sed -i -e '/# ghcup-env$/ s/^#*/#/' "${GHCUP_PROFILE_FILE}"
|
||||
echo "[ -f \"${GHCUP_DIR}/env\" ] && source \"${GHCUP_DIR}/env\" # ghcup-env" >> "${GHCUP_PROFILE_FILE}"
|
||||
;;
|
||||
esac
|
||||
echo
|
||||
echo "==============================================================================="
|
||||
echo
|
||||
warn "OK! ${GHCUP_PROFILE_FILE} has been modified. Restart your terminal for the changes to take effect,"
|
||||
warn "or type \"source ${GHCUP_DIR}/env\" to apply them in your current terminal session."
|
||||
return
|
||||
;;
|
||||
*)
|
||||
warn_path
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
warn_path() {
|
||||
echo
|
||||
echo "==============================================================================="
|
||||
echo
|
||||
[ -n "$1" ] && warn "$1"
|
||||
yellow "In order to run ghc and cabal, you need to adjust your PATH variable."
|
||||
yellow "To do so, you may want to run 'source $GHCUP_DIR/env' in your current terminal"
|
||||
yellow "session as well as your shell configuration (e.g. ~/.bashrc)."
|
||||
|
||||
}
|
||||
|
||||
adjust_cabal_config() {
|
||||
edo cabal user-config -a "extra-prog-path: $(cygpath -w "$GHCUP_BIN"), $(cygpath -w "$HOME"/AppData/Roaming/cabal/bin), $(cygpath -w "$GHCUP_MSYS2"/usr/bin), $(cygpath -w "$GHCUP_MSYS2"/mingw64/bin)" -a "extra-include-dirs: $(cygpath -w "$GHCUP_MSYS2"/mingw64/include)" -a "extra-lib-dirs: $(cygpath -w "$GHCUP_MSYS2"/mingw64/lib)" -f init
|
||||
}
|
||||
|
||||
ask_cabal_config_init() {
|
||||
case "${plat}" in
|
||||
MSYS*|MINGW*)
|
||||
if [ -n "${BOOTSTRAP_HASKELL_ADJUST_CABAL_CONFIG}" ] ; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -z "${BOOTSTRAP_HASKELL_NONINTERACTIVE}" ] ; then
|
||||
echo "-------------------------------------------------------------------------------"
|
||||
warn "Create an initial cabal.config including relevant msys2 paths (recommended)?"
|
||||
warn "[Y] Yes [N] No [?] Help (default is \"Y\")."
|
||||
echo
|
||||
while true; do
|
||||
read -r mingw_answer </dev/tty
|
||||
|
||||
case $mingw_answer in
|
||||
[Yy]* | "")
|
||||
return 1 ;;
|
||||
[Nn]*)
|
||||
return 0 ;;
|
||||
*)
|
||||
echo "Possible choices are:"
|
||||
echo
|
||||
echo "Y - Yes, create a cabal.config with pre-set paths to msys2/mingw64 (default)"
|
||||
echo "N - No, leave the current/default cabal config untouched"
|
||||
echo
|
||||
echo "Please make your choice and press ENTER."
|
||||
;;
|
||||
esac
|
||||
done
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
unset mingw_answer
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
do_cabal_config_init() {
|
||||
case "${plat}" in
|
||||
MSYS*|MINGW*)
|
||||
case $1 in
|
||||
1)
|
||||
adjust_cabal_config
|
||||
;;
|
||||
0)
|
||||
echo "Make sure that your global cabal.config references the correct mingw64 paths (extra-prog-path, extra-include-dirs and extra-lib-dirs)."
|
||||
echo "And set the environment variable GHCUP_MSYS2 to the root path of your msys2 installation."
|
||||
sleep 5
|
||||
return ;;
|
||||
*) ;;
|
||||
esac
|
||||
esac
|
||||
}
|
||||
|
||||
ask_hls() {
|
||||
if [ -n "${BOOTSTRAP_HASKELL_INSTALL_HLS}" ] ; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -z "${BOOTSTRAP_HASKELL_NONINTERACTIVE}" ] ; then
|
||||
echo "-------------------------------------------------------------------------------"
|
||||
|
||||
warn "Do you want to install haskell-language-server (HLS)?"
|
||||
warn "HLS is a language-server that provides IDE-like functionality"
|
||||
warn "and can integrate with different editors, such as Vim, Emacs, VS Code, Atom, ..."
|
||||
warn "Also see https://github.com/haskell/haskell-language-server/blob/master/README.md"
|
||||
warn ""
|
||||
warn "[Y] Yes [N] No [?] Help (default is \"N\")."
|
||||
warn ""
|
||||
|
||||
while true; do
|
||||
read -r hls_answer </dev/tty
|
||||
|
||||
case $hls_answer in
|
||||
[Yy]*)
|
||||
return 1
|
||||
;;
|
||||
[Nn]* | "")
|
||||
return 0
|
||||
;;
|
||||
*)
|
||||
echo "Possible choices are:"
|
||||
echo
|
||||
echo "Y - Yes, install the haskell-langauge-server"
|
||||
echo "N - No, don't install anything more (default)"
|
||||
echo
|
||||
echo "Please make your choice and press ENTER."
|
||||
;;
|
||||
esac
|
||||
done
|
||||
else
|
||||
return 0
|
||||
fi
|
||||
|
||||
unset hls_answer
|
||||
}
|
||||
|
||||
ask_stack() {
|
||||
if [ -n "${BOOTSTRAP_HASKELL_INSTALL_STACK}" ] ; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -z "${BOOTSTRAP_HASKELL_NONINTERACTIVE}" ] ; then
|
||||
echo "-------------------------------------------------------------------------------"
|
||||
|
||||
warn "Do you want to install stack?"
|
||||
warn "Stack is a haskell build tool similar to cabal that is used by some projects."
|
||||
warn "Also see https://docs.haskellstack.org/"
|
||||
warn ""
|
||||
warn "[Y] Yes [N] No [?] Help (default is \"N\")."
|
||||
warn ""
|
||||
|
||||
while true; do
|
||||
read -r stack_answer </dev/tty
|
||||
|
||||
case $stack_answer in
|
||||
[Yy]*)
|
||||
return 1 ;;
|
||||
[Nn]* | "")
|
||||
return 0 ;;
|
||||
*)
|
||||
echo "Possible choices are:"
|
||||
echo
|
||||
echo "Y - Yes, install stack"
|
||||
echo "N - No, don't install anything more (default)"
|
||||
echo
|
||||
echo "Please make your choice and press ENTER."
|
||||
;;
|
||||
esac
|
||||
done
|
||||
else
|
||||
return 0
|
||||
fi
|
||||
|
||||
unset stack_answer
|
||||
}
|
||||
|
||||
|
||||
find_shell
|
||||
|
||||
|
||||
echo
|
||||
echo "Welcome to Haskell!"
|
||||
echo
|
||||
echo "This script will download and install the following binaries:"
|
||||
echo " * ghcup - The Haskell toolchain installer"
|
||||
echo " * ghc - The Glasgow Haskell Compiler"
|
||||
echo " * cabal - The Cabal build tool for managing Haskell software"
|
||||
echo " * stack - (optional) A cross-platform program for developing Haskell projects"
|
||||
echo " * hls - (optional) A language server for developers to integrate with their editor/IDE"
|
||||
echo
|
||||
if [ -z "${GHCUP_USE_XDG_DIRS}" ] ; then
|
||||
echo "ghcup installs only into the following directory,"
|
||||
echo "which can be removed anytime:"
|
||||
case "${plat}" in
|
||||
MSYS*|MINGW*)
|
||||
echo " $(cygpath -w "$GHCUP_DIR")"
|
||||
;;
|
||||
*)
|
||||
echo " $GHCUP_DIR"
|
||||
;;
|
||||
esac
|
||||
else
|
||||
echo "ghcup installs into XDG directories as long as"
|
||||
echo "'GHCUP_USE_XDG_DIRS' is set."
|
||||
fi
|
||||
echo
|
||||
|
||||
if [ -z "${BOOTSTRAP_HASKELL_NONINTERACTIVE}" ] ; then
|
||||
warn "Press ENTER to proceed or ctrl-c to abort."
|
||||
warn "Note that this script can be re-run at any given time."
|
||||
# Wait for user input to continue.
|
||||
# shellcheck disable=SC2034
|
||||
read -r answer </dev/tty
|
||||
fi
|
||||
|
||||
ask_bashrc
|
||||
ask_bashrc_answer=$?
|
||||
ask_cabal_config_init
|
||||
ask_cabal_config_init_answer=$?
|
||||
if [ -z "${BOOTSTRAP_HASKELL_MINIMAL}" ] ; then
|
||||
ask_hls
|
||||
ask_hls_answer=$?
|
||||
ask_stack
|
||||
ask_stack_answer=$?
|
||||
fi
|
||||
|
||||
edo mkdir -p "${GHCUP_BIN}"
|
||||
|
||||
if command -V "ghcup" >/dev/null 2>&1 ; then
|
||||
if [ -z "${BOOTSTRAP_HASKELL_NO_UPGRADE}" ] ; then
|
||||
_eghcup upgrade || download_ghcup
|
||||
fi
|
||||
else
|
||||
download_ghcup
|
||||
fi
|
||||
|
||||
echo
|
||||
if [ -n "${BOOTSTRAP_HASKELL_YAML}" ] ; then (>&2 ghcup -s "${BOOTSTRAP_HASKELL_YAML}" tool-requirements) ; else (>&2 ghcup tool-requirements) ; fi
|
||||
echo
|
||||
|
||||
if [ -z "${BOOTSTRAP_HASKELL_NONINTERACTIVE}" ] ; then
|
||||
warn "Press ENTER to proceed or ctrl-c to abort."
|
||||
warn "Installation may take a while."
|
||||
echo
|
||||
|
||||
# Wait for user input to continue.
|
||||
# shellcheck disable=SC2034
|
||||
read -r answer </dev/tty
|
||||
fi
|
||||
|
||||
if [ -z "${BOOTSTRAP_HASKELL_MINIMAL}" ] ; then
|
||||
eghcup --cache install ghc "${BOOTSTRAP_HASKELL_GHC_VERSION}"
|
||||
|
||||
eghcup set ghc "${BOOTSTRAP_HASKELL_GHC_VERSION}"
|
||||
eghcup --cache install cabal "${BOOTSTRAP_HASKELL_CABAL_VERSION}"
|
||||
|
||||
do_cabal_config_init $ask_cabal_config_init_answer
|
||||
|
||||
edo cabal new-update
|
||||
else # don't install ghc and cabal
|
||||
case "${plat}" in
|
||||
MSYS*|MINGW*)
|
||||
# need to bootstrap cabal to initialize config on windows
|
||||
# we'll remove it afterwards
|
||||
tmp_dir="$(mktemp -d)"
|
||||
eghcup --cache install cabal -i "${tmp_dir}" "${BOOTSTRAP_HASKELL_CABAL_VERSION}"
|
||||
PATH="${tmp_dir}:$PATH" do_cabal_config_init $ask_cabal_config_init_answer
|
||||
rm "${tmp_dir}/cabal"
|
||||
unset tmp_dir
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
case $ask_hls_answer in
|
||||
1)
|
||||
_eghcup --cache install hls || warn "HLS installation failed, continuing anyway"
|
||||
;;
|
||||
*) ;;
|
||||
esac
|
||||
|
||||
case $ask_stack_answer in
|
||||
1)
|
||||
_eghcup --cache install stack || warn "Stack installation failed, continuing anyway"
|
||||
;;
|
||||
*) ;;
|
||||
esac
|
||||
|
||||
|
||||
adjust_bashrc $ask_bashrc_answer
|
||||
|
||||
|
||||
_done
|
||||
|
||||
)
|
||||
|
||||
# vim: tabstop=4 shiftwidth=4 expandtab
|
||||
@@ -11,22 +11,36 @@
|
||||
* cabal - The Cabal build tool for managing Haskell software"
|
||||
* stack - (optional) A cross-platform program for developing Haskell projects"
|
||||
* hls - (optional) A language server for developers to integrate with their editor/IDE"
|
||||
|
||||
By default, the installation is non-interactive, unless you run it with 'Interactive $true'.
|
||||
#>
|
||||
param (
|
||||
# Run a non-interactive installation
|
||||
[switch]$Silent,
|
||||
# Specify the install root (default: 'C:\')
|
||||
# Run an interactive installation
|
||||
[switch]$Interactive,
|
||||
# Do minimal installation of ghcup and msys2 only
|
||||
[switch]$Minimal,
|
||||
# Run the final bootstrap script via 'bash' instead of a full newly spawned msys2 shell
|
||||
[switch]$InBash,
|
||||
# Overwrite (or rather backup) a previous install
|
||||
[switch]$Overwrite,
|
||||
# Skip adjusting cabal.config with mingw paths
|
||||
[switch]$NoAdjustCabalConfig,
|
||||
# Whether to install stack as well
|
||||
[switch]$InstallStack,
|
||||
# Whether to install hls as well
|
||||
[switch]$InstallHLS,
|
||||
# Specify the bootstrap url (default: 'https://www.haskell.org/ghcup/sh/bootstrap-haskell')
|
||||
[string]$InstallDir,
|
||||
# Instead of installing a new MSys2, use an existing installation
|
||||
[string]$BootstrapUrl,
|
||||
# Specify the install root (default: 'C:\')
|
||||
[string]$ExistingMsys2Dir,
|
||||
# Specify the cabal root directory (default: '$InstallDir\cabal')
|
||||
[string]$CabalDir,
|
||||
# Perform a quick installation, omitting some expensive operations (you may have to install dependencies yourself later)
|
||||
[bool]$Quick,
|
||||
# Overwrite (or rather backup) a previous install
|
||||
[bool]$Overwrite
|
||||
[string]$CabalDir
|
||||
)
|
||||
|
||||
$Silent = !$Interactive
|
||||
|
||||
function Print-Msg {
|
||||
param ( [Parameter(Mandatory=$true, HelpMessage='String to output')][string]$msg, [string]$color = "Green" )
|
||||
Write-Host ('{0}' -f $msg) -ForegroundColor $color
|
||||
@@ -148,20 +162,61 @@ $ErrorActionPreference = 'Stop'
|
||||
|
||||
$GhcupBasePrefixEnv = [System.Environment]::GetEnvironmentVariable('GHCUP_INSTALL_BASE_PREFIX', 'user')
|
||||
|
||||
if ($GhcupBasePrefixEnv) {
|
||||
$defaultGhcupBasePrefix = $GhcupBasePrefixEnv
|
||||
} else {
|
||||
$defaultGhcupBasePrefix = 'C:\'
|
||||
if (Get-Command -Name 'chocolatey.exe' -ErrorAction SilentlyContinue) {
|
||||
if (!($Silent)) {
|
||||
Print-Msg -color Magenta -msg (@'
|
||||
Chocolatey was detected on your system. It is capable of installing the Haskell toolchain as well.
|
||||
If you want to rather use that instead of ghcup, abort the installation and run the following at an
|
||||
elevated command prompt:
|
||||
choco install haskell-dev
|
||||
refreshenv
|
||||
|
||||
'@)
|
||||
$decision = $Host.UI.PromptForChoice(''
|
||||
, 'Continue with GHCup installation?'
|
||||
, [System.Management.Automation.Host.ChoiceDescription[]] @('&Continue'
|
||||
'&Abort'), 0)
|
||||
if ($decision -eq 1) {
|
||||
Exit 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($GhcupBasePrefixEnv) {
|
||||
$defaultGhcupBasePrefix = $GhcupBasePrefixEnv
|
||||
} elseif (!($InstallDir)) {
|
||||
$partitions = Get-CimInstance win32_logicaldisk
|
||||
$defaultGhcupBasePrefix = $null
|
||||
foreach ($p in $partitions){
|
||||
try {
|
||||
if ($p."FreeSpace" -lt 5368709120) { # at least 5 GB are needed
|
||||
throw ("Not enough free space on {0}" -f $p."DeviceId")
|
||||
}
|
||||
$null = New-Item -Path ('{0}\' -f $p."DeviceId") -Name "ghcup.test" -ItemType "directory" -Force
|
||||
$defaultGhcupBasePrefix = ('{0}\' -f $p."DeviceId")
|
||||
Remove-Item -LiteralPath ('{0}\ghcup.test' -f $p."DeviceId")
|
||||
break
|
||||
} catch {
|
||||
Print-Msg -color Yellow -msg ("{0} not writable or not enough disk space, trying next device" -f $p."DeviceId")
|
||||
}
|
||||
}
|
||||
if ($defaultGhcupBasePrefix) {
|
||||
Print-Msg -color Green -msg ("Picked {0} as default Install prefix!" -f $defaultGhcupBasePrefix)
|
||||
} else {
|
||||
Print-Msg -color Red -msg "Couldn't find a writable partition with at least 5GB free disk space!"
|
||||
Exit 1
|
||||
}
|
||||
}
|
||||
|
||||
# ask for base install prefix
|
||||
if ($Silent -and !($InstallDir)) {
|
||||
$GhcupBasePrefix = $defaultGhcupBasePrefix
|
||||
} elseif ($InstallDir) {
|
||||
if (!(Test-Path -LiteralPath ('{0}' -f $InstallDir) -IsValid)) {
|
||||
Print-Msg -color Red -msg "Not a valid directory!"
|
||||
Print-Msg -color Red -msg "Not a valid directory! (InstallDir)"
|
||||
Exit 1
|
||||
} elseif (!(Split-Path -IsAbsolute -Path "$InstallDir")) {
|
||||
Print-Msg -color Red -msg "Non-absolute Path specified!"
|
||||
Print-Msg -color Red -msg "Non-absolute Path specified! (InstallDir)"
|
||||
Exit 1
|
||||
} else {
|
||||
$GhcupBasePrefix = $InstallDir
|
||||
@@ -192,13 +247,29 @@ $null = [Environment]::SetEnvironmentVariable("GHCUP_INSTALL_BASE_PREFIX", $Ghcu
|
||||
|
||||
|
||||
$GhcupDir = ('{0}\ghcup' -f $GhcupBasePrefix)
|
||||
$MsysDir = ('{0}\msys64' -f $GhcupDir)
|
||||
if ($ExistingMsys2Dir) {
|
||||
if (!(Test-Path -LiteralPath ('{0}' -f $ExistingMsys2Dir) -IsValid)) {
|
||||
Print-Msg -color Red -msg "Not a valid directory! (ExistingMsys2Dir)"
|
||||
Exit 1
|
||||
} elseif (!(Split-Path -IsAbsolute -Path "$ExistingMsys2Dir")) {
|
||||
Print-Msg -color Red -msg "Non-absolute Path specified! (ExistingMsys2Dir)"
|
||||
Exit 1
|
||||
} else {
|
||||
$MsysDir = $ExistingMsys2Dir
|
||||
}
|
||||
} else {
|
||||
$MsysDir = ('{0}\msys64' -f $GhcupDir)
|
||||
}
|
||||
|
||||
$Bash = ('{0}\usr\bin\bash' -f $MsysDir)
|
||||
$BootstrapUrl = 'https://www.haskell.org/ghcup/sh/bootstrap-haskell'
|
||||
if (!($BootstrapUrl)) {
|
||||
$BootstrapUrl = 'https://www.haskell.org/ghcup/sh/bootstrap-haskell'
|
||||
}
|
||||
$GhcupMsys2 = [System.Environment]::GetEnvironmentVariable('GHCUP_MSYS2', 'user')
|
||||
|
||||
Print-Msg -msg 'Preparing for GHCup installation...'
|
||||
|
||||
# ask what to do in case ghcup is already installed
|
||||
if (Test-Path -LiteralPath ('{0}' -f $GhcupDir)) {
|
||||
Print-Msg -msg ('GHCup already installed at ''{0}''...' -f $GhcupDir)
|
||||
if ($Overwrite) {
|
||||
@@ -228,8 +299,73 @@ if (Test-Path -LiteralPath ('{0}' -f $GhcupDir)) {
|
||||
$null = New-Item -Path ('{0}' -f $GhcupDir) -ItemType 'directory' -ErrorAction SilentlyContinue
|
||||
$null = New-Item -Path ('{0}' -f $GhcupDir) -Name 'bin' -ItemType 'directory' -ErrorAction SilentlyContinue
|
||||
|
||||
Print-Msg -msg 'First checking for Msys2...'
|
||||
# ask for cabal dir destination
|
||||
if ($CabalDir) {
|
||||
$CabDirEnv = $CabalDir
|
||||
if (!($CabDirEnv)) {
|
||||
Print-Msg -color Red -msg "No directory specified!"
|
||||
Exit 1
|
||||
} elseif (!(Split-Path -IsAbsolute -Path "$CabDirEnv")) {
|
||||
Print-Msg -color Red -msg "Invalid/Non-absolute Path specified"
|
||||
Exit 1
|
||||
}
|
||||
} elseif (!($Silent)) {
|
||||
while ($true) {
|
||||
|
||||
$defaultCabalDir = ('{0}\cabal' -f $GhcupBasePrefix)
|
||||
Print-Msg -color Magenta -msg ('Specify Cabal directory (this is where haskell packages end up){1}Press enter to accept the default [{0}]:' -f $defaultCabalDir, "`n")
|
||||
$CabalDirPrompt = Read-Host
|
||||
$CabDirEnv = ($defaultCabalDir,$CabalDirPrompt)[[bool]$CabalDirPrompt]
|
||||
|
||||
if (!($CabDirEnv)) {
|
||||
Print-Msg -color Red -msg "No directory specified!"
|
||||
} elseif (!(Split-Path -IsAbsolute -Path "$CabDirEnv")) {
|
||||
Print-Msg -color Red -msg "Invalid/Non-absolute Path specified"
|
||||
} else {
|
||||
Break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$CabDirEnv = ('{0}\cabal' -f $GhcupBasePrefix)
|
||||
}
|
||||
|
||||
# ask whether to install HLS
|
||||
if (!($InstallHLS)) {
|
||||
if (!($Silent)) {
|
||||
$HLSdecision = $Host.UI.PromptForChoice('Install HLS'
|
||||
, 'Do you want to install the haskell-language-server (HLS) for development purposes as well?'
|
||||
, [System.Management.Automation.Host.ChoiceDescription[]] @('&Yes'
|
||||
'&No'
|
||||
'&Abort'), 1)
|
||||
|
||||
if ($HLSdecision -eq 0) {
|
||||
$InstallHLS = $true
|
||||
} elseif ($HLSdecision -eq 2) {
|
||||
Exit 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ask whether to install stack
|
||||
if (!($InstallStack)) {
|
||||
if (!($Silent)) {
|
||||
$StackDecision = $Host.UI.PromptForChoice('Install stack'
|
||||
, 'Do you want to install stack as well?'
|
||||
, [System.Management.Automation.Host.ChoiceDescription[]] @('&Yes'
|
||||
'&No'
|
||||
'&Abort'), 1)
|
||||
|
||||
if ($StackDecision -eq 0) {
|
||||
$InstallStack = $true
|
||||
} elseif ($StackDecision -eq 2) {
|
||||
Exit 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# mingw foo
|
||||
Print-Msg -msg 'First checking for Msys2...'
|
||||
if (!(Test-Path -Path ('{0}' -f $MsysDir))) {
|
||||
if ($Silent) {
|
||||
$msys2Decision = 0
|
||||
@@ -241,7 +377,10 @@ if (!(Test-Path -Path ('{0}' -f $MsysDir))) {
|
||||
}
|
||||
|
||||
if ($msys2Decision -eq 0) {
|
||||
Print-Msg -msg ('...Msys2 doesn''t exist, installing into {0} ...this may take a while' -f $MsysDir)
|
||||
Print-Msg -msg ('...Msys2 doesn''t exist, installing into {0}' -f $MsysDir)
|
||||
|
||||
Print-Msg -msg 'Starting installation in 5 seconds, this may take a while...'
|
||||
Start-Sleep -s 5
|
||||
|
||||
# Download the archive
|
||||
Print-Msg -msg 'Downloading Msys2 archive...'
|
||||
@@ -268,32 +407,21 @@ if (!(Test-Path -Path ('{0}' -f $MsysDir))) {
|
||||
Print-Msg -msg 'Upgrading full system twice...'
|
||||
Exec "$Bash" '-lc' 'pacman --noconfirm -Syuu'
|
||||
|
||||
if ($Quick) {
|
||||
$ghcBuildDeps = $Quick
|
||||
} elseif (!($Silent)) {
|
||||
$ghcBuildDeps = $Host.UI.PromptForChoice('Install Dependencies'
|
||||
, 'Install a standard set of mingw64 packages to be able to build various haskell packages requiring unix libraries? (recommended, however this might take a while... if you skip this, you might have to do it manually later)'
|
||||
, [System.Management.Automation.Host.ChoiceDescription[]] @('&Yes'
|
||||
'&No'), 0)
|
||||
} else {
|
||||
$ghcBuildDeps = 0
|
||||
}
|
||||
if ($ghcBuildDeps -eq 0) {
|
||||
Print-Msg -msg 'Installing Dependencies...'
|
||||
Exec "$Bash" '-lc' 'pacman --noconfirm -S --needed git tar curl wget base-devel gettext binutils autoconf make libtool automake pkgconf python p7zip patch unzip'
|
||||
}
|
||||
Print-Msg -msg 'Installing Dependencies...'
|
||||
Exec "$Bash" '-lc' 'pacman --noconfirm -S --needed curl autoconf mingw-w64-x86_64-pkgconf'
|
||||
|
||||
Print-Msg -msg 'Updating SSL root certificate authorities...'
|
||||
Exec "$Bash" '-lc' 'pacman --noconfirm -S ca-certificates'
|
||||
|
||||
Print-Msg -msg 'Setting default home directory...'
|
||||
Exec "$Bash" '-lc' "sed -i -e 's/db_home:.*$/db_home: windows/' /etc/nsswitch.conf"
|
||||
|
||||
} elseif ($msys2Decision -eq 1) {
|
||||
Print-Msg -color Yellow -msg 'Skipping MSys2 installation.'
|
||||
while ($true) {
|
||||
if ($GhcupMsys2) {
|
||||
$defaultMsys2Dir = $GhcupMsys2
|
||||
Print-Msg -color Magenta -msg ('Input existing MSys2 toolchain directory. Press enter to accept the default [{0}]:' -f $defaultMsys2Dir)
|
||||
Print-Msg -color Magenta -msg ('Input existing MSys2 toolchain directory.{1}Press enter to accept the default [{0}]:' -f $defaultMsys2Dir, "`n")
|
||||
$MsysDirPrompt = Read-Host
|
||||
$MsysDir = ($defaultMsys2Dir,$MsysDirPrompt)[[bool]$MsysDirPrompt]
|
||||
} else {
|
||||
@@ -316,43 +444,85 @@ if (!(Test-Path -Path ('{0}' -f $MsysDir))) {
|
||||
}
|
||||
} else {
|
||||
Print-Msg -msg ('...Msys2 found in {0} ...skipping Msys2 installation.' -f $MsysDir)
|
||||
|
||||
Print-Msg -msg 'Starting installation in 5 seconds, this may take a while...'
|
||||
Start-Sleep -s 5
|
||||
}
|
||||
|
||||
Print-Msg -msg 'Creating shortcuts...'
|
||||
Create-Shortcut -SourceExe ('{0}\msys2_shell.cmd' -f $MsysDir) -ArgumentsToSourceExe '-mingw64' -DestinationPath ('{0}\Desktop\Mingw haskell shell.lnk' -f $HOME)
|
||||
Create-Shortcut -SourceExe 'https://www.msys2.org/docs/package-management' -ArgumentsToSourceExe '' -DestinationPath ('{0}\Desktop\Mingw package management docs.url' -f $HOME)
|
||||
$uninstallShortCut = @'
|
||||
$decision = $Host.UI.PromptForChoice('Uninstall Haskell'
|
||||
, 'Do you want to uninstall all of the haskell toolchain, including GHC, Cabal, Stack and GHCup itself?'
|
||||
, [System.Management.Automation.Host.ChoiceDescription[]] @('&Uninstall'
|
||||
'&Abort'), 0)
|
||||
|
||||
if ($decision -eq 1) {
|
||||
Exit 0
|
||||
}
|
||||
|
||||
Write-Host 'Removing ghcup toolchain' -ForegroundColor Green
|
||||
ghcup nuke
|
||||
|
||||
Write-Host 'Unsetting GHCUP_INSTALL_BASE_PREFIX' -ForegroundColor Green
|
||||
[Environment]::SetEnvironmentVariable('GHCUP_INSTALL_BASE_PREFIX', $null, [System.EnvironmentVariableTarget]::User)
|
||||
|
||||
$ghcupMsys2 = [System.Environment]::GetEnvironmentVariable('GHCUP_MSYS2', 'user')
|
||||
$GhcupBasePrefixEnv = [System.Environment]::GetEnvironmentVariable('GHCUP_INSTALL_BASE_PREFIX', 'user')
|
||||
|
||||
if ($ghcupMsys2) {
|
||||
$msys2Dir = [IO.Path]::GetFullPath($ghcupMsys2)
|
||||
$baseDir = [IO.Path]::GetFullPath('{0}\ghcup' -f $GhcupBasePrefixEnv)
|
||||
|
||||
if ($msys2Dir.StartsWith($baseDir)) {
|
||||
Write-Host 'Unsetting GHCUP_MSYS2' -ForegroundColor Green
|
||||
[Environment]::SetEnvironmentVariable('GHCUP_MSYS2', $null, [System.EnvironmentVariableTarget]::User)
|
||||
} else {
|
||||
Write-Host ('GHCUP_MSYS2 env variable is set to a non-standard location {0}. Environment variable not unset. Uninstall manually.' -f $msys2Dir) -ForegroundColor Magenta
|
||||
}
|
||||
} else {
|
||||
Write-Host 'Unsetting GHCUP_MSYS2' -ForegroundColor Green
|
||||
[Environment]::SetEnvironmentVariable('GHCUP_MSYS2', $null, [System.EnvironmentVariableTarget]::User)
|
||||
}
|
||||
|
||||
Write-Host 'Removing ghcup from PATH env var' -ForegroundColor Green
|
||||
$path = [System.Environment]::GetEnvironmentVariable(
|
||||
'PATH',
|
||||
'user'
|
||||
)
|
||||
$path = ($path.Split(';') | Where-Object { $_ -ne ('{0}\bin' -f $baseDir) }) -join ';'
|
||||
[System.Environment]::SetEnvironmentVariable(
|
||||
'PATH',
|
||||
$path,
|
||||
'user'
|
||||
)
|
||||
|
||||
Write-Host 'Removing desktop files' -ForegroundColor Green
|
||||
$DesktopDir = [Environment]::GetFolderPath("Desktop")
|
||||
Remove-Item -LiteralPath ('{0}\Install GHC dev dependencies.lnk' -f $DesktopDir) -Force
|
||||
Remove-Item -LiteralPath ('{0}\Mingw haskell shell.lnk' -f $DesktopDir) -Force
|
||||
Remove-Item -LiteralPath ('{0}\Mingw package management docs.url' -f $DesktopDir) -Force
|
||||
|
||||
Write-Host ('CABAL_DIR env variable is still set to {0} and will be used by cabal regardless of ghcup. You may want to uninstall this manually.' -f [System.Environment]::GetEnvironmentVariable('CABAL_DIR', 'user')) -ForegroundColor Magenta
|
||||
Write-Host 'You may remove this script now.' -ForegroundColor Magenta
|
||||
|
||||
if ($Host.Name -eq "ConsoleHost")
|
||||
{
|
||||
Write-Host "Press any key to continue..."
|
||||
$Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyUp") > $null
|
||||
}
|
||||
'@
|
||||
|
||||
$DesktopDir = [Environment]::GetFolderPath("Desktop")
|
||||
$GhcInstArgs = '-mingw64 -mintty -c "pacman --noconfirm -S --needed base-devel gettext autoconf make libtool automake python p7zip patch unzip"'
|
||||
Create-Shortcut -SourceExe ('{0}\msys2_shell.cmd' -f $MsysDir) -ArgumentsToSourceExe $GhcInstArgs -DestinationPath ('{0}\Install GHC dev dependencies.lnk' -f $DesktopDir)
|
||||
Create-Shortcut -SourceExe ('{0}\msys2_shell.cmd' -f $MsysDir) -ArgumentsToSourceExe '-mingw64' -DestinationPath ('{0}\Mingw haskell shell.lnk' -f $DesktopDir)
|
||||
Create-Shortcut -SourceExe 'https://www.msys2.org/docs/package-management' -ArgumentsToSourceExe '' -DestinationPath ('{0}\Mingw package management docs.url' -f $DesktopDir)
|
||||
$null = New-Item -Path $DesktopDir -Name "Uninstall Haskell.ps1" -ItemType "file" -Force -Value $uninstallShortCut
|
||||
|
||||
Print-Msg -msg ('Adding {0}\bin to Users Path...' -f $GhcupDir)
|
||||
Add-EnvPath -Path ('{0}\bin' -f ([System.IO.Path]::GetFullPath("$GhcupDir"))) -Container 'User'
|
||||
|
||||
if ($CabalDir) {
|
||||
$CabDirEnv = $CabalDir
|
||||
if (!($CabDirEnv)) {
|
||||
Print-Msg -color Red -msg "No directory specified!"
|
||||
Exit 1
|
||||
} elseif (!(Split-Path -IsAbsolute -Path "$CabDirEnv")) {
|
||||
Print-Msg -color Red -msg "Invalid/Non-absolute Path specified"
|
||||
Exit 1
|
||||
}
|
||||
} elseif (!($Silent)) {
|
||||
while ($true) {
|
||||
|
||||
$defaultCabalDir = ('{0}\cabal' -f $GhcupBasePrefix)
|
||||
Print-Msg -color Magenta -msg ('Specify Cabal directory (this is where haskell packages end up). Press enter to accept the default [{0}]:' -f $defaultCabalDir)
|
||||
$CabalDirPrompt = Read-Host
|
||||
$CabDirEnv = ($defaultCabalDir,$CabalDirPrompt)[[bool]$CabalDirPrompt]
|
||||
|
||||
if (!($CabDirEnv)) {
|
||||
Print-Msg -color Red -msg "No directory specified!"
|
||||
} elseif (!(Split-Path -IsAbsolute -Path "$CabDirEnv")) {
|
||||
Print-Msg -color Red -msg "Invalid/Non-absolute Path specified"
|
||||
} else {
|
||||
Break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$CabDirEnv = ('{0}\cabal' -f $GhcupBasePrefix)
|
||||
}
|
||||
|
||||
$CabalDirFull = [System.IO.Path]::GetFullPath("$CabDirEnv")
|
||||
Print-Msg -msg ('Setting CABAL_DIR to ''{0}''' -f $CabalDirFull)
|
||||
@@ -362,16 +532,29 @@ Print-Msg -msg 'Starting GHCup installer...'
|
||||
|
||||
$Msys2Shell = ('{0}\msys2_shell.cmd' -f $MsysDir)
|
||||
|
||||
if ($Silent) {
|
||||
$SilentExport = 'export BOOTSTRAP_HASKELL_NONINTERACTIVE=1 ;'
|
||||
} else {
|
||||
$SilentExport = ''
|
||||
# The bootstrap script is always silent, since we ask relevant questions here
|
||||
$SilentExport = 'export BOOTSTRAP_HASKELL_NONINTERACTIVE=1 ;'
|
||||
|
||||
if ($InstallStack) {
|
||||
$StackInstallExport = 'export BOOTSTRAP_HASKELL_INSTALL_STACK=1 ;'
|
||||
}
|
||||
|
||||
if ((Get-Process -ID $PID).ProcessName.StartsWith("bootstrap-haskell")) {
|
||||
Exec "$Bash" '-lc' ('{4} [ -n ''{1}'' ] && export GHCUP_MSYS2=$(cygpath -m ''{1}'') ; [ -n ''{2}'' ] && export GHCUP_INSTALL_BASE_PREFIX=$(cygpath -m ''{2}/'') ; export PATH=$(cygpath -u ''{3}/bin''):$PATH ; export CABAL_DIR=''{5}'' ; curl --proto ''=https'' --tlsv1.2 -sSf {0} | bash' -f $BootstrapUrl, $MsysDir, $GhcupBasePrefix, $GhcupDir, $SilentExport, $CabalDirFull)
|
||||
if ($InstallHLS) {
|
||||
$HLSInstallExport = 'export BOOTSTRAP_HASKELL_INSTALL_HLS=1 ;'
|
||||
}
|
||||
|
||||
if (!($NoAdjustCabalConfig)) {
|
||||
$AdjustCabalConfigExport = 'export BOOTSTRAP_HASKELL_ADJUST_CABAL_CONFIG=1 ;'
|
||||
}
|
||||
|
||||
if ($Minimal) {
|
||||
$MinimalExport = 'export BOOTSTRAP_HASKELL_MINIMAL=1 ;'
|
||||
}
|
||||
|
||||
if ((Get-Process -ID $PID).ProcessName.StartsWith("bootstrap-haskell") -Or $InBash) {
|
||||
Exec "$Bash" '-lc' ('{4} {6} {7} {8} {9} [ -n ''{1}'' ] && export GHCUP_MSYS2=$(cygpath -m ''{1}'') ; [ -n ''{2}'' ] && export GHCUP_INSTALL_BASE_PREFIX=$(cygpath -m ''{2}/'') ; export PATH=$(cygpath -u ''{3}/bin''):$PATH ; export CABAL_DIR=''{5}'' ; [[ ''{0}'' = https* ]] && curl --proto ''=https'' --tlsv1.2 -sSf {0} | bash || cat $(cygpath -m ''{0}'') | bash' -f $BootstrapUrl, $MsysDir, $GhcupBasePrefix, $GhcupDir, $SilentExport, $CabalDirFull, $StackInstallExport, $HLSInstallExport, $AdjustCabalConfigExport, $MinimalExport)
|
||||
} else {
|
||||
Exec "$Msys2Shell" '-mingw64' '-mintty' '-c' ('{4} [ -n ''{1}'' ] && export GHCUP_MSYS2=$(cygpath -m ''{1}'') ; [ -n ''{2}'' ] && export GHCUP_INSTALL_BASE_PREFIX=$(cygpath -m ''{2}/'') ; export PATH=$(cygpath -u ''{3}/bin''):$PATH ; export CABAL_DIR=''{5}'' ; trap ''echo Press any key to exit && read -n 1 && exit'' 2 ; curl --proto =https --tlsv1.2 -sSf -k {0} | bash ; echo ''Press any key to exit'' && read -n 1' -f $BootstrapUrl, $MsysDir, $GhcupBasePrefix, $GhcupDir, $SilentExport, $CabalDirFull)
|
||||
Exec "$Msys2Shell" '-mingw64' '-mintty' '-c' ('{4} {6} {7} {8} {9} [ -n ''{1}'' ] && export GHCUP_MSYS2=$(cygpath -m ''{1}'') ; [ -n ''{2}'' ] && export GHCUP_INSTALL_BASE_PREFIX=$(cygpath -m ''{2}/'') ; export PATH=$(cygpath -u ''{3}/bin''):$PATH ; export CABAL_DIR=''{5}'' ; trap ''echo Press any key to exit && read -n 1 && exit'' 2 ; [[ ''{0}'' = https* ]] && curl --proto ''=https'' --tlsv1.2 -sSf {0} | bash || cat $(cygpath -m ''{0}'') | bash ; echo ''Press any key to exit'' && read -n 1' -f $BootstrapUrl, $MsysDir, $GhcupBasePrefix, $GhcupDir, $SilentExport, $CabalDirFull, $StackInstallExport, $HLSInstallExport, $AdjustCabalConfigExport, $MinimalExport)
|
||||
}
|
||||
|
||||
|
||||
@@ -399,3 +582,9 @@ if ((Get-Process -ID $PID).ProcessName.StartsWith("bootstrap-haskell")) {
|
||||
# E5VhEwLBnwzWrvLKtdEclhgUCo5Tq87QMXVdgX4aRmunl4ZE+Q==
|
||||
# SIG # End signature block
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
4
scripts/dev/modgraph.sh
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
|
||||
graphmod | tred | dot -Tsvg -Gsize=10,9\! > docs/modules_small.svg
|
||||
graphmod | tred | dot -Tsvg -Gsize=15,9\! > docs/modules_wide.svg
|
||||