Compare commits
1222 Commits
a93aaf9a5f
...
rename
| Author | SHA1 | Date | |
|---|---|---|---|
|
e9db8f9895
|
|||
|
7f542646dd
|
|||
|
34910f853b
|
|||
|
c05876cc60
|
|||
|
b9c4c9a0b7
|
|||
|
6697e804ee
|
|||
|
2c57def8f1
|
|||
|
62b16e957b
|
|||
|
18d7bdd85c
|
|||
|
190b5dedba
|
|||
|
886e45f788
|
|||
|
360daf2a09
|
|||
|
7bb67dd4c6
|
|||
|
72c4ea70c4
|
|||
|
0ae42dd71e
|
|||
|
1df1e7eb98
|
|||
|
9592021c48
|
|||
|
9a9c3b340e
|
|||
|
abd64cb3fa
|
|||
|
b366a50af1
|
|||
|
e4b9eeefc6
|
|||
|
4d7a8557eb
|
|||
|
c23357df81
|
|||
|
f728d5aa23
|
|||
|
ac59563adf
|
|||
|
b2d2996077
|
|||
|
df2337abf9
|
|||
|
d68ab3b657
|
|||
|
c10821c332
|
|||
|
219cba5fc7
|
|||
|
8e3c74958a
|
|||
|
ed08e0b166
|
|||
|
168f2e6d16
|
|||
|
4574f3aa4f
|
|||
|
2a11e85a95
|
|||
|
69df100b18
|
|||
|
920b027a32
|
|||
|
9f8c9c228d
|
|||
|
9d8fdfe090
|
|||
|
01956d694d
|
|||
|
09d2a1e815
|
|||
|
ccfaedb7ad
|
|||
|
356a69f575
|
|||
|
752efad4bf
|
|||
|
05adb224e9
|
|||
|
bf1a3fbbe8
|
|||
|
8b14b22b12
|
|||
|
b8b47a45ba
|
|||
|
2b9e51cc31
|
|||
|
d9fa0cdb45
|
|||
|
288af4abc6
|
|||
|
e77b2c39f9
|
|||
|
87e5d526cb
|
|||
|
2b33dd4871
|
|||
|
62b68cfa3e
|
|||
|
|
af14227862 | ||
|
|
eb0e9df6ab | ||
|
f1cc2ebf20
|
|||
|
74f14c68a4
|
|||
|
5dc5c2094e
|
|||
|
940b5842b6
|
|||
|
d19602d06f
|
|||
|
ae85f7152e
|
|||
|
|
2cb40af62f
|
||
|
|
569b46f0c4
|
||
|
|
6b0c915077
|
||
|
|
237ed173ee
|
||
|
c0c6cd4fb3
|
|||
|
1f100623a7
|
|||
|
f137d5cc21
|
|||
|
aea8af513b
|
|||
|
c846e52acb
|
|||
|
19e7f0df34
|
|||
|
cd218ce025
|
|||
|
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
|
|||
|
a608a105e3
|
|||
|
2e3e413f6c
|
|||
|
dfb6c09133
|
|||
|
9636276c17
|
|||
|
41783ff027
|
|||
|
08b0ecd057
|
|||
|
7e31798446
|
|||
|
534afa6e8d
|
|||
|
b56c44a210
|
|||
|
ef0c94fddd
|
|||
|
f14c281841
|
|||
|
b40cefee35
|
|||
|
ff32ccfb50
|
|||
|
581108ab65
|
|||
|
54e8e3efb0
|
|||
|
4dcc63606e
|
|||
|
a396b6044d
|
|||
|
94e5d2e19f
|
|||
|
a0976eee70
|
|||
|
61494d8c4b
|
|||
|
2b34c2dd69
|
|||
|
afc30b87dd
|
|||
|
|
ed0a63eb0c | ||
|
9ba590dd90
|
|||
|
d4bffd2c4a
|
|||
|
650f0a3e4e
|
|||
|
fd6ccf8f0a
|
|||
|
d9fe4b8723
|
|||
|
da2e7e0411
|
|||
|
79d6a50e44
|
|||
|
a13a5e5d20
|
|||
|
82743dda2b
|
|||
|
|
6f80dd1fcc | ||
|
1325dce493
|
|||
|
ac21c19b7e
|
|||
|
2b4088d068
|
|||
|
d86dc9b1d7
|
|||
|
9982311c87
|
|||
|
40c88d0b66
|
|||
|
e0ee1c2f94
|
|||
|
b4fa2780eb
|
|||
|
df86183e97
|
|||
|
f7868dc646
|
|||
|
e742be7693
|
|||
|
924bc8698d
|
|||
|
5214c35b20
|
|||
|
700e04535a
|
|||
|
fedc0bbef6
|
|||
|
468fc5ade9
|
|||
|
2c077db36b
|
|||
|
f80638bba4
|
|||
|
860aa0dafd
|
|||
|
27510b3b51
|
|||
|
96bcbbeeec
|
|||
|
8a632eb3b4
|
|||
|
aa992c0e5d
|
|||
|
810870e3a5
|
|||
|
d584e7b21b
|
|||
|
e93ac62c81
|
|||
|
0d7d6c8382
|
|||
|
5cd9ce8835
|
|||
|
443522d526
|
|||
|
9061e60518
|
|||
|
d65ab434b2
|
|||
|
cff592db82
|
|||
|
97029e8102
|
|||
|
|
828fd9eb10 | ||
|
03800d3b74
|
|||
|
a47304e599
|
|||
|
7b050e9fe2
|
|||
|
687a1d0c88
|
|||
|
e09e3c264d
|
|||
|
b56431b4e3
|
|||
|
70ad50010d
|
|||
|
|
ca3a249bea | ||
|
|
4337cdc38d | ||
|
9f92e0bc86
|
|||
|
98751cf8fb
|
|||
|
2f62067d96
|
|||
|
2cb1554244
|
|||
|
6f3c143228
|
|||
|
9793fc6888
|
|||
|
043cab08ae
|
|||
|
b7c83780da
|
|||
|
cff11135ff
|
|||
|
b94a4123eb
|
|||
|
8ef1c8b5d4
|
|||
|
132d331e7c
|
|||
|
734916728c
|
|||
|
5f6ed1292d
|
|||
|
a7dc03af50
|
|||
|
5a86a28d67
|
|||
|
a905c6322c
|
|||
|
49ccadd470
|
|||
|
9f0ac0ee19
|
|||
|
7e0f839ff8
|
|||
|
1e9ee260e7
|
|||
|
0b7d447aaf
|
|||
|
16a9336d31
|
|||
|
7d13836fea
|
|||
|
b645c4d57e
|
|||
|
5db43cd908
|
|||
|
93cd421ca3
|
|||
|
ec7130dac6
|
|||
|
f2b8cc530c
|
|||
|
de765088d1
|
|||
|
|
e11188aa99 | ||
|
0c6699c3c6
|
|||
|
c5858be6b8
|
|||
|
ffe00c7b1f
|
|||
|
43114959fd
|
|||
|
b1c3ffd729
|
|||
|
4f1a9e95a2
|
|||
|
f6a4f55384
|
|||
|
672b179446
|
|||
|
3111387e5a
|
|||
|
f8fda269f1
|
|||
|
fbac593739
|
|||
|
c80e54dff5
|
|||
|
4a86b2479e
|
|||
|
7bb2552d0f
|
|||
|
ad21640cd9
|
|||
|
e4aad4e645
|
|||
|
adf44ba141
|
|||
|
8707b194fd
|
|||
|
77bb7c4aba
|
|||
|
7383fdd0c0
|
|||
|
f4201d946a
|
|||
|
d5b5f1fddd
|
|||
| 910d660732 | |||
| ab4ad3a1bb | |||
| 13b27101f1 | |||
| 44b5d0dcff | |||
| df54b3711f | |||
| 197288453f | |||
| 00d5691a13 | |||
| 561b6684ce | |||
| a13bb3154d | |||
| fd9d3faf9f | |||
| f6cc467e95 | |||
| ef978c1230 | |||
| 52af598473 | |||
| 2acacd46c2 | |||
| 4b2f9ddb40 | |||
| 0d3dc4eba2 | |||
| 824faa8091 | |||
| d10cdfdf57 | |||
| 5e911793ce | |||
| 8c87c9aeb7 | |||
| 9da5998a5c | |||
| 08943dadca | |||
| 7fac7226c5 | |||
| 9686c8ebf9 | |||
| 4bf96d0ec9 | |||
| 34add82bee | |||
| f46e7e8c4b | |||
| 3baf254251 | |||
| 10ca9ea827 | |||
| 4a50c8ecb7 | |||
| 47d9766c78 | |||
| 45ab69960f | |||
| d3505d4ee6 | |||
| 9297d1a2f8 | |||
| 56feb7c09e | |||
| bede4b8712 | |||
| 95c1c55f22 | |||
| f547a6eb68 | |||
|
|
453a29fdf7 | ||
|
|
1a5f0259f4 | ||
|
|
d6fa61e223 | ||
| eab82b5d63 | |||
| c455b521a9 | |||
| b4f9e12293 | |||
| bbd353ea3a | |||
| 4189c5de69 | |||
| dee3218723 | |||
| 3c803a9f58 | |||
| a9b0c0fbc9 | |||
| 38b6c918f9 | |||
| 6e584c96c4 | |||
| 20338f7d14 | |||
| 1a995a5d63 | |||
| f964382175 | |||
| 0c7f60fae6 | |||
| 413e63d1ca | |||
| 8b000f4e48 | |||
| b0522507be | |||
| d4bcf7021e | |||
| 48cf0b1f67 | |||
| d82e189c01 | |||
| e5a60d1b9a | |||
| ff067351cb | |||
| 345712a617 | |||
| 118dac6907 | |||
| 5ca40caf81 | |||
| d858187fd4 | |||
| bd65517df1 | |||
| b1acad6c95 | |||
| a8333281ac | |||
| 2fdb08ac00 | |||
|
|
bd4e5a2314 | ||
| 34ed317b6b | |||
|
|
14661502ab | ||
| 097754ffdf | |||
|
|
f26ec6d295 | ||
| 858d430845 | |||
| 5134eccbf8 | |||
| 28b4737758 | |||
|
|
5c43ff4c9e | ||
|
|
53db68e39f | ||
| 9e628e34dd | |||
|
|
62d5d53232 | ||
|
|
56569a0698 | ||
|
|
ef44f818d0 | ||
|
|
8944ed6e36 | ||
| 51805b27aa | |||
| 0ec64510b3 | |||
| 20152443da | |||
|
|
7c8929fe9f | ||
| 5617516c93 | |||
| f6fe08367d | |||
| a5f02133e2 | |||
|
|
8ed9b4432d | ||
|
|
db1d05e8ad | ||
| eae58137c8 | |||
| b0f90c096f | |||
| e8361c564a | |||
|
|
54db9c9a92 | ||
|
|
73db341dc8 | ||
| 5fd30b412b | |||
|
|
bbe2e87640 | ||
|
|
67f59f6895 | ||
|
|
3e2df2e111 | ||
| 824d2149c6 | |||
|
|
c86dbe043b | ||
|
|
8043ac7f51 | ||
|
|
ead9d31647 | ||
|
|
a08e624309 | ||
| b20371c3ac | |||
| 0589a7cbcc | |||
| cf48961063 | |||
| 6046582b9c | |||
| 82aa6c70ea | |||
| e829bd8235 | |||
| 66f989e691 | |||
| eebb91fbb0 | |||
| 1d3e88bdfe | |||
| fbb03dee7e | |||
|
|
88e5afb70f | ||
| 67eabfd3af | |||
| cd1dd8c29e | |||
| 08ddb591b7 | |||
| 3e841b3c68 | |||
| 53f5a08924 | |||
| d368863c3d | |||
| c76cce5830 | |||
| 4fef93b7b1 | |||
| 241dadbeb5 | |||
| 12459c2544 | |||
| e250d6013f | |||
| 0d41d180d6 | |||
|
|
ef251ce17e | ||
| 956e11c3f8 | |||
| 951b0843b2 | |||
| a4e4080a1b | |||
| 2aa91c5d91 | |||
| 6471b3877f | |||
| 778ee142d5 | |||
| 1140132a25 | |||
| c5c299179d | |||
| 0ce4549eb8 | |||
| 97d568ddd6 | |||
| ea58465240 | |||
| 7afd262b1b | |||
| 34ceaa0823 | |||
| 57c34a07f2 | |||
| 73d1d97f1f | |||
| f7ed1a4bde | |||
| bdd80d0229 | |||
| 0238f70c64 | |||
| 24ff430c45 | |||
| 281fb14d4c | |||
| 03bac93929 | |||
| 1ae0c2a654 | |||
| 8140936bd3 | |||
| 8786acf476 | |||
| c460d4c743 | |||
| 5294adf0d7 | |||
| 00f3fa35fd | |||
| 9c9aa4f9c0 | |||
| e23a187cc4 | |||
| 3e429945dc | |||
| 8be2a8eed7 | |||
| 6b65167581 | |||
| 9d7914e69a | |||
| 6c62884b24 | |||
| 965d2a3ba8 | |||
| 40a1cc98c6 | |||
| 4c2d4ee6bd | |||
| 9276664465 | |||
| a94bcdb92d | |||
| 5da5fabfef | |||
| 05cc55c52d | |||
| 571df1349c | |||
| cbbb75062c | |||
| bb7c4205db | |||
| b2027f1625 | |||
| 65945c87df | |||
| 081582d3e1 | |||
| bf240af518 | |||
| a269131e2d | |||
| 59ece98fdc | |||
| 563924ff26 | |||
| 8ee3f55428 | |||
| 93c17607b5 | |||
| 8b4c239444 | |||
| 8bef17bf59 | |||
| a649146a39 | |||
| 9d6a5313ab | |||
| de09c950d5 | |||
| 47838b1bd9 | |||
| 02b360e2a9 | |||
| c10ab15e0c | |||
| 46f3da1a94 | |||
| 7ec9d90aab | |||
| 326bf510c9 | |||
| ce3d1f4309 | |||
| b31ba883e4 | |||
| e5d1c04616 | |||
| 34ff0ed9cf | |||
| 85bd87d5f3 | |||
| 8b274214af | |||
| 069e3102f4 | |||
| 8623b32721 | |||
| 6342e8edf0 | |||
| bbd8f0c84c | |||
| 873c951d6e | |||
| d9c864d3c5 | |||
| 4280d7109a | |||
| c8855c068f | |||
| 90503061e9 | |||
| 672ebf6426 | |||
| fd76fde23a | |||
| e24c9a3ffe | |||
| 2641d50c21 | |||
| 202f3ea3ba | |||
| 4f09e3ff7e | |||
| 1148219130 | |||
| 4b47800dfb | |||
| e2c4db9132 | |||
| 90af68b211 | |||
| 80603662b4 | |||
| d2c5d4dfd9 | |||
| 6f1b8b4041 | |||
| f63b2bf744 | |||
| 71cb75c170 | |||
| dac64f5718 | |||
| 27b2d2ac7d | |||
| 47142dd376 | |||
| d071a7e51b | |||
| 5c45884f5f | |||
| cafedd73a2 | |||
| 7163b77837 | |||
| 122c54b51e | |||
| b9d7d7d007 | |||
| 9050c9792a | |||
| aac8f760ad | |||
| 7d334c18f5 | |||
| 86b0e4b31b | |||
| af811f3dbc | |||
| d30d2ac8a5 | |||
| 86a4b10de6 | |||
| cfa7049ab9 | |||
| 391676e90a | |||
| 34e4ece8b5 | |||
| cf6443d83f | |||
| 846cf92fa4 | |||
| ab568901f8 | |||
| bfda95c0d6 | |||
| fb1875ee5b | |||
| 185d4f869b | |||
| 2ac8b61aa8 | |||
| 8739cb4656 | |||
| 826900cc41 | |||
| ec6bbdbf06 | |||
| 15a188c501 | |||
| b5440fc7d2 | |||
| 4b21adadf1 | |||
| 78ae77780b | |||
| ccb95bcbee | |||
| 21ac670bbe | |||
| 8b54dee66c | |||
| dad926f3ba | |||
| a298d949b5 | |||
| e1cf11f9d4 | |||
| a046f16308 | |||
| 97cd43792d | |||
| 08693e6d3a | |||
| e2227da8d2 | |||
| 5f20e4c583 | |||
| f82f1a12dd | |||
| 53148fd1c9 | |||
| 8985101b2a | |||
| d1949c8490 | |||
| b7faae1203 | |||
| b6a9d35c3e | |||
| 6cb6c7a448 | |||
| 22a5ad739e | |||
| 14c91bdd78 | |||
| 2c638cd2e2 | |||
| 9e59f484e3 | |||
| ac8419ecb2 | |||
| 3ecdb63063 | |||
| cfe24428fa | |||
| 4c4266dd8c | |||
| e8336bbc8a | |||
| 0f69c73e0e | |||
| e348de8dc4 | |||
| 55a3ba9be2 | |||
| 51b29b81b0 | |||
| 3c2e0334b7 | |||
| 0679626514 | |||
| 5035051135 | |||
| 63c70ee74b | |||
| 2e0bbca2e0 | |||
| b52fa23ca2 | |||
| ba03b78f23 | |||
| 04ef472c15 | |||
| 75cd8f2341 | |||
| f2e26c1800 | |||
| 0f7dd597d2 | |||
| fb0eba9201 | |||
| 3c80929c38 | |||
| b184ee835f | |||
| ef8e3bd940 | |||
| 1a64527e14 | |||
| 30b4d399b9 | |||
| 50424c2801 | |||
| 7e7c357e47 | |||
| 531b82a406 | |||
| 146ac38549 | |||
| c481956b07 | |||
| 8ef19f0825 | |||
| c1e29a8f16 | |||
| c3611eec6a | |||
| 74b58db7d1 | |||
| 9e4763c640 | |||
| abc4278fc8 | |||
| 8c4cde3d14 | |||
| 3824f6417a | |||
|
|
2be1aa2707 | ||
| da94fa5f92 | |||
| 35bf9b5ff2 | |||
| bed2cca8d2 | |||
| 9717a1c00f | |||
| 3ddc719d8a | |||
| 4b89810892 | |||
| b82367838d | |||
| dd7556ba21 | |||
| f4b6bfc594 | |||
| f9251589cd | |||
| 2de549862a | |||
| c502f70f68 | |||
| cbf076740a | |||
| 86c144b285 | |||
| 7ec6e8604c | |||
| de70f4820f | |||
|
|
febe6fcb35 | ||
|
|
3055529d4c | ||
|
|
d276bfb3ec | ||
| 9db0664465 | |||
| e9c727647a | |||
| 55eef8a3d3 | |||
| d07ad3eb26 | |||
|
|
ad53b141c7 | ||
|
|
23c13a07a9 | ||
|
|
a186b07763 | ||
|
|
1ca628aba1 | ||
| 8f4ef48891 | |||
|
|
d852ab3415 | ||
| a1bcc4b51f | |||
| be93a98bd4 | |||
| 85054d9c76 | |||
| 6c95218daf | |||
| ede6299681 | |||
| bf6e94cfb2 | |||
| 378942cbce | |||
| 1207c7b3dd | |||
| 788883df7b | |||
| 5ab1f6c203 | |||
| 175066780b | |||
| a629cf7b9f | |||
| 684130bfa3 | |||
| ee34d85dbc | |||
| d2b280da2d | |||
| a5593a725f | |||
| 5e35a91ef0 | |||
| 4abd10d9c9 | |||
| 0bbac877bd | |||
| f558bd9932 | |||
| 781c28b03c | |||
| a8be2efd85 | |||
| f46700e1cc | |||
| d7a6935a1a | |||
| a1282b2854 | |||
| 34b9ea7d20 | |||
| 0ff7ebb1fd | |||
| f83dcbc430 | |||
| 56e4a6b15f | |||
| ee9b2ec30d | |||
| 640cf1e2c1 | |||
| 56c439d716 | |||
| 1ed6e49a81 | |||
| fad9f83e6a | |||
| 2e28b0d00f | |||
| ed4ff15f96 | |||
| 1d623723a2 | |||
| 931080244f | |||
| 27e2e7f848 | |||
| 8b638c7ecb | |||
| acd370611f | |||
| e1b5a89cee | |||
| 5edebd57d9 | |||
| bcaccaaf31 | |||
| 818a5d2d85 | |||
| 13acce07d4 | |||
| 4ed5e21b7f | |||
| 86aab6bb59 | |||
| 7f5cb64b18 | |||
| 6c12eb16eb | |||
| e637f90fae | |||
| 5b33c3f491 | |||
| 1842ed464f | |||
| 296bbdd561 | |||
| 27ead1be7c | |||
| 5184609dba | |||
| 5d94d0bf75 | |||
| 72bcfa9270 | |||
| fafff9dadd | |||
| e3c20d53a8 | |||
| 8b7dc68491 | |||
| 7742fe08b5 | |||
| a773da037c | |||
| dfeb814dcc | |||
| 0623c7b1b1 | |||
| 62005f83a4 | |||
| eaafd77a7e | |||
| 9d9e415a09 | |||
| 6c1ae585b7 | |||
| 793aad7b6c | |||
| fd7807a66e | |||
| 879bd061dd | |||
| 75632b2cf1 | |||
| b65b9dc5e1 | |||
| 31d70e34e9 | |||
| 84de282655 | |||
| 997dcadf89 | |||
| b2312629ce | |||
| 3d10f964c6 | |||
| 404038edcb | |||
| ea4f9ceab1 | |||
| 5c481ea94e | |||
| 1ccaf4ba91 | |||
| b532511cd5 | |||
| b3105b439c | |||
| 2b6cb5f1a8 | |||
| f4242b10e7 | |||
| ad4d185ead | |||
| b18aafe2c4 | |||
| 340196bf9d | |||
| 883226aa70 | |||
| 0d393612a7 | |||
| 5635f6cc4e | |||
| a7fd36beeb | |||
| baee1d5b85 | |||
| 68df6b8e50 | |||
| ac73090784 | |||
| faf4f3b7ca | |||
| d888d11d59 | |||
| 28a1077833 | |||
| c40b9dbc0b | |||
| 6bbd262818 | |||
| 78d36bce24 | |||
| aedfc19220 | |||
| 2f34fc7bef | |||
| de66b92631 | |||
| fee3984bf7 | |||
| b953c8fd30 | |||
| 24e4c3a19b | |||
| d2efb504b9 | |||
| df9dd0e785 | |||
| 89c9699158 | |||
| 124ddcdfeb | |||
| 5c0a0fc155 | |||
| b11b74d2b4 | |||
| 5ac8f5b651 | |||
| 9032df97cf | |||
| 14e1077ad1 | |||
| b5648bdd6b | |||
| e7cd952970 | |||
| 1455c2c175 | |||
| c106dd3f65 | |||
| f6725fbf5f | |||
| c706a047ea | |||
| 9602db31ab | |||
| c2c47e1b7e | |||
| 34386680cc | |||
| 16a26d9881 | |||
| 3496f24f6e | |||
| 1a5876a074 | |||
| c782bc44de | |||
| f78e7b1cbc | |||
| adec7b2398 | |||
| 958bf698b9 | |||
| 6a79782650 | |||
| 5382fd9aca | |||
| 8a0236a350 | |||
| 3e52def226 | |||
| 5d3c26b509 | |||
| 99941bc2a1 | |||
| 63f290107c | |||
| 31a8316bfa | |||
| 3ff6be5435 | |||
| 0963081fd8 | |||
| af42598a27 | |||
| e6037b9eb5 | |||
| e58e1c1954 | |||
| c7a831a280 | |||
| e77ed1a26c | |||
| c0c70f5c9b | |||
| fee16758de | |||
| f8448cf02b | |||
| 35b6359c1b | |||
| 9c7d17800d | |||
| ee570c024c | |||
| fcb7129251 | |||
| 8a1bd45ffe | |||
| f5a2db6719 | |||
| 2c99070d89 | |||
| 93aac16fc5 | |||
| 775c541895 | |||
| b0eba1a77a | |||
| 8aa2be5898 | |||
| 951a7173ae | |||
| b7f49b1c94 | |||
| dcd6812fb7 | |||
| 167826dfce | |||
| 03ee8915fb |
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.7
|
||||
cabal-version: 3.6.2.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
|
||||
|
||||
16
.gitignore
vendored
@@ -1 +1,17 @@
|
||||
.ghci
|
||||
.vim
|
||||
codex.tags
|
||||
dist-newstyle/
|
||||
cabal.project.local
|
||||
.stack-work/
|
||||
bin/
|
||||
/*.prof
|
||||
/*.ps
|
||||
/*.hp
|
||||
tags
|
||||
TAGS
|
||||
/tmp/
|
||||
.entangled
|
||||
release/
|
||||
releases/
|
||||
site/
|
||||
|
||||
660
.gitlab-ci.yml
Normal file
@@ -0,0 +1,660 @@
|
||||
stages:
|
||||
- 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: 8d0224e6b2a08157649651e69302380b2bd24e11
|
||||
|
||||
# Sequential version number of all cached things.
|
||||
# Bump to invalidate GitLab CI cache.
|
||||
CACHE_REV: 0
|
||||
|
||||
############################################################
|
||||
# CI Step
|
||||
############################################################
|
||||
|
||||
.debian:
|
||||
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"
|
||||
tags:
|
||||
- x86_64-linux
|
||||
variables:
|
||||
OS: "LINUX"
|
||||
ARCH: "64"
|
||||
CABAL_DIR: "$CI_PROJECT_DIR/cabal"
|
||||
|
||||
.alpine:32bit:
|
||||
image: "i386/alpine:3.12"
|
||||
tags:
|
||||
- x86_64-linux
|
||||
variables:
|
||||
OS: "LINUX"
|
||||
ARCH: "32"
|
||||
CABAL_DIR: "$CI_PROJECT_DIR/cabal"
|
||||
|
||||
.linux:armv7:
|
||||
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: "registry.gitlab.haskell.org/ghc/ci-images/aarch64-linux-deb10:$DOCKER_REV"
|
||||
tags:
|
||||
- aarch64-linux
|
||||
variables:
|
||||
OS: "LINUX"
|
||||
ARCH: "ARM64"
|
||||
CABAL_DIR: "$CI_PROJECT_DIR/cabal"
|
||||
|
||||
.darwin:
|
||||
tags:
|
||||
- x86_64-darwin
|
||||
variables:
|
||||
OS: "DARWIN"
|
||||
ARCH: "64"
|
||||
CABAL_DIR: "$CI_PROJECT_DIR/cabal"
|
||||
|
||||
.darwin:aarch64:
|
||||
tags:
|
||||
- aarch64-darwin-m1
|
||||
variables:
|
||||
OS: "DARWIN"
|
||||
ARCH: "ARM64"
|
||||
CABAL_DIR: "$CI_PROJECT_DIR/cabal"
|
||||
|
||||
.freebsd13:
|
||||
tags:
|
||||
- x86_64-freebsd13
|
||||
variables:
|
||||
OS: "FREEBSD"
|
||||
ARCH: "64"
|
||||
CABAL_DIR: "$CI_PROJECT_DIR/cabal"
|
||||
|
||||
.freebsd12:
|
||||
tags:
|
||||
- x86_64-freebsd12
|
||||
variables:
|
||||
OS: "FREEBSD"
|
||||
ARCH: "64"
|
||||
CABAL_DIR: "$CI_PROJECT_DIR/cabal"
|
||||
|
||||
.windows:
|
||||
tags:
|
||||
- new-x86_64-windows
|
||||
variables:
|
||||
OS: "WINDOWS"
|
||||
ARCH: "64"
|
||||
CABAL_DIR: "$CI_PROJECT_DIR/cabal"
|
||||
retry: 2
|
||||
|
||||
.root_cleanup:
|
||||
after_script:
|
||||
- bash ./.gitlab/after_script.sh
|
||||
|
||||
.test_ghcup_version:
|
||||
script:
|
||||
- bash ./.gitlab/script/ghcup_version.sh
|
||||
variables:
|
||||
JSON_VERSION: "0.0.6"
|
||||
artifacts:
|
||||
expire_in: 2 week
|
||||
paths:
|
||||
- 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
|
||||
- .debian
|
||||
before_script:
|
||||
- ./.gitlab/before_script/linux/install_deps.sh
|
||||
|
||||
.test_ghcup_version:linux32:
|
||||
extends:
|
||||
- .test_ghcup_version
|
||||
- .alpine:32bit
|
||||
before_script:
|
||||
- ./.gitlab/before_script/linux/alpine/install_deps.sh
|
||||
|
||||
.test_ghcup_version:armv7:
|
||||
extends:
|
||||
- .test_ghcup_version
|
||||
- .linux:armv7
|
||||
before_script:
|
||||
- ./.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.sh
|
||||
|
||||
.test_ghcup_version:darwin:
|
||||
extends:
|
||||
- .test_ghcup_version
|
||||
- .darwin
|
||||
- .root_cleanup
|
||||
before_script:
|
||||
- ./.gitlab/before_script/darwin/install_deps.sh
|
||||
|
||||
.test_ghcup_version:darwin:aarch64:
|
||||
extends:
|
||||
- .test_ghcup_version
|
||||
- .darwin:aarch64
|
||||
- .root_cleanup
|
||||
cache:
|
||||
key: darwin-brew-$CACHE_REV
|
||||
paths:
|
||||
- .brew
|
||||
- .brew_cache
|
||||
before_script:
|
||||
# Install brew locally in the project dir. Packages will also be installed here.
|
||||
- '[ -e "$CI_PROJECT_DIR/.brew" ] || git clone --depth=1 https://github.com/Homebrew/brew $CI_PROJECT_DIR/.brew'
|
||||
- export PATH="$CI_PROJECT_DIR/.brew/bin:$CI_PROJECT_DIR/.brew/sbin:$PATH"
|
||||
|
||||
# otherwise we seem to get intel binaries
|
||||
- export HOMEBREW_CHANGE_ARCH_TO_ARM=1
|
||||
|
||||
# make sure to not pollute the machine with temp files etc
|
||||
- mkdir -p $CI_PROJECT_DIR/.bc
|
||||
- export HOMEBREW_CACHE=$CI_PROJECT_DIR/.bc
|
||||
- mkdir -p $CI_PROJECT_DIR/.bl
|
||||
- export HOMEBREW_LOGS=$CI_PROJECT_DIR/.bl
|
||||
- mkdir -p $CI_PROJECT_DIR/.bt
|
||||
- export HOMEBREW_TEMP=$CI_PROJECT_DIR/.bt
|
||||
|
||||
# update and install packages
|
||||
- brew update
|
||||
- brew install llvm
|
||||
- brew install autoconf automake coreutils
|
||||
script: |
|
||||
export PATH="$CI_PROJECT_DIR/.brew/opt/llvm/bin:$CI_PROJECT_DIR/.brew/bin:$CI_PROJECT_DIR/.brew/sbin:$PATH"
|
||||
export CC=$CI_PROJECT_DIR/.brew/opt/llvm/bin/clang
|
||||
export CXX=$CI_PROJECT_DIR/.brew/opt/llvm/bin/clang++
|
||||
export LD=ld
|
||||
export AR=$CI_PROJECT_DIR/.brew/opt/llvm/bin/llvm-ar
|
||||
export RANLIB=$CI_PROJECT_DIR/.brew/opt/llvm/bin/llvm-ranlib
|
||||
./.gitlab/before_script/darwin/install_deps.sh
|
||||
./.gitlab/script/ghcup_version.sh
|
||||
|
||||
.test_ghcup_version:freebsd12:
|
||||
extends:
|
||||
- .test_ghcup_version
|
||||
- .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
|
||||
|
||||
.test_ghcup_version:windows:
|
||||
extends:
|
||||
- .test_ghcup_version
|
||||
- .windows
|
||||
- .root_cleanup
|
||||
before_script:
|
||||
- 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
|
||||
artifacts:
|
||||
expire_in: 2 week
|
||||
paths:
|
||||
- out
|
||||
- dist-newstyle/cache/
|
||||
only:
|
||||
- tags
|
||||
variables:
|
||||
JSON_VERSION: "0.0.6"
|
||||
|
||||
######## stack test ########
|
||||
|
||||
test:linux:stack:
|
||||
stage: test
|
||||
before_script:
|
||||
- ./.gitlab/before_script/linux/install_deps_minimal.sh
|
||||
script:
|
||||
- ./.gitlab/script/ghcup_stack.sh
|
||||
extends:
|
||||
- .debian
|
||||
needs: []
|
||||
|
||||
######## bootstrap test ########
|
||||
|
||||
test:linux:bootstrap_script:
|
||||
stage: quick-test
|
||||
before_script:
|
||||
- ./.gitlab/before_script/linux/install_deps_minimal.sh
|
||||
script:
|
||||
- ./.gitlab/script/ghcup_bootstrap.sh
|
||||
variables:
|
||||
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:
|
||||
stage: test
|
||||
extends: .test_ghcup_version:linux
|
||||
variables:
|
||||
GHC_VERSION: "8.10.7"
|
||||
CABAL_VERSION: "3.6.2.0"
|
||||
needs: []
|
||||
|
||||
test:linux:hls:
|
||||
stage: expensive-test
|
||||
extends:
|
||||
- .test_ghcup_version
|
||||
- .debian
|
||||
variables:
|
||||
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:32bit:
|
||||
stage: test
|
||||
extends: .test_ghcup_version:linux32
|
||||
variables:
|
||||
GHC_VERSION: "8.10.7"
|
||||
CABAL_VERSION: "3.6.2.0"
|
||||
needs: []
|
||||
|
||||
######## arm tests ########
|
||||
|
||||
test:linux:armv7:
|
||||
stage: test
|
||||
extends: .test_ghcup_version:armv7
|
||||
variables:
|
||||
GHC_VERSION: "8.10.7"
|
||||
CABAL_VERSION: "3.6.2.0"
|
||||
CROSS: ""
|
||||
when: manual
|
||||
needs: []
|
||||
|
||||
test:linux:aarch64:
|
||||
stage: test
|
||||
extends: .test_ghcup_version:aarch64
|
||||
variables:
|
||||
GHC_VERSION: "8.10.7"
|
||||
CABAL_VERSION: "3.6.2.0"
|
||||
CROSS: ""
|
||||
when: manual
|
||||
needs: []
|
||||
|
||||
######## darwin test ########
|
||||
|
||||
test:mac:
|
||||
stage: test
|
||||
extends: .test_ghcup_version:darwin
|
||||
variables:
|
||||
GHC_VERSION: "8.10.7"
|
||||
CABAL_VERSION: "3.6.2.0"
|
||||
needs: []
|
||||
|
||||
test:mac:aarch64:
|
||||
stage: test
|
||||
extends: .test_ghcup_version:darwin:aarch64
|
||||
variables:
|
||||
GHC_VERSION: "8.10.7"
|
||||
CABAL_VERSION: "3.6.2.0"
|
||||
needs: []
|
||||
allow_failure: true
|
||||
when: manual
|
||||
|
||||
|
||||
######## freebsd test ########
|
||||
|
||||
test:freebsd12:
|
||||
stage: test
|
||||
extends: .test_ghcup_version:freebsd12
|
||||
variables:
|
||||
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:
|
||||
stage: test
|
||||
extends: .test_ghcup_version:windows
|
||||
variables:
|
||||
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"]
|
||||
extends:
|
||||
- .alpine:64bit
|
||||
- .release_ghcup
|
||||
before_script:
|
||||
- ./.gitlab/before_script/linux/alpine/install_deps.sh
|
||||
variables:
|
||||
ARTIFACT: "x86_64-linux-ghcup"
|
||||
GHC_VERSION: "8.10.7"
|
||||
CABAL_VERSION: "3.6.2.0"
|
||||
|
||||
|
||||
release:linux:32bit:
|
||||
stage: release
|
||||
needs: ["test:linux:32bit"]
|
||||
extends:
|
||||
- .alpine:32bit
|
||||
- .release_ghcup
|
||||
before_script:
|
||||
- ./.gitlab/before_script/linux/alpine/install_deps.sh
|
||||
variables:
|
||||
ARTIFACT: "i386-linux-ghcup"
|
||||
GHC_VERSION: "8.10.7"
|
||||
CABAL_VERSION: "3.6.2.0"
|
||||
|
||||
release:linux:armv7:
|
||||
stage: release
|
||||
needs: ["test:linux:armv7"]
|
||||
extends:
|
||||
- .linux:armv7
|
||||
- .release_ghcup
|
||||
before_script:
|
||||
- ./.gitlab/before_script/linux/install_deps.sh
|
||||
variables:
|
||||
ARTIFACT: "armv7-linux-ghcup"
|
||||
GHC_VERSION: "8.10.7"
|
||||
CABAL_VERSION: "3.6.2.0"
|
||||
CROSS: ""
|
||||
|
||||
release:linux:aarch64:
|
||||
stage: release
|
||||
needs: ["test:linux:aarch64"]
|
||||
extends:
|
||||
- .linux:aarch64
|
||||
- .release_ghcup
|
||||
before_script:
|
||||
- ./.gitlab/before_script/linux/install_deps.sh
|
||||
variables:
|
||||
ARTIFACT: "aarch64-linux-ghcup"
|
||||
GHC_VERSION: "8.10.7"
|
||||
CABAL_VERSION: "3.6.2.0"
|
||||
CROSS: ""
|
||||
|
||||
######## darwin release ########
|
||||
|
||||
release:darwin:
|
||||
stage: release
|
||||
needs: ["test:mac"]
|
||||
extends:
|
||||
- .darwin
|
||||
- .release_ghcup
|
||||
- .root_cleanup
|
||||
before_script:
|
||||
- ./.gitlab/before_script/darwin/install_deps.sh
|
||||
variables:
|
||||
ARTIFACT: "x86_64-apple-darwin-ghcup"
|
||||
GHC_VERSION: "8.10.7"
|
||||
CABAL_VERSION: "3.6.2.0"
|
||||
MACOSX_DEPLOYMENT_TARGET: "10.7"
|
||||
|
||||
release:darwin:aarch64:
|
||||
stage: release
|
||||
needs: ["test:mac:aarch64"]
|
||||
extends:
|
||||
- .darwin:aarch64
|
||||
- .release_ghcup
|
||||
- .root_cleanup
|
||||
cache:
|
||||
key: darwin-brew-$CACHE_REV
|
||||
paths:
|
||||
- .brew
|
||||
- .brew_cache
|
||||
before_script:
|
||||
# Install brew locally in the project dir. Packages will also be installed here.
|
||||
- '[ -e "$CI_PROJECT_DIR/.brew" ] || git clone --depth=1 https://github.com/Homebrew/brew $CI_PROJECT_DIR/.brew'
|
||||
- export PATH="$CI_PROJECT_DIR/.brew/bin:$CI_PROJECT_DIR/.brew/sbin:$PATH"
|
||||
|
||||
# otherwise we seem to get intel binaries
|
||||
- export HOMEBREW_CHANGE_ARCH_TO_ARM=1
|
||||
|
||||
# make sure to not pollute the machine with temp files etc
|
||||
- mkdir -p $CI_PROJECT_DIR/.bc
|
||||
- export HOMEBREW_CACHE=$CI_PROJECT_DIR/.bc
|
||||
- mkdir -p $CI_PROJECT_DIR/.bl
|
||||
- export HOMEBREW_LOGS=$CI_PROJECT_DIR/.bl
|
||||
- mkdir -p $CI_PROJECT_DIR/.bt
|
||||
- export HOMEBREW_TEMP=$CI_PROJECT_DIR/.bt
|
||||
|
||||
# update and install packages
|
||||
- brew update
|
||||
- brew install llvm
|
||||
- brew install autoconf automake
|
||||
script: |
|
||||
export PATH="$CI_PROJECT_DIR/.brew/opt/llvm/bin:$CI_PROJECT_DIR/.brew/bin:$CI_PROJECT_DIR/.brew/sbin:$PATH"
|
||||
export CC=$CI_PROJECT_DIR/.brew/opt/llvm/bin/clang
|
||||
export CXX=$CI_PROJECT_DIR/.brew/opt/llvm/bin/clang++
|
||||
export LD=ld
|
||||
export AR=$CI_PROJECT_DIR/.brew/opt/llvm/bin/llvm-ar
|
||||
export RANLIB=$CI_PROJECT_DIR/.brew/opt/llvm/bin/llvm-ranlib
|
||||
./.gitlab/before_script/darwin/install_deps.sh
|
||||
./.gitlab/script/ghcup_release.sh
|
||||
variables:
|
||||
ARTIFACT: "aarch64-apple-darwin-ghcup"
|
||||
GHC_VERSION: "8.10.7"
|
||||
CABAL_VERSION: "3.6.2.0"
|
||||
MACOSX_DEPLOYMENT_TARGET: "10.7"
|
||||
allow_failure: true
|
||||
when: manual
|
||||
|
||||
|
||||
######## freebsd release ########
|
||||
|
||||
release:freebsd12:
|
||||
stage: release
|
||||
needs: ["test:freebsd12"]
|
||||
extends:
|
||||
- .freebsd12
|
||||
- .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
|
||||
|
||||
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"]
|
||||
extends:
|
||||
- .windows
|
||||
- .release_ghcup
|
||||
- .root_cleanup
|
||||
before_script:
|
||||
- bash ./.gitlab/before_script/windows/install_deps.sh
|
||||
variables:
|
||||
ARTIFACT: "x86_64-mingw64-ghcup"
|
||||
GHC_VERSION: "8.10.7"
|
||||
CABAL_VERSION: "3.6.2.0"
|
||||
|
||||
######## hlint ########
|
||||
|
||||
hlint:
|
||||
stage: checks
|
||||
extends:
|
||||
- .debian
|
||||
script:
|
||||
- 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
|
||||
|
||||
15
.gitlab/after_script.sh
Normal file
@@ -0,0 +1,15 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eux
|
||||
|
||||
BUILD_DIR=$CI_PROJECT_DIR
|
||||
echo "Cleaning $BUILD_DIR"
|
||||
cd $HOME
|
||||
test -n "$BUILD_DIR"
|
||||
shopt -s extglob
|
||||
rm -Rf "$BUILD_DIR"/!(out)
|
||||
if [ "${OS}" = "WINDOWS" ] ; then
|
||||
rm -Rf /c/ghcup
|
||||
fi
|
||||
|
||||
exit 0
|
||||
32
.gitlab/before_script/darwin/install_deps.sh
Executable file
@@ -0,0 +1,32 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eux
|
||||
|
||||
. "$( cd "$(dirname "$0")" ; pwd -P )/../../ghcup_env"
|
||||
|
||||
mkdir -p "${TMPDIR}"
|
||||
|
||||
if [ $ARCH = 'ARM64' ] ; then
|
||||
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
|
||||
chmod +x ghcup-bin
|
||||
./ghcup-bin upgrade -i -f
|
||||
fi
|
||||
|
||||
./ghcup-bin install ${GHC_VERSION}
|
||||
./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
|
||||
19
.gitlab/before_script/freebsd/install_deps.sh
Executable file
@@ -0,0 +1,19 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eux
|
||||
|
||||
# pkg install --force --yes --no-repo-update curl gcc gmp gmake ncurses perl5 libffi libiconv
|
||||
|
||||
. "$( cd "$(dirname "$0")" ; pwd -P )/../../ghcup_env"
|
||||
|
||||
mkdir -p "${TMPDIR}"
|
||||
|
||||
curl -sSfL https://downloads.haskell.org/~ghcup/x86_64-portbld-freebsd-ghcup > ./ghcup-bin
|
||||
chmod +x ghcup-bin
|
||||
|
||||
./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
|
||||
58
.gitlab/before_script/linux/alpine/install_deps.sh
Executable file
@@ -0,0 +1,58 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eux
|
||||
|
||||
. "$( cd "$(dirname "$0")" ; pwd -P )/../../../ghcup_env"
|
||||
|
||||
mkdir -p "${TMPDIR}"
|
||||
|
||||
apk add --no-cache \
|
||||
curl \
|
||||
gcc \
|
||||
g++ \
|
||||
binutils \
|
||||
binutils-gold \
|
||||
bsd-compat-headers \
|
||||
gmp-dev \
|
||||
ncurses-dev \
|
||||
libffi-dev \
|
||||
make \
|
||||
xz \
|
||||
tar \
|
||||
perl
|
||||
|
||||
if [ "${ARCH}" = "32" ] ; then
|
||||
curl -sSfL https://downloads.haskell.org/ghcup/i386-linux-ghcup > ./ghcup-bin
|
||||
else
|
||||
curl -sSfL https://downloads.haskell.org/ghcup/x86_64-linux-ghcup > ./ghcup-bin
|
||||
fi
|
||||
chmod +x ghcup-bin
|
||||
./ghcup-bin upgrade -i -f
|
||||
./ghcup-bin install ${GHC_VERSION}
|
||||
./ghcup-bin install-cabal ${CABAL_VERSION}
|
||||
|
||||
# utils
|
||||
apk add --no-cache \
|
||||
bash \
|
||||
git
|
||||
|
||||
## Package specific
|
||||
apk add --no-cache \
|
||||
zlib \
|
||||
zlib-dev \
|
||||
zlib-static \
|
||||
bzip2 \
|
||||
bzip2-dev \
|
||||
bzip2-static \
|
||||
gmp \
|
||||
gmp-dev \
|
||||
openssl-dev \
|
||||
openssl-libs-static \
|
||||
xz \
|
||||
xz-dev \
|
||||
ncurses-static
|
||||
|
||||
if [ "${ARCH}" = "32" ] ; then
|
||||
apk add --no-cache \
|
||||
bsd-compat-headers
|
||||
fi
|
||||
27
.gitlab/before_script/linux/install_deps.sh
Executable file
@@ -0,0 +1,27 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eux
|
||||
|
||||
. "$( cd "$(dirname "$0")" ; pwd -P )/../../ghcup_env"
|
||||
|
||||
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 lsb-release software-properties-common gnupg2 apt-transport-https gcc autoconf automake build-essential
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
10
.gitlab/before_script/linux/install_deps_minimal.sh
Executable file
@@ -0,0 +1,10 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eux
|
||||
|
||||
. "$( cd "$(dirname "$0")" ; pwd -P )/../../ghcup_env"
|
||||
|
||||
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
|
||||
21
.gitlab/before_script/windows/install_deps.sh
Normal file
@@ -0,0 +1,21 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eux
|
||||
|
||||
. "$( cd "$(dirname "$0")" ; pwd -P )/../../ghcup_env"
|
||||
|
||||
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/x86_64-mingw64-ghcup.exe
|
||||
chmod +x ghcup.exe
|
||||
|
||||
./ghcup.exe install ${GHC_VERSION}
|
||||
./ghcup.exe set ${GHC_VERSION}
|
||||
./ghcup.exe install-cabal ${CABAL_VERSION}
|
||||
|
||||
rm ./ghcup.exe
|
||||
|
||||
exit 0
|
||||
8734
.gitlab/ghc-8.10.3-linux.files
Normal file
10321
.gitlab/ghc-8.10.3-windows.files
Normal file
11
.gitlab/ghcup_env
Normal file
@@ -0,0 +1,11 @@
|
||||
if [ "${OS}" = "WINDOWS" ] ; then
|
||||
export GHCUP_INSTALL_BASE_PREFIX="$CI_PROJECT_DIR"
|
||||
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 GHCUP_BIN="$CI_PROJECT_DIR/.ghcup/bin"
|
||||
export PATH="$GHCUP_BIN:$CI_PROJECT_DIR/.local/bin:$PATH"
|
||||
export TMPDIR="$CI_PROJECT_DIR/tmp"
|
||||
fi
|
||||
30
.gitlab/script/ghcup_bootstrap.sh
Executable file
@@ -0,0 +1,30 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eux
|
||||
|
||||
. "$( cd "$(dirname "$0")" ; pwd -P )/../ghcup_env"
|
||||
|
||||
mkdir -p "$CI_PROJECT_DIR"/.local/bin
|
||||
|
||||
ecabal() {
|
||||
cabal "$@"
|
||||
}
|
||||
|
||||
eghcup() {
|
||||
ghcup -v -c -s file://$(pwd)/ghcup-${JSON_VERSION}.yaml "$@"
|
||||
}
|
||||
|
||||
git describe --always
|
||||
|
||||
### build
|
||||
|
||||
ecabal update
|
||||
|
||||
export BOOTSTRAP_HASKELL_NONINTERACTIVE=yes
|
||||
export BOOTSTRAP_HASKELL_GHC_VERSION=$GHC_VERSION
|
||||
export BOOTSTRAP_HASKELL_CABAL_VERSION=$CABAL_VERSION
|
||||
|
||||
./scripts/bootstrap/bootstrap-haskell
|
||||
|
||||
[ "$(ghc --numeric-version)" = "${GHC_VERSION}" ]
|
||||
|
||||
54
.gitlab/script/ghcup_cross.sh
Executable file
@@ -0,0 +1,54 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eux
|
||||
|
||||
. "$( cd "$(dirname "$0")" ; pwd -P )/../ghcup_env"
|
||||
|
||||
mkdir -p "$CI_PROJECT_DIR"/.local/bin
|
||||
mkdir -p data/
|
||||
git clone https://github.com/haskell/ghcup-metadata.git data/metadata
|
||||
|
||||
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" ]
|
||||
|
||||
54
.gitlab/script/ghcup_git.sh
Executable file
@@ -0,0 +1,54 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eux
|
||||
|
||||
. "$( cd "$(dirname "$0")" ; pwd -P )/../ghcup_env"
|
||||
|
||||
mkdir -p "$CI_PROJECT_DIR"/.local/bin
|
||||
mkdir -p data/
|
||||
git clone https://github.com/haskell/ghcup-metadata.git data/metadata
|
||||
|
||||
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" ]
|
||||
|
||||
53
.gitlab/script/ghcup_hls.sh
Executable file
@@ -0,0 +1,53 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eux
|
||||
|
||||
. "$( cd "$(dirname "$0")" ; pwd -P )/../ghcup_env"
|
||||
|
||||
mkdir -p "$CI_PROJECT_DIR"/.local/bin
|
||||
mkdir -p data/
|
||||
git clone https://github.com/haskell/ghcup-metadata.git data/metadata
|
||||
|
||||
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" ]
|
||||
|
||||
44
.gitlab/script/ghcup_release.sh
Executable file
@@ -0,0 +1,44 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eux
|
||||
|
||||
. "$( cd "$(dirname "$0")" ; pwd -P )/../ghcup_env"
|
||||
|
||||
mkdir -p "$CI_PROJECT_DIR"/.local/bin
|
||||
|
||||
ecabal() {
|
||||
cabal "$@"
|
||||
}
|
||||
|
||||
git describe
|
||||
|
||||
# build
|
||||
ecabal update
|
||||
|
||||
|
||||
if [ "${OS}" = "LINUX" ] ; then
|
||||
if [ "${ARCH}" = "32" ] ; then
|
||||
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
|
||||
ecabal build -w ghc-${GHC_VERSION} -ftui
|
||||
fi
|
||||
elif [ "${OS}" = "FREEBSD" ] ; then
|
||||
ecabal build -w ghc-${GHC_VERSION} --ghc-options='-split-sections' --constraint="zlib +bundled-c-zlib" --constraint="zip +disable-zstd" -ftui
|
||||
elif [ "${OS}" = "WINDOWS" ] ; then
|
||||
ecabal build -w ghc-${GHC_VERSION} --constraint="zlib +bundled-c-zlib" --constraint="lzma +static"
|
||||
else
|
||||
ecabal build -w ghc-${GHC_VERSION} --constraint="zlib +bundled-c-zlib" --constraint="lzma +static" -ftui
|
||||
fi
|
||||
|
||||
mkdir out
|
||||
binary=$(ecabal new-exec -w ghc-${GHC_VERSION} --verbose=0 --offline sh -- -c 'command -v ghcup')
|
||||
ver=$("${binary}" --numeric-version)
|
||||
if [ "${OS}" = "DARWIN" ] ; then
|
||||
strip "${binary}"
|
||||
else
|
||||
strip -s "${binary}"
|
||||
fi
|
||||
cp "${binary}" out/${ARTIFACT}-${ver}
|
||||
|
||||
21
.gitlab/script/ghcup_stack.sh
Executable file
@@ -0,0 +1,21 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eux
|
||||
|
||||
. "$( cd "$(dirname "$0")" ; pwd -P )/../ghcup_env"
|
||||
|
||||
mkdir -p "$CI_PROJECT_DIR"/.local/bin
|
||||
|
||||
git describe --always
|
||||
|
||||
### build
|
||||
|
||||
curl -L -O https://get.haskellstack.org/stable/linux-x86_64.tar.gz
|
||||
tar xf linux-x86_64.tar.gz
|
||||
cp stack-*-linux-*/stack "$CI_PROJECT_DIR"/.local/bin/stack
|
||||
chmod +x "$CI_PROJECT_DIR"/.local/bin/stack
|
||||
|
||||
mkdir -p "$CI_PROJECT_DIR"/.stack_root
|
||||
export TAR_OPTIONS=--no-same-owner
|
||||
stack --allow-different-user --stack-root "$CI_PROJECT_DIR"/.stack_root build
|
||||
stack --allow-different-user --stack-root "$CI_PROJECT_DIR"/.stack_root test
|
||||
257
.gitlab/script/ghcup_version.sh
Executable file
@@ -0,0 +1,257 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eux
|
||||
|
||||
. "$( cd "$(dirname "$0")" ; pwd -P )/../ghcup_env"
|
||||
|
||||
mkdir -p "$CI_PROJECT_DIR"/.local/bin
|
||||
mkdir -p data/
|
||||
git clone https://github.com/haskell/ghcup-metadata.git data/metadata
|
||||
|
||||
CI_PROJECT_DIR=$(pwd)
|
||||
|
||||
ecabal() {
|
||||
cabal "$@"
|
||||
}
|
||||
|
||||
raw_eghcup() {
|
||||
ghcup -v -c "$@"
|
||||
}
|
||||
|
||||
eghcup() {
|
||||
if [ "${OS}" = "WINDOWS" ] ; then
|
||||
ghcup -v -c -s file:/$CI_PROJECT_DIR/data/metadata/ghcup-${JSON_VERSION}.yaml "$@"
|
||||
else
|
||||
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
|
||||
|
||||
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
|
||||
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"
|
||||
ecabal test -w ghc-${GHC_VERSION} -finternal-downloader -ftui --constraint="zip +disable-zstd" ghcup-test
|
||||
ecabal haddock -w ghc-${GHC_VERSION} -finternal-downloader -ftui --constraint="zip +disable-zstd"
|
||||
elif [ "${OS}" = "WINDOWS" ] ; then
|
||||
ecabal build -w ghc-${GHC_VERSION}
|
||||
ecabal test -w ghc-${GHC_VERSION} ghcup-test
|
||||
ecabal haddock -w ghc-${GHC_VERSION}
|
||||
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
|
||||
fi
|
||||
|
||||
|
||||
if [ "${OS}" = "WINDOWS" ] ; then
|
||||
ext=".exe"
|
||||
else
|
||||
ext=''
|
||||
fi
|
||||
cp "$(ecabal new-exec -w ghc-${GHC_VERSION} --verbose=0 --offline sh -- -c 'command -v ghcup')" "$CI_PROJECT_DIR"/.local/bin/ghcup${ext}
|
||||
|
||||
### cleanup
|
||||
|
||||
rm -rf "${GHCUP_DIR}"
|
||||
|
||||
### manual cli based testing
|
||||
|
||||
|
||||
eghcup --numeric-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
|
||||
|
||||
ghc_ver=$(ghc --numeric-version)
|
||||
ghc --version
|
||||
ghc-${ghc_ver} --version
|
||||
if [ "${OS}" != "WINDOWS" ] ; then
|
||||
ghci --version
|
||||
ghci-${ghc_ver} --version
|
||||
fi
|
||||
|
||||
|
||||
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
|
||||
$(eghcup whereis hls) --version
|
||||
|
||||
eghcup install stack
|
||||
$(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)
|
||||
|
||||
# https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/116
|
||||
if [ "${OS}" = "LINUX" ] ; then
|
||||
if [ "${ARCH}" = "64" ] ; then
|
||||
eghcup install cabal -u https://oleg.fi/cabal-install-3.4.0.0-rc4/cabal-install-3.4.0.0-x86_64-ubuntu-16.04.tar.xz 3.4.0.0-rc4
|
||||
eghcup rm cabal 3.4.0.0-rc4
|
||||
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}" ]
|
||||
19
.gitlab/script/hlint.sh
Executable file
@@ -0,0 +1,19 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eux
|
||||
|
||||
. "$( cd "$(dirname "$0")" ; pwd -P )/../ghcup_env"
|
||||
|
||||
mkdir -p "$CI_PROJECT_DIR"/.local/bin
|
||||
|
||||
ecabal() {
|
||||
cabal --store-dir="$(pwd)"/.store "$@"
|
||||
}
|
||||
|
||||
git describe
|
||||
|
||||
ecabal update
|
||||
ecabal install -w ghc-${GHC_VERSION} --installdir="$CI_PROJECT_DIR"/.local/bin hlint
|
||||
|
||||
hlint -r app/ lib/ test/
|
||||
|
||||
83
.hlint.yaml
Normal file
@@ -0,0 +1,83 @@
|
||||
# HLint configuration file
|
||||
# https://github.com/ndmitchell/hlint
|
||||
##########################
|
||||
|
||||
# This file contains a template configuration file, which is typically
|
||||
# placed as .hlint.yaml in the root of your project
|
||||
|
||||
|
||||
# Warnings currently triggered by your code
|
||||
- ignore: {name: "Redundant bang pattern"}
|
||||
- ignore: {name: "Use camelCase"}
|
||||
- ignore: {name: "Use if"}
|
||||
- ignore: {name: "Use newtype instead of data"}
|
||||
- ignore: {name: "Use <$>"}
|
||||
- ignore: {name: "Use mapMaybe"}
|
||||
- ignore: {name: "Use const"}
|
||||
- ignore: {name: "Use list comprehension"}
|
||||
- ignore: {name: "Redundant multi-way if"}
|
||||
- ignore: {name: "Redundant lambda"}
|
||||
- ignore: {name: "Avoid lambda"}
|
||||
- ignore: {name: "Use uncurry"}
|
||||
- ignore: {name: "Use replicateM"}
|
||||
- ignore: {name: "Redundant irrefutable pattern"}
|
||||
|
||||
|
||||
# Specify additional command line arguments
|
||||
#
|
||||
# - arguments: [--color, --cpp-simple, -XQuasiQuotes]
|
||||
|
||||
|
||||
# Control which extensions/flags/modules/functions can be used
|
||||
#
|
||||
# - extensions:
|
||||
# - default: false # all extension are banned by default
|
||||
# - name: [PatternGuards, ViewPatterns] # only these listed extensions can be used
|
||||
# - {name: CPP, within: CrossPlatform} # CPP can only be used in a given module
|
||||
#
|
||||
# - flags:
|
||||
# - {name: -w, within: []} # -w is allowed nowhere
|
||||
#
|
||||
# - modules:
|
||||
# - {name: [Data.Set, Data.HashSet], as: Set} # if you import Data.Set qualified, it must be as 'Set'
|
||||
# - {name: Control.Arrow, within: []} # Certain modules are banned entirely
|
||||
#
|
||||
# - functions:
|
||||
# - {name: unsafePerformIO, within: []} # unsafePerformIO can only appear in no modules
|
||||
|
||||
|
||||
# Add custom hints for this project
|
||||
#
|
||||
# Will suggest replacing "wibbleMany [myvar]" with "wibbleOne myvar"
|
||||
# - error: {lhs: "wibbleMany [x]", rhs: wibbleOne x}
|
||||
|
||||
# The hints are named by the string they display in warning messages.
|
||||
# For example, if you see a warning starting like
|
||||
#
|
||||
# Main.hs:116:51: Warning: Redundant ==
|
||||
#
|
||||
# You can refer to that hint with `{name: Redundant ==}` (see below).
|
||||
|
||||
# Turn on hints that are off by default
|
||||
#
|
||||
# Ban "module X(module X) where", to require a real export list
|
||||
# - warn: {name: Use explicit module export list}
|
||||
#
|
||||
# Replace a $ b $ c with a . b $ c
|
||||
# - group: {name: dollar, enabled: true}
|
||||
#
|
||||
# Generalise map to fmap, ++ to <>
|
||||
# - group: {name: generalise, enabled: true}
|
||||
|
||||
|
||||
# Ignore some builtin hints
|
||||
# - ignore: {name: Use let}
|
||||
# - ignore: {name: Use const, within: SpecialModule} # Only within certain modules
|
||||
|
||||
|
||||
# Define some custom infix operators
|
||||
# - fixity: infixr 3 ~^#^~
|
||||
|
||||
|
||||
# To generate a suitable file for HLint do:
|
||||
# $ hlint --default > .hlint.yaml
|
||||
25
.travis.yml
Normal file
@@ -0,0 +1,25 @@
|
||||
jobs:
|
||||
include:
|
||||
- os: osx
|
||||
osx_image: xcode10.1
|
||||
language: generic
|
||||
env: ARTIFACT=x86_64-apple-darwin-10.13-ghcup
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode11.3
|
||||
language: generic
|
||||
env: ARTIFACT=x86_64-apple-darwin-10.14-ghcup
|
||||
|
||||
|
||||
script: ".travis/build.sh"
|
||||
|
||||
deploy:
|
||||
provider: releases
|
||||
api_key:
|
||||
secure: "hT2od8Iy04tdFVuonPSWv0NX5hZDmv4al8Q0GbIWmviUetROuM7c6/MCHUcgyiw6H2L3pmH4F24GBYWpKBT3ZMbxrKXhZOZ3KPLXzlnuRlm1qymKqqwsJs3466bMftaiBr16rx1VpAuditN4A32oSmTFcQAJc84Bxn2WZ4t8hk9muS8YPyLhqg3/NxT6ob8dzNp9eS2cA0WODMb/fMzaMruRtepSK8JvuXb/SnTvaDcl9plmPzEa+eW54jwVsDps8ZpQMQlTtGIjYHIwTQ36/iLH4LoAvD7OEnB7qf753LOzmI/bvlB75xYGsLxe1qgpzPMjuG3AK0jb2KGSZCzyAyrbBFSQMIyC1gNKMtab3CohnA9WdQqAT1xrzPzA9zNw516G5Fn/z+t9Ek1f6L2OYO2hJfweNhWh+ChAIsOags2QBpqc0qjkwUS4wqxCWBdyVfgPTUoGelvjCfjQgypgIyLEHFvXt9rlj+kd97FY7nG3vxZrsvWTKKKT551OqUYX5zWTyvGR71jKyNst/p93Pg3DkRy31gHrGnG9zfNgN5tWxJqDd/suR/BAFTp0VtkFb8fR3ct7WMVeJXtE2+bKqxO5Fnocs1VjEm8pKPk7glnp0muu08kaO0h54wiSOCbk1RvO1KZtHue4wKWrHcI18dwW2WtzoBQ4P1lOSkS81UY="
|
||||
file: $ARTIFACT
|
||||
on:
|
||||
repo: hasufell/ghcup-hs
|
||||
tags: true
|
||||
skip_cleanup: true
|
||||
draft: true
|
||||
28
.travis/build.sh
Executable file
@@ -0,0 +1,28 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -ex
|
||||
|
||||
mkdir -p ~/.ghcup/bin
|
||||
curl -sSfL https://downloads.haskell.org/~ghcup/x86_64-apple-darwin-ghcup > ~/.ghcup/bin/ghcup
|
||||
chmod +x ~/.ghcup/bin/ghcup
|
||||
|
||||
export PATH="$HOME/.ghcup/bin:$PATH"
|
||||
|
||||
ghcup install 8.10.4
|
||||
ghcup install-cabal 3.4.0.0
|
||||
ghcup set 8.10.4
|
||||
|
||||
|
||||
## install ghcup
|
||||
|
||||
cabal update
|
||||
|
||||
(
|
||||
cd /tmp
|
||||
cabal install --installdir="$HOME"/.ghcup/bin hspec-discover
|
||||
)
|
||||
|
||||
cabal build --constraint="zlib +static" --constraint="lzma +static" -ftui
|
||||
cp "$(cabal new-exec --verbose=0 --offline sh -- -c 'command -v ghcup')" .
|
||||
strip ./ghcup
|
||||
cp ghcup "./${ARTIFACT}"
|
||||
214
CHANGELOG.md
@@ -1,5 +1,217 @@
|
||||
# Revision history for ghcup
|
||||
|
||||
## 0.1.0.0 -- YYYY-mm-dd
|
||||
## 0.1.17.3 -- 2021-10-27
|
||||
|
||||
* clean up during unpack failures as well
|
||||
* migrate te aeson-2.0.1.0
|
||||
* switch to yaml-streamly to fix performance regression wrt [#270](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/270)
|
||||
* use [github.com/haskell/ghcup-metadata](https://github.com/haskell/ghcup-metadata) for metadata file download (better caching)
|
||||
|
||||
## 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)
|
||||
* Fix GHC compilation from git
|
||||
* Fix 'ghcup upgrade' on windows
|
||||
* Allow to skip update checks via `GHCUP_SKIP_UPDATE_CHECK`
|
||||
* Use libarchive on windows as well, fixing unpack errors wrt [#147](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/147)
|
||||
|
||||
## 0.1.15.1 -- 2021-06-11
|
||||
|
||||
* Add Apple Silicon support
|
||||
* Add windows support wrt [#130](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/130)
|
||||
* Add stack support
|
||||
* Warn when /tmp doesn't have 5GB or more of disk space
|
||||
* Allow to compile GHC from git repo wrt [#126](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/126)
|
||||
* Allow to set custom ghc version when running 'ghcup compile ghc' wrt [#136](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/136)
|
||||
* Add date to GHC bindist names created by ghcup
|
||||
|
||||
## 0.1.14.2 -- 2021-05-12
|
||||
|
||||
* Remove dead dependency on ascii-string
|
||||
|
||||
## 0.1.14.1 -- 2021-04-11
|
||||
|
||||
* Make internal symlink target parser more lax, fixes [#119](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/119)
|
||||
* Prepare for hackage release
|
||||
|
||||
## 0.1.14 -- 2021-03-07
|
||||
|
||||
* Major bugfix: fix handling of stray versions wrt [#116](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/116)
|
||||
* Fix error messages and overhaul pretty printing wrt [#115](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/115)
|
||||
|
||||
## 0.1.13 -- 2021-02-26
|
||||
|
||||
* Support ARMv7/AARCH64
|
||||
* Add command line completions for installed and available versions wrt [MR #70](https://gitlab.haskell.org/haskell/ghcup-hs/-/merge_requests/70)
|
||||
* Allow to cycle through set tools wrt [#114](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/114)
|
||||
* Fix item selection with unavailable versions wrt [#107](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/107)
|
||||
* Allow for dynamic post-install, post-remove and pre-compile msgs wrt [MR #68](https://gitlab.haskell.org/haskell/ghcup-hs/-/merge_requests/68)
|
||||
* Alert user if upgraded ghcup is shadowed by old ghcup wrt [#111](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/111)
|
||||
* Fix to `ghcup` directory creation and placement for the XDG install mode ([MR #49](https://gitlab.haskell.org/haskell/ghcup-hs/-/merge_requests/49))
|
||||
* Do 755 permissions on executables, wrt #97
|
||||
* Add [NO_COLOR](https://no-color.org/) support wrt [MR #47](https://gitlab.haskell.org/haskell/ghcup-hs/-/merge_requests/47)
|
||||
|
||||
## 0.1.12 -- 2020-11-21
|
||||
|
||||
* Fix disappearing HLS symlinks wrt #91
|
||||
* improve TUI:
|
||||
- separators between tools sections
|
||||
- reverse list order so latest is on top
|
||||
- expand the blues selected bar
|
||||
- show new latest versions in bright white
|
||||
* allow configuration file and setting TUI hotkeys wrt #41
|
||||
- see https://gitlab.haskell.org/haskell/ghcup-hs#configuration for a more in-depth explanation
|
||||
* add a `--set` switch to `ghcup install ghc` to automatically set as default after install
|
||||
* emit warnings when CC/LD is set wrt #82
|
||||
* add support for version ranges in distro specifiers wrt #84
|
||||
- e.g. `"(>= 19 && <= 20) || ==0.2.2"` is a valid version key for distro
|
||||
|
||||
## 0.1.11 -- 2020-09-23
|
||||
|
||||
* Add support for installing haskell-language-server, wrt #65
|
||||
* When compiling GHC from source create a bindist first, store that bindist in `~/.ghcup/cache` and install it, wrt #51
|
||||
* Allow to compile over existing version (`ghcup compile ghc -v 8.6.5 -b 8.6.5`) and replace it wrt #59
|
||||
* simplify installing from custom bindist wrt #60
|
||||
- `ghcup install ghc -u <url> <version>`
|
||||
* fix bug when cabal isn't marked executable in bindist
|
||||
* fix bug when `~/.ghcup` is a valid symlink wrt #49
|
||||
* Drop support for compiling cabal from source (the old bootstrap script is discontinued)
|
||||
|
||||
## 0.1.10 -- 2020-08-14
|
||||
|
||||
* Show stray Cabals (useful for pre-releases or compiled ones)
|
||||
|
||||
## 0.1.9 -- 2020-08-14
|
||||
|
||||
* Fix bug when uninstalling all cabal versions
|
||||
* Fix bug when setting a non-installed ghc version as current default
|
||||
* Use yaml instead of generated json for download info for ease of adding new GHC versions #44
|
||||
* Allow pre-release versions of GHC/cabal
|
||||
* Add XDG dirs support (set `GHCUP_USE_XDG_DIRS`) wrt #39
|
||||
* Allow to specify regex for tarball subdir (e.g. `ghc-.*`)
|
||||
* Allow installing arbitrary bindists more seamlessly:
|
||||
- e.g. installing GHC HEAD: `ghcup -n install ghc -u '{"dlHash": "", "dlSubdir": { "RegexDir": "ghc-.*"}, "dlUri": "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`
|
||||
* Avoid duplicate edits to .bashrc/.zshrc wrt #43
|
||||
|
||||
## 0.1.8 -- 2020-07-21
|
||||
|
||||
* Fix bug in logging thread dying on newlines
|
||||
* Allow to install from arbitrary bindists: `ghcup -n install ghc -u '{"dlHash": "", "dlSubdir": "ghc-8.10.1", "dlUri": "https://github.com/commercialhaskell/ghc/releases/download/ghc-8.10.1-release/ghc-8.10.1-x86_64-deb9-linux.tar.xz"}' 8.10.1`
|
||||
|
||||
## 0.1.7 -- 2020-07-20
|
||||
|
||||
* Fix a bug in libarchive not unpacking some uncleanly packed bindists
|
||||
* Improved fish support in bootstrap-haskell
|
||||
* Only check for upgrades when not upgrading
|
||||
* Fix platform detection for i386 docker images
|
||||
* Improve alpine support
|
||||
- more/proper bindists
|
||||
- don't fall back to glibc based bindists
|
||||
- install bindists with `--disable-ld-override` to avoid ld.gold bugs
|
||||
|
||||
## 0.1.6 -- 2020-07-13
|
||||
|
||||
* Create a new curses (brick) based TUI, accessible via `ghcup tui` #24
|
||||
* Support multiple installed versions of cabal #23
|
||||
* Improvements to `ghcup list` (show unavailable bindists for platform)
|
||||
* Fix redhat downloads #29
|
||||
* Support for hadrian bindists (fixes alpine-8.10.1) #31
|
||||
* Add FreeBSD bindists 8.6.5 and 8.8.3
|
||||
* Fix memory leak during unpack
|
||||
|
||||
## 0.1.5 -- 2020-04-30
|
||||
|
||||
* Fix errors when PATH variable contains path components that are actually files
|
||||
* Add `--version` and `--numeric-version` options
|
||||
* Add `changelog` command
|
||||
* Also check for available GHC and Cabal updates on start
|
||||
* Add base versions as tags for every GHC version (these are "installable" tags and the latest GHC version matching the tag will be picked)
|
||||
* Added `--format-raw` to list subcommand
|
||||
* Allow to install X.Y versions (e.g.: ghcup install 8.8)
|
||||
* Implement `--keep=<always|errors|never>` to control temporary build directories cleanup
|
||||
* Add proper shell completions to the repo
|
||||
* Fix building of documentation
|
||||
* Allow to work in offline mode and use cached files if possible
|
||||
* Allow to set the downloader via `--downloader=<curl|wget>`
|
||||
* Support for compiling and installing a cross GHC (see README). This is experimental.
|
||||
|
||||
## 0.1.4 -- 2020-04-16
|
||||
|
||||
* build on all platforms with curl (as a binary), wrt https://gitlab.haskell.org/haskell/ghcup-hs/issues/6
|
||||
* Fix unlinking of ghc symlinks after new installation, wrt https://gitlab.haskell.org/haskell/ghcup-hs/issues/7
|
||||
|
||||
## 0.1.3 -- 2020-04-15
|
||||
|
||||
* Fix lesser bug when skipping ghcup update
|
||||
|
||||
## 0.1.2 -- 2020-04-15
|
||||
|
||||
* Fix bug when removing the set GHC version
|
||||
* Fix use of undocumented `GHCUP_INSTALL_BASE_PREFIX` variable
|
||||
* skip upgrade if ghcup is already latest version
|
||||
|
||||
## 0.1.1 -- 2020-04-15
|
||||
|
||||
* fix awful fdopendir bug on mac bug by updating hpath-posix
|
||||
|
||||
## 0.1.0
|
||||
|
||||
* First version. Released on an unsuspecting world.
|
||||
|
||||
42
README.md
@@ -1,37 +1,13 @@
|
||||
# ghcup
|
||||
## The GHCup Haskell installer
|
||||
|
||||
A rewrite of ghcup in haskell.
|
||||
[](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>
|
||||
|
||||
## TODO
|
||||
GHCup is an installer for the general purpose language [Haskell](https://www.haskell.org/).
|
||||
|
||||
* create static ghcup binaries
|
||||
* adjust url in GHCupDownloads
|
||||
* add print-system-reqs command
|
||||
Visit the [documentation](https://www.haskell.org/ghcup/) for installation instructions.
|
||||
|
||||
## Motivation
|
||||
|
||||
Maintenance problems:
|
||||
|
||||
* platform incompatibilities regularly causing breaking bugs:
|
||||
* [Mktemp not working properly on macOS](https://gitlab.haskell.org/haskell/ghcup/issues/130)
|
||||
* [ln: illegal option -- T on macOS Catalina](https://gitlab.haskell.org/haskell/ghcup/issues/123)
|
||||
* [Wrong tar flag on darwin](https://gitlab.haskell.org/haskell/ghcup/issues/119))
|
||||
* refactoring being difficult due to POSIX sh
|
||||
|
||||
Benefits of a rewrite:
|
||||
|
||||
* Features such as installing [release candidates](https://gitlab.haskell.org/haskell/ghcup/issues/94) or [HEAD builds](https://gitlab.haskell.org/haskell/ghcup/issues/65) can be more conveniently implemented in a rewrite
|
||||
* Refactoring will be easier
|
||||
* Better tool support (such as linting the downloads file)
|
||||
* saner downloads file format (such as JSON)
|
||||
|
||||
Downsides:
|
||||
|
||||
* building static binaries for all platforms (and possibly causing SSL/DNS problems)
|
||||
* still bootstrapping those binaries via a POSIX sh script
|
||||
|
||||
## Goals
|
||||
|
||||
* Correct low-level code
|
||||
* Good exception handling
|
||||
* Cleaner user interface
|
||||
If you're looking for the metadata YAML files, see here: [https://github.com/haskell/ghcup-metadata](https://github.com/haskell/ghcup-metadata)
|
||||
|
||||
@@ -1,164 +0,0 @@
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE TypeApplications #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE TemplateHaskell #-}
|
||||
{-# LANGUAGE QuasiQuotes #-}
|
||||
{-# LANGUAGE DuplicateRecordFields #-}
|
||||
|
||||
|
||||
module Main where
|
||||
|
||||
import GHCup.Types.JSON ( )
|
||||
import GHCup.Utils.Logger
|
||||
import GHCupDownloads
|
||||
|
||||
import Data.Aeson ( eitherDecode )
|
||||
import Data.Aeson.Encode.Pretty
|
||||
import Data.Semigroup ( (<>) )
|
||||
import Options.Applicative hiding ( style )
|
||||
import System.Console.Pretty
|
||||
import System.Exit
|
||||
import System.IO ( stdout )
|
||||
import Validate
|
||||
|
||||
import qualified Data.ByteString as B
|
||||
import qualified Data.ByteString.Lazy as L
|
||||
|
||||
|
||||
data Options = Options
|
||||
{ optCommand :: Command
|
||||
}
|
||||
|
||||
data Command = GenJSON GenJSONOpts
|
||||
| ValidateJSON ValidateJSONOpts
|
||||
| ValidateTarballs ValidateJSONOpts
|
||||
|
||||
data Output
|
||||
= FileOutput FilePath -- optsparse-applicative doesn't handle ByteString correctly anyway
|
||||
| StdOutput
|
||||
|
||||
fileOutput :: Parser Output
|
||||
fileOutput =
|
||||
FileOutput
|
||||
<$> (strOption
|
||||
(long "file" <> short 'f' <> metavar "FILENAME" <> help
|
||||
"Output to a file"
|
||||
)
|
||||
)
|
||||
|
||||
stdOutput :: Parser Output
|
||||
stdOutput = flag'
|
||||
StdOutput
|
||||
(short 'o' <> long "stdout" <> help "Print to stdout (default)")
|
||||
|
||||
outputP :: Parser Output
|
||||
outputP = fileOutput <|> stdOutput
|
||||
|
||||
|
||||
data GenJSONOpts = GenJSONOpts
|
||||
{ output :: Maybe Output
|
||||
}
|
||||
|
||||
genJSONOpts :: Parser GenJSONOpts
|
||||
genJSONOpts = GenJSONOpts <$> optional outputP
|
||||
|
||||
|
||||
data Input
|
||||
= FileInput FilePath -- optsparse-applicative doesn't handle ByteString correctly anyway
|
||||
| StdInput
|
||||
|
||||
fileInput :: Parser Input
|
||||
fileInput =
|
||||
FileInput
|
||||
<$> (strOption
|
||||
(long "file" <> short 'f' <> metavar "FILENAME" <> help
|
||||
"Input file to validate"
|
||||
)
|
||||
)
|
||||
|
||||
stdInput :: Parser Input
|
||||
stdInput = flag'
|
||||
StdInput
|
||||
(short 'i' <> long "stdin" <> help "Validate from stdin (default)")
|
||||
|
||||
inputP :: Parser Input
|
||||
inputP = fileInput <|> stdInput
|
||||
|
||||
data ValidateJSONOpts = ValidateJSONOpts
|
||||
{ input :: Maybe Input
|
||||
}
|
||||
|
||||
validateJSONOpts :: Parser ValidateJSONOpts
|
||||
validateJSONOpts = ValidateJSONOpts <$> optional inputP
|
||||
|
||||
opts :: Parser Options
|
||||
opts = Options <$> com
|
||||
|
||||
com :: Parser Command
|
||||
com = subparser
|
||||
( (command
|
||||
"gen"
|
||||
( GenJSON
|
||||
<$> (info (genJSONOpts <**> helper)
|
||||
(progDesc "Generate the json downloads file")
|
||||
)
|
||||
)
|
||||
)
|
||||
<> (command
|
||||
"check"
|
||||
( ValidateJSON
|
||||
<$> (info (validateJSONOpts <**> helper)
|
||||
(progDesc "Validate the JSON")
|
||||
)
|
||||
)
|
||||
)
|
||||
<> (command
|
||||
"check-tarballs"
|
||||
( ValidateTarballs
|
||||
<$> (info
|
||||
(validateJSONOpts <**> helper)
|
||||
(progDesc "Validate all tarballs (download and checksum)")
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
|
||||
main :: IO ()
|
||||
main = do
|
||||
customExecParser (prefs showHelpOnError) (info (opts <**> helper) idm)
|
||||
>>= \Options {..} -> case optCommand of
|
||||
GenJSON gopts -> do
|
||||
let
|
||||
bs = encodePretty' (defConfig { confIndent = Spaces 2 })
|
||||
ghcupDownloads
|
||||
case gopts of
|
||||
GenJSONOpts { output = Nothing } -> L.hPutStr stdout bs
|
||||
GenJSONOpts { output = Just StdOutput } -> L.hPutStr stdout bs
|
||||
GenJSONOpts { output = Just (FileOutput file) } ->
|
||||
L.writeFile file bs
|
||||
ValidateJSON vopts -> case vopts of
|
||||
ValidateJSONOpts { input = Nothing } ->
|
||||
L.getContents >>= valAndExit validate
|
||||
ValidateJSONOpts { input = Just StdInput } ->
|
||||
L.getContents >>= valAndExit validate
|
||||
ValidateJSONOpts { input = Just (FileInput file) } ->
|
||||
L.readFile file >>= valAndExit validate
|
||||
ValidateTarballs vopts -> case vopts of
|
||||
ValidateJSONOpts { input = Nothing } ->
|
||||
L.getContents >>= valAndExit validateTarballs
|
||||
ValidateJSONOpts { input = Just StdInput } ->
|
||||
L.getContents >>= valAndExit validateTarballs
|
||||
ValidateJSONOpts { input = Just (FileInput file) } ->
|
||||
L.readFile file >>= valAndExit validateTarballs
|
||||
pure ()
|
||||
|
||||
where
|
||||
valAndExit f contents = do
|
||||
av <- case eitherDecode contents of
|
||||
Right r -> pure r
|
||||
Left e -> die (color Red $ show e)
|
||||
myLoggerT (LoggerConfig True (B.hPut stdout) (\_ -> pure ())) (f av)
|
||||
>>= exitWith
|
||||
|
||||
@@ -1,181 +0,0 @@
|
||||
{-# LANGUAGE TemplateHaskell #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE QuasiQuotes #-}
|
||||
|
||||
module Validate where
|
||||
|
||||
import GHCup
|
||||
import GHCup.Download
|
||||
import GHCup.Types
|
||||
import GHCup.Utils.Logger
|
||||
|
||||
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 )
|
||||
import Control.Monad.Trans.Resource ( runResourceT
|
||||
, MonadUnliftIO
|
||||
)
|
||||
import Data.IORef
|
||||
import Data.List
|
||||
import Data.String.Interpolate
|
||||
import Data.Versions
|
||||
import Haskus.Utils.Variant.Excepts
|
||||
import Optics
|
||||
import System.Exit
|
||||
import System.IO
|
||||
|
||||
import qualified Data.ByteString as B
|
||||
import qualified Data.Map.Strict as M
|
||||
|
||||
|
||||
data ValidationError = InternalError String
|
||||
deriving Show
|
||||
|
||||
instance Exception ValidationError
|
||||
|
||||
|
||||
addError :: (MonadReader (IORef Int) m, MonadIO m, Monad m) => m ()
|
||||
addError = do
|
||||
ref <- ask
|
||||
liftIO $ modifyIORef ref (+ 1)
|
||||
|
||||
|
||||
validate :: (Monad m, MonadLogger m, MonadThrow m, MonadIO m, MonadUnliftIO m)
|
||||
=> GHCupDownloads
|
||||
-> m ExitCode
|
||||
validate dls = do
|
||||
ref <- liftIO $ newIORef 0
|
||||
|
||||
-- * verify binary downloads * --
|
||||
flip runReaderT ref $ do
|
||||
-- unique tags
|
||||
forM_ (M.toList dls) $ \(t, _) -> checkUniqueTags t
|
||||
|
||||
-- required platforms
|
||||
forM_ (M.toList dls) $ \(t, versions) ->
|
||||
forM_ (M.toList versions) $ \(v, vi) ->
|
||||
forM_ (M.toList $ _viArch vi) $ \(arch, pspecs) -> do
|
||||
checkHasRequiredPlatforms t v arch (M.keys pspecs)
|
||||
|
||||
checkGHCisSemver
|
||||
forM_ (M.toList dls) $ \(t, _) -> checkMandatoryTags t
|
||||
|
||||
-- exit
|
||||
e <- liftIO $ readIORef ref
|
||||
if e > 0
|
||||
then pure $ ExitFailure e
|
||||
else do
|
||||
lift $ $(logInfo) [i|All good|]
|
||||
pure ExitSuccess
|
||||
where
|
||||
checkHasRequiredPlatforms t v arch pspecs = do
|
||||
let v' = prettyVer v
|
||||
when (not $ any (== Linux UnknownLinux) pspecs) $ do
|
||||
lift $ $(logError)
|
||||
[i|Linux UnknownLinux missing for for #{t} #{v'} #{arch}|]
|
||||
addError
|
||||
when ((not $ any (== Darwin) pspecs) && arch == A_64) $ do
|
||||
lift $ $(logError) [i|Darwin missing for #{t} #{v'} #{arch}|]
|
||||
addError
|
||||
when ((not $ any (== FreeBSD) pspecs) && arch == A_64) $ lift $ $(logWarn)
|
||||
[i|FreeBSD missing for #{t} #{v'} #{arch}|]
|
||||
|
||||
checkUniqueTags tool = do
|
||||
let allTags = join $ fmap snd $ availableToolVersions dls tool
|
||||
let nonUnique =
|
||||
fmap fst
|
||||
. filter (\(_, b) -> not b)
|
||||
<$> ( mapM
|
||||
(\case
|
||||
[] -> throwM $ InternalError "empty inner list"
|
||||
(t : ts) ->
|
||||
pure $ (t, ) $ if isUniqueTag t then ts == [] else True
|
||||
)
|
||||
. group
|
||||
. sort
|
||||
$ allTags
|
||||
)
|
||||
case join nonUnique of
|
||||
[] -> pure ()
|
||||
xs -> do
|
||||
lift $ $(logError) [i|Tags not unique for #{tool}: #{xs}|]
|
||||
addError
|
||||
where
|
||||
isUniqueTag Latest = True
|
||||
isUniqueTag Recommended = True
|
||||
|
||||
checkGHCisSemver = do
|
||||
let ghcVers = toListOf (ix GHC % to M.keys % folded) dls
|
||||
forM_ ghcVers $ \v -> case semver (prettyVer v) of
|
||||
Left _ -> do
|
||||
lift $ $(logError) [i|GHC version #{v} is not valid semver|]
|
||||
addError
|
||||
Right _ -> pure ()
|
||||
|
||||
-- a tool must have at least one of each mandatory tags
|
||||
checkMandatoryTags tool = do
|
||||
let allTags = join $ fmap snd $ availableToolVersions dls tool
|
||||
forM_ [Latest, Recommended] $ \t -> case elem t allTags of
|
||||
False -> do
|
||||
lift $ $(logError) [i|Tag #{t} missing from #{tool}|]
|
||||
addError
|
||||
True -> pure ()
|
||||
|
||||
|
||||
validateTarballs :: ( Monad m
|
||||
, MonadLogger m
|
||||
, MonadThrow m
|
||||
, MonadIO m
|
||||
, MonadUnliftIO m
|
||||
, MonadMask m
|
||||
)
|
||||
=> GHCupDownloads
|
||||
-> m ExitCode
|
||||
validateTarballs dls = do
|
||||
ref <- liftIO $ newIORef 0
|
||||
|
||||
flip runReaderT ref $ do
|
||||
-- download/verify all binary tarballs
|
||||
let
|
||||
dlbis = nub $ join $ (M.elems dls) <&> \versions ->
|
||||
join $ (M.elems versions) <&> \vi ->
|
||||
join $ (M.elems $ _viArch vi) <&> \pspecs ->
|
||||
join $ (M.elems pspecs) <&> \pverspecs -> (M.elems pverspecs)
|
||||
forM_ dlbis $ downloadAll
|
||||
|
||||
let dlsrc = nub $ join $ (M.elems dls) <&> \versions ->
|
||||
join $ (M.elems versions) <&> maybe [] (: []) . _viSourceDL
|
||||
forM_ dlsrc $ downloadAll
|
||||
|
||||
-- exit
|
||||
e <- liftIO $ readIORef ref
|
||||
if e > 0
|
||||
then pure $ ExitFailure e
|
||||
else do
|
||||
lift $ $(logInfo) [i|All good|]
|
||||
pure ExitSuccess
|
||||
|
||||
where
|
||||
downloadAll dli = do
|
||||
let settings = Settings True GHCupURL False
|
||||
let runLogger = myLoggerT LoggerConfig { lcPrintDebug = True
|
||||
, colorOutter = B.hPut stderr
|
||||
, rawOutter = (\_ -> pure ())
|
||||
}
|
||||
|
||||
r <-
|
||||
runLogger
|
||||
. flip runReaderT settings
|
||||
. runResourceT
|
||||
. runE
|
||||
$ downloadCached dli Nothing
|
||||
case r of
|
||||
VRight _ -> pure ()
|
||||
VLeft e -> do
|
||||
lift $ $(logError)
|
||||
[i|Could not download (or verify hash) of #{dli}, Error was: #{e}|]
|
||||
addError
|
||||
620
app/ghcup/BrickMain.hs
Normal file
@@ -0,0 +1,620 @@
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE TypeApplications #-}
|
||||
{-# LANGUAGE RankNTypes #-}
|
||||
|
||||
module BrickMain where
|
||||
|
||||
import GHCup
|
||||
import GHCup.Download
|
||||
import GHCup.Errors
|
||||
import GHCup.Types.Optics ( getDirs )
|
||||
import GHCup.Types hiding ( LeanAppState(..) )
|
||||
import GHCup.Utils
|
||||
import GHCup.Logger
|
||||
import GHCup.Prelude ( decUTF8Safe )
|
||||
import GHCup.System.Process
|
||||
|
||||
import Brick
|
||||
import Brick.Widgets.Border
|
||||
import Brick.Widgets.Border.Style
|
||||
import Brick.Widgets.Center
|
||||
import Brick.Widgets.List ( listSelectedFocusedAttr
|
||||
, listSelectedAttr
|
||||
, listAttr
|
||||
)
|
||||
import Codec.Archive
|
||||
import Control.Exception.Safe
|
||||
#if !MIN_VERSION_base(4,13,0)
|
||||
import Control.Monad.Fail ( MonadFail )
|
||||
#endif
|
||||
import Control.Monad.Reader
|
||||
import Control.Monad.Trans.Except
|
||||
import Control.Monad.Trans.Resource
|
||||
import Data.Bool
|
||||
import Data.Functor
|
||||
import Data.List
|
||||
import Data.Maybe
|
||||
import Data.IORef
|
||||
import Data.Vector ( Vector
|
||||
, (!?)
|
||||
)
|
||||
import Data.Versions hiding ( str )
|
||||
import Haskus.Utils.Variant.Excepts
|
||||
import Prelude hiding ( appendFile )
|
||||
import System.Directory ( canonicalizePath )
|
||||
import System.FilePath
|
||||
import System.Exit
|
||||
import System.IO.Unsafe
|
||||
import Text.PrettyPrint.HughesPJClass ( prettyShow )
|
||||
import URI.ByteString
|
||||
|
||||
import qualified Data.Text as T
|
||||
import qualified Graphics.Vty as Vty
|
||||
import qualified Data.Vector as V
|
||||
import System.Environment (getExecutablePath)
|
||||
import qualified System.Posix.Process as SPP
|
||||
|
||||
|
||||
hiddenTools :: [Tool]
|
||||
hiddenTools = []
|
||||
|
||||
|
||||
data BrickData = BrickData
|
||||
{ lr :: [ListResult]
|
||||
}
|
||||
deriving Show
|
||||
|
||||
data BrickSettings = BrickSettings
|
||||
{ showAllVersions :: Bool
|
||||
, showAllTools :: Bool
|
||||
}
|
||||
deriving Show
|
||||
|
||||
data BrickInternalState = BrickInternalState
|
||||
{ clr :: Vector ListResult
|
||||
, ix :: Int
|
||||
}
|
||||
deriving Show
|
||||
|
||||
data BrickState = BrickState
|
||||
{ appData :: BrickData
|
||||
, appSettings :: BrickSettings
|
||||
, appState :: BrickInternalState
|
||||
, appKeys :: KeyBindings
|
||||
}
|
||||
deriving Show
|
||||
|
||||
|
||||
keyHandlers :: KeyBindings
|
||||
-> [ ( Vty.Key
|
||||
, BrickSettings -> String
|
||||
, BrickState -> EventM n (Next BrickState)
|
||||
)
|
||||
]
|
||||
keyHandlers KeyBindings {..} =
|
||||
[ (bQuit, const "Quit" , halt)
|
||||
, (bInstall, const "Install" , withIOAction install')
|
||||
, (bUninstall, const "Uninstall", withIOAction del')
|
||||
, (bSet, const "Set" , withIOAction ((liftIO .) . set'))
|
||||
, (bChangelog, const "ChangeLog", withIOAction changelog')
|
||||
, ( bShowAllVersions
|
||||
, \BrickSettings {..} ->
|
||||
if showAllVersions then "Don't show all versions" else "Show all versions"
|
||||
, hideShowHandler (not . showAllVersions) showAllTools
|
||||
)
|
||||
, ( bShowAllTools
|
||||
, \BrickSettings {..} ->
|
||||
if showAllTools then "Don't show all tools" else "Show all tools"
|
||||
, hideShowHandler showAllVersions (not . showAllTools)
|
||||
)
|
||||
, (bUp, const "Up", \BrickState {..} -> continue BrickState{ appState = moveCursor 1 appState Up, .. })
|
||||
, (bDown, const "Down", \BrickState {..} -> continue BrickState{ appState = moveCursor 1 appState Down, .. })
|
||||
]
|
||||
where
|
||||
hideShowHandler f p BrickState{..} =
|
||||
let newAppSettings = appSettings { showAllVersions = f appSettings , showAllTools = p appSettings }
|
||||
newInternalState = constructList appData newAppSettings (Just appState)
|
||||
in continue (BrickState appData newAppSettings newInternalState appKeys)
|
||||
|
||||
|
||||
showKey :: Vty.Key -> String
|
||||
showKey (Vty.KChar c) = [c]
|
||||
showKey Vty.KUp = "↑"
|
||||
showKey Vty.KDown = "↓"
|
||||
showKey key = tail (show key)
|
||||
|
||||
|
||||
ui :: AttrMap -> BrickState -> Widget String
|
||||
ui dimAttrs BrickState{ appSettings = as@BrickSettings{}, ..}
|
||||
= padBottom Max
|
||||
( withBorderStyle unicode
|
||||
$ borderWithLabel (str "GHCup")
|
||||
(center (header <=> hBorder <=> renderList' appState))
|
||||
)
|
||||
<=> footer
|
||||
|
||||
where
|
||||
footer =
|
||||
withAttr "help"
|
||||
. txtWrap
|
||||
. T.pack
|
||||
. foldr1 (\x y -> x <> " " <> y)
|
||||
. fmap (\(key, s, _) -> showKey key <> ":" <> s as)
|
||||
$ keyHandlers appKeys
|
||||
header =
|
||||
minHSize 2 emptyWidget
|
||||
<+> padLeft (Pad 2) (minHSize 6 $ str "Tool")
|
||||
<+> minHSize 15 (str "Version")
|
||||
<+> padLeft (Pad 1) (minHSize 25 $ str "Tags")
|
||||
<+> padLeft (Pad 5) (str "Notes")
|
||||
renderList' = withDefAttr listAttr . drawListElements renderItem True
|
||||
renderItem _ b listResult@ListResult{..} =
|
||||
let marks = if
|
||||
| lSet -> (withAttr "set" $ str "✔✔")
|
||||
| lInstalled -> (withAttr "installed" $ str "✓ ")
|
||||
| otherwise -> (withAttr "not-installed" $ str "✗ ")
|
||||
ver = case lCross of
|
||||
Nothing -> T.unpack . prettyVer $ lVer
|
||||
Just c -> T.unpack (c <> "-" <> prettyVer lVer)
|
||||
dim
|
||||
| lNoBindist && not lInstalled
|
||||
&& not b -- TODO: overloading dim and active ignores active
|
||||
-- so we hack around it here
|
||||
= updateAttrMap (const dimAttrs) . withAttr "no-bindist"
|
||||
| otherwise = id
|
||||
hooray
|
||||
| elem Latest lTag && not lInstalled =
|
||||
withAttr "hooray"
|
||||
| otherwise = id
|
||||
active = if b then putCursor "GHCup" (Location (0,0)) . forceAttr "active" else id
|
||||
in hooray $ active $ dim
|
||||
( marks
|
||||
<+> padLeft (Pad 2)
|
||||
( minHSize 6
|
||||
(printTool lTool)
|
||||
)
|
||||
<+> minHSize 15 (str ver)
|
||||
<+> (let l = catMaybes . fmap printTag $ sort lTag
|
||||
in padLeft (Pad 1) $ minHSize 25 $ if null l
|
||||
then emptyWidget
|
||||
else foldr1 (\x y -> x <+> str "," <+> y) l
|
||||
)
|
||||
<+> padLeft (Pad 5)
|
||||
( let notes = printNotes listResult
|
||||
in if null notes
|
||||
then emptyWidget
|
||||
else foldr1 (\x y -> x <+> str "," <+> y) notes
|
||||
)
|
||||
<+> vLimit 1 (fill ' ')
|
||||
)
|
||||
|
||||
printTag Recommended = Just $ withAttr "recommended" $ str "recommended"
|
||||
printTag Latest = Just $ withAttr "latest" $ str "latest"
|
||||
printTag Prerelease = Just $ withAttr "prerelease" $ str "prerelease"
|
||||
printTag (Base pvp'') = Just $ str ("base-" ++ T.unpack (prettyPVP pvp''))
|
||||
printTag Old = Nothing
|
||||
printTag (UnknownTag t) = Just $ str t
|
||||
|
||||
printTool Cabal = str "cabal"
|
||||
printTool GHC = str "GHC"
|
||||
printTool GHCup = str "GHCup"
|
||||
printTool HLS = str "HLS"
|
||||
printTool Stack = str "Stack"
|
||||
|
||||
printNotes ListResult {..} =
|
||||
(if hlsPowered then [withAttr "hls-powered" $ str "hls-powered"] else mempty
|
||||
)
|
||||
++ (if fromSrc then [withAttr "compiled" $ str "compiled"] else mempty)
|
||||
++ (if lStray then [withAttr "stray" $ str "stray"] else mempty)
|
||||
|
||||
-- | Draws the list elements.
|
||||
--
|
||||
-- Evaluates the underlying container up to, and a bit beyond, the
|
||||
-- selected element. The exact amount depends on available height
|
||||
-- for drawing and 'listItemHeight'. At most, it will evaluate up to
|
||||
-- element @(i + h + 1)@ where @i@ is the selected index and @h@ is the
|
||||
-- available height.
|
||||
drawListElements :: (Int -> Bool -> ListResult -> Widget String)
|
||||
-> Bool
|
||||
-> BrickInternalState
|
||||
-> Widget String
|
||||
drawListElements drawElem foc is@(BrickInternalState clr _) =
|
||||
Widget Greedy Greedy $
|
||||
let
|
||||
es = clr
|
||||
listSelected = fmap fst $ listSelectedElement' is
|
||||
|
||||
drawnElements = flip V.imap es $ \i' e ->
|
||||
let addSeparator w = case es !? (i' - 1) of
|
||||
Just e' | lTool e' /= lTool e ->
|
||||
hBorder <=> w
|
||||
_ -> w
|
||||
|
||||
isSelected = Just i' == listSelected
|
||||
elemWidget = drawElem i' isSelected e
|
||||
selItemAttr = if foc
|
||||
then withDefAttr listSelectedFocusedAttr
|
||||
else withDefAttr listSelectedAttr
|
||||
makeVisible = if isSelected then visible . selItemAttr else id
|
||||
in addSeparator $ makeVisible elemWidget
|
||||
|
||||
in render
|
||||
$ viewport "GHCup" Vertical
|
||||
$ vBox
|
||||
$ V.toList drawnElements
|
||||
|
||||
|
||||
minHSize :: Int -> Widget n -> Widget n
|
||||
minHSize s' = hLimit s' . vLimit 1 . (<+> fill ' ')
|
||||
|
||||
|
||||
app :: AttrMap -> AttrMap -> App BrickState e String
|
||||
app attrs dimAttrs =
|
||||
App { appDraw = \st -> [ui dimAttrs st]
|
||||
, appHandleEvent = eventHandler
|
||||
, appStartEvent = return
|
||||
, appAttrMap = const attrs
|
||||
, appChooseCursor = showFirstCursor
|
||||
}
|
||||
|
||||
defaultAttributes :: Bool -> AttrMap
|
||||
defaultAttributes no_color = attrMap
|
||||
Vty.defAttr
|
||||
[ ("active" , Vty.defAttr `withBackColor` Vty.blue)
|
||||
, ("not-installed", Vty.defAttr `withForeColor` Vty.red)
|
||||
, ("set" , Vty.defAttr `withForeColor` Vty.green)
|
||||
, ("installed" , Vty.defAttr `withForeColor` Vty.green)
|
||||
, ("recommended" , Vty.defAttr `withForeColor` Vty.green)
|
||||
, ("hls-powered" , Vty.defAttr `withForeColor` Vty.green)
|
||||
, ("latest" , Vty.defAttr `withForeColor` Vty.yellow)
|
||||
, ("prerelease" , Vty.defAttr `withForeColor` Vty.red)
|
||||
, ("compiled" , Vty.defAttr `withForeColor` Vty.blue)
|
||||
, ("stray" , Vty.defAttr `withForeColor` Vty.blue)
|
||||
, ("help" , Vty.defAttr `withStyle` Vty.italic)
|
||||
, ("hooray" , Vty.defAttr `withForeColor` Vty.brightWhite)
|
||||
]
|
||||
where
|
||||
withForeColor | no_color = const
|
||||
| otherwise = Vty.withForeColor
|
||||
|
||||
withBackColor | no_color = \attr _ -> attr `Vty.withStyle` Vty.reverseVideo
|
||||
| otherwise = Vty.withBackColor
|
||||
|
||||
withStyle = Vty.withStyle
|
||||
|
||||
dimAttributes :: Bool -> AttrMap
|
||||
dimAttributes no_color = attrMap
|
||||
(Vty.defAttr `Vty.withStyle` Vty.dim)
|
||||
[ ("active" , Vty.defAttr `withBackColor` Vty.blue) -- has no effect ??
|
||||
, ("no-bindist", Vty.defAttr `Vty.withStyle` Vty.dim)
|
||||
]
|
||||
where
|
||||
withBackColor | no_color = \attr _ -> attr `Vty.withStyle` Vty.reverseVideo
|
||||
| otherwise = Vty.withBackColor
|
||||
|
||||
eventHandler :: BrickState -> BrickEvent n e -> EventM n (Next BrickState)
|
||||
eventHandler st@BrickState{..} ev = do
|
||||
AppState { keyBindings = kb } <- liftIO $ readIORef settings'
|
||||
case ev of
|
||||
(MouseDown _ Vty.BScrollUp _ _) ->
|
||||
continue (BrickState { appState = moveCursor 1 appState Up, .. })
|
||||
(MouseDown _ Vty.BScrollDown _ _) ->
|
||||
continue (BrickState { appState = moveCursor 1 appState Down, .. })
|
||||
(VtyEvent (Vty.EvResize _ _)) -> continue st
|
||||
(VtyEvent (Vty.EvKey Vty.KUp _)) ->
|
||||
continue BrickState{ appState = moveCursor 1 appState Up, .. }
|
||||
(VtyEvent (Vty.EvKey Vty.KDown _)) ->
|
||||
continue BrickState{ appState = moveCursor 1 appState Down, .. }
|
||||
(VtyEvent (Vty.EvKey key _)) ->
|
||||
case find (\(key', _, _) -> key' == key) (keyHandlers kb) of
|
||||
Nothing -> continue st
|
||||
Just (_, _, handler) -> handler st
|
||||
_ -> continue st
|
||||
|
||||
|
||||
moveCursor :: Int -> BrickInternalState -> Direction -> BrickInternalState
|
||||
moveCursor steps ais@BrickInternalState{..} direction =
|
||||
let newIx = if direction == Down then ix + steps else ix - steps
|
||||
in case clr !? newIx of
|
||||
Just _ -> BrickInternalState { ix = newIx, .. }
|
||||
Nothing -> ais
|
||||
|
||||
|
||||
-- | Suspend the current UI and run an IO action in terminal. If the
|
||||
-- IO action returns a Left value, then it's thrown as userError.
|
||||
withIOAction :: (BrickState
|
||||
-> (Int, ListResult)
|
||||
-> ReaderT AppState IO (Either String a))
|
||||
-> BrickState
|
||||
-> EventM n (Next BrickState)
|
||||
withIOAction action as = case listSelectedElement' (appState as) of
|
||||
Nothing -> continue as
|
||||
Just (ix, e) -> do
|
||||
suspendAndResume $ do
|
||||
settings <- readIORef settings'
|
||||
flip runReaderT settings $ action as (ix, e) >>= \case
|
||||
Left err -> liftIO $ putStrLn ("Error: " <> err)
|
||||
Right _ -> liftIO $ putStrLn "Success"
|
||||
getAppData Nothing >>= \case
|
||||
Right data' -> do
|
||||
putStrLn "Press enter to continue"
|
||||
_ <- getLine
|
||||
pure (updateList data' as)
|
||||
Left err -> throwIO $ userError err
|
||||
|
||||
|
||||
-- | Update app data and list internal state based on new evidence.
|
||||
-- This synchronises @BrickInternalState@ with @BrickData@
|
||||
-- and @BrickSettings@.
|
||||
updateList :: BrickData -> BrickState -> BrickState
|
||||
updateList appD BrickState{..} =
|
||||
let newInternalState = constructList appD appSettings (Just appState)
|
||||
in BrickState { appState = newInternalState
|
||||
, appData = appD
|
||||
, appSettings = appSettings
|
||||
, appKeys = appKeys
|
||||
}
|
||||
|
||||
|
||||
constructList :: BrickData
|
||||
-> BrickSettings
|
||||
-> Maybe BrickInternalState
|
||||
-> BrickInternalState
|
||||
constructList appD appSettings =
|
||||
replaceLR (filterVisible (showAllVersions appSettings)
|
||||
(showAllTools appSettings))
|
||||
(lr appD)
|
||||
|
||||
listSelectedElement' :: BrickInternalState -> Maybe (Int, ListResult)
|
||||
listSelectedElement' BrickInternalState{..} = fmap (ix, ) $ clr !? ix
|
||||
|
||||
|
||||
selectLatest :: Vector ListResult -> Int
|
||||
selectLatest = fromMaybe 0 . V.findIndex (\ListResult {..} -> lTool == GHC && Latest `elem` lTag)
|
||||
|
||||
|
||||
-- | Replace the @appState@ or construct it based on a filter function
|
||||
-- and a new @[ListResult]@ evidence.
|
||||
-- When passed an existing @appState@, tries to keep the selected element.
|
||||
replaceLR :: (ListResult -> Bool)
|
||||
-> [ListResult]
|
||||
-> Maybe BrickInternalState
|
||||
-> BrickInternalState
|
||||
replaceLR filterF lr s =
|
||||
let oldElem = s >>= listSelectedElement'
|
||||
newVec = V.fromList . filter filterF $ lr
|
||||
newSelected =
|
||||
case oldElem >>= \(_, oldE) -> V.findIndex (toolEqual oldE) newVec of
|
||||
Just ix -> ix
|
||||
Nothing -> selectLatest newVec
|
||||
in BrickInternalState newVec newSelected
|
||||
where
|
||||
toolEqual e1 e2 =
|
||||
lTool e1 == lTool e2 && lVer e1 == lVer e2 && lCross e1 == lCross e2
|
||||
|
||||
|
||||
filterVisible :: Bool -> Bool -> ListResult -> Bool
|
||||
filterVisible v t e | lInstalled e = True
|
||||
| v
|
||||
, not t
|
||||
, lTool e `notElem` hiddenTools = True
|
||||
| not v
|
||||
, t
|
||||
, Old `notElem` lTag e = True
|
||||
| v
|
||||
, t = True
|
||||
| otherwise = (Old `notElem` lTag e) &&
|
||||
(lTool e `notElem` hiddenTools)
|
||||
|
||||
|
||||
install' :: (MonadReader AppState m, MonadIO m, MonadThrow m, MonadFail m, MonadMask m, MonadUnliftIO m)
|
||||
=> BrickState
|
||||
-> (Int, ListResult)
|
||||
-> m (Either String ())
|
||||
install' _ (_, ListResult {..}) = do
|
||||
AppState { ghcupInfo = GHCupInfo { _ghcupDownloads = dls }} <- ask
|
||||
|
||||
let run =
|
||||
runResourceT
|
||||
. runE
|
||||
@'[ AlreadyInstalled
|
||||
, ArchiveResult
|
||||
, UnknownArchive
|
||||
, FileDoesNotExistError
|
||||
, CopyError
|
||||
, NoDownload
|
||||
, NotInstalled
|
||||
, BuildFailed
|
||||
, TagNotFound
|
||||
, DigestError
|
||||
, GPGError
|
||||
, DownloadFailed
|
||||
, DirNotEmpty
|
||||
, NoUpdate
|
||||
, TarDirDoesNotExist
|
||||
, FileAlreadyExistsError
|
||||
, ProcessError
|
||||
]
|
||||
|
||||
run (do
|
||||
ce <- liftIO $ fmap (either (const Nothing) Just) $
|
||||
try @_ @SomeException $ getExecutablePath >>= canonicalizePath
|
||||
dirs <- lift getDirs
|
||||
case lTool of
|
||||
GHC -> do
|
||||
let vi = getVersionInfo lVer GHC dls
|
||||
liftE $ installGHCBin lVer Nothing False $> (vi, dirs, ce)
|
||||
Cabal -> do
|
||||
let vi = getVersionInfo lVer Cabal dls
|
||||
liftE $ installCabalBin lVer Nothing False $> (vi, dirs, ce)
|
||||
GHCup -> do
|
||||
let vi = snd <$> getLatest dls GHCup
|
||||
liftE $ upgradeGHCup Nothing False $> (vi, dirs, ce)
|
||||
HLS -> do
|
||||
let vi = getVersionInfo lVer HLS dls
|
||||
liftE $ installHLSBin lVer Nothing False $> (vi, dirs, ce)
|
||||
Stack -> do
|
||||
let vi = getVersionInfo lVer Stack dls
|
||||
liftE $ installStackBin lVer Nothing False $> (vi, dirs, ce)
|
||||
)
|
||||
>>= \case
|
||||
VRight (vi, Dirs{..}, Just ce) -> do
|
||||
forM_ (_viPostInstall =<< vi) $ \msg -> logInfo msg
|
||||
case lTool of
|
||||
GHCup -> do
|
||||
up <- liftIO $ fmap (either (const Nothing) Just)
|
||||
$ try @_ @SomeException $ canonicalizePath (binDir </> "ghcup" <.> exeExt)
|
||||
when ((normalise <$> up) == Just (normalise ce)) $
|
||||
-- TODO: track cli arguments of previous invocation
|
||||
liftIO $ SPP.executeFile ce False ["tui"] Nothing
|
||||
logInfo "Please restart 'ghcup' for the changes to take effect"
|
||||
_ -> pure ()
|
||||
pure $ Right ()
|
||||
VRight (vi, _, _) -> do
|
||||
forM_ (_viPostInstall =<< vi) $ \msg -> logInfo msg
|
||||
logInfo "Please restart 'ghcup' for the changes to take effect"
|
||||
pure $ Right ()
|
||||
VLeft (V (AlreadyInstalled _ _)) -> pure $ Right ()
|
||||
VLeft (V NoUpdate) -> pure $ Right ()
|
||||
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'
|
||||
|
||||
let run =
|
||||
flip runReaderT settings
|
||||
. runE @'[FileDoesNotExistError , NotInstalled , TagNotFound]
|
||||
|
||||
run (do
|
||||
case lTool of
|
||||
GHC -> liftE $ setGHC (GHCTargetVersion lCross lVer) SetGHCOnly $> ()
|
||||
Cabal -> liftE $ setCabal lVer $> ()
|
||||
HLS -> liftE $ setHLS lVer $> ()
|
||||
Stack -> liftE $ setStack lVer $> ()
|
||||
GHCup -> pure ()
|
||||
)
|
||||
>>= \case
|
||||
VRight _ -> pure $ Right ()
|
||||
VLeft e -> pure $ Left (prettyShow e)
|
||||
|
||||
|
||||
del' :: (MonadReader AppState m, MonadIO m, MonadFail m, MonadMask m, MonadUnliftIO m)
|
||||
=> BrickState
|
||||
-> (Int, ListResult)
|
||||
-> m (Either String ())
|
||||
del' _ (_, ListResult {..}) = do
|
||||
AppState { ghcupInfo = GHCupInfo { _ghcupDownloads = dls }} <- ask
|
||||
|
||||
let run = runE @'[NotInstalled]
|
||||
|
||||
run (do
|
||||
let vi = getVersionInfo lVer lTool dls
|
||||
case lTool of
|
||||
GHC -> liftE $ rmGHCVer (GHCTargetVersion lCross lVer) $> vi
|
||||
Cabal -> liftE $ rmCabalVer lVer $> vi
|
||||
HLS -> liftE $ rmHLSVer lVer $> vi
|
||||
Stack -> liftE $ rmStackVer lVer $> vi
|
||||
GHCup -> pure Nothing
|
||||
)
|
||||
>>= \case
|
||||
VRight vi -> do
|
||||
forM_ (_viPostRemove =<< vi) $ \msg ->
|
||||
logInfo msg
|
||||
pure $ Right ()
|
||||
VLeft e -> pure $ Left (prettyShow e)
|
||||
|
||||
|
||||
changelog' :: (MonadReader AppState m, MonadIO m)
|
||||
=> BrickState
|
||||
-> (Int, ListResult)
|
||||
-> m (Either String ())
|
||||
changelog' _ (_, ListResult {..}) = do
|
||||
AppState { pfreq, ghcupInfo = GHCupInfo { _ghcupDownloads = dls }} <- ask
|
||||
case getChangeLog dls lTool (Left lVer) of
|
||||
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"
|
||||
Linux _ -> "xdg-open"
|
||||
FreeBSD -> "xdg-open"
|
||||
Windows -> "start"
|
||||
exec cmd [T.unpack $ decUTF8Safe $ serializeURIRef' uri] Nothing Nothing >>= \case
|
||||
Right _ -> pure $ Right ()
|
||||
Left e -> pure $ Left $ prettyShow e
|
||||
|
||||
|
||||
settings' :: IORef AppState
|
||||
{-# NOINLINE settings' #-}
|
||||
settings' = unsafePerformIO $ do
|
||||
dirs <- getAllDirs
|
||||
let loggerConfig = LoggerConfig { lcPrintDebug = False
|
||||
, consoleOutter = \_ -> pure ()
|
||||
, fileOutter = \_ -> pure ()
|
||||
, fancyColors = True
|
||||
}
|
||||
newIORef $ AppState defaultSettings
|
||||
dirs
|
||||
defaultKeyBindings
|
||||
(GHCupInfo mempty mempty mempty)
|
||||
(PlatformRequest A_64 Darwin Nothing)
|
||||
loggerConfig
|
||||
|
||||
|
||||
|
||||
brickMain :: AppState
|
||||
-> IO ()
|
||||
brickMain s = do
|
||||
writeIORef settings' s
|
||||
|
||||
eAppData <- getAppData (Just $ ghcupInfo s)
|
||||
case eAppData of
|
||||
Right ad ->
|
||||
defaultMain
|
||||
(app (defaultAttributes (noColor $ settings s)) (dimAttributes (noColor $ settings s)))
|
||||
(BrickState ad
|
||||
defaultAppSettings
|
||||
(constructList ad defaultAppSettings Nothing)
|
||||
(keyBindings (s :: AppState))
|
||||
|
||||
)
|
||||
$> ()
|
||||
Left e -> do
|
||||
flip runReaderT s $ logError $ "Error building app state: " <> T.pack (show e)
|
||||
exitWith $ ExitFailure 2
|
||||
|
||||
|
||||
defaultAppSettings :: BrickSettings
|
||||
defaultAppSettings = BrickSettings { showAllVersions = False, showAllTools = False }
|
||||
|
||||
|
||||
getGHCupInfo :: IO (Either String GHCupInfo)
|
||||
getGHCupInfo = do
|
||||
settings <- readIORef settings'
|
||||
|
||||
r <-
|
||||
flip runReaderT settings
|
||||
. runE @'[DigestError, GPGError, JSONError , DownloadFailed , FileDoesNotExistError]
|
||||
$ liftE getDownloadsF
|
||||
|
||||
case r of
|
||||
VRight a -> pure $ Right a
|
||||
VLeft e -> pure $ Left (prettyShow e)
|
||||
|
||||
|
||||
getAppData :: Maybe GHCupInfo
|
||||
-> IO (Either String BrickData)
|
||||
getAppData mgi = runExceptT $ do
|
||||
r <- ExceptT $ maybe getGHCupInfo (pure . Right) mgi
|
||||
liftIO $ modifyIORef settings' (\s -> s { ghcupInfo = r })
|
||||
settings <- liftIO $ readIORef settings'
|
||||
|
||||
flip runReaderT settings $ do
|
||||
lV <- listVersions Nothing Nothing
|
||||
pure $ BrickData (reverse lV)
|
||||
305
app/ghcup/GHCup/OptParse.hs
Normal file
@@ -0,0 +1,305 @@
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE DuplicateRecordFields #-}
|
||||
|
||||
|
||||
module GHCup.OptParse (
|
||||
module GHCup.OptParse.Common
|
||||
, module GHCup.OptParse.Install
|
||||
, module GHCup.OptParse.Set
|
||||
, module GHCup.OptParse.UnSet
|
||||
, module GHCup.OptParse.Rm
|
||||
, module GHCup.OptParse.Compile
|
||||
, module GHCup.OptParse.Config
|
||||
, module GHCup.OptParse.Whereis
|
||||
, module GHCup.OptParse.List
|
||||
, module GHCup.OptParse.Upgrade
|
||||
, module GHCup.OptParse.ChangeLog
|
||||
, module GHCup.OptParse.Prefetch
|
||||
, module GHCup.OptParse.GC
|
||||
, module GHCup.OptParse.DInfo
|
||||
, module GHCup.OptParse.Nuke
|
||||
, module GHCup.OptParse.ToolRequirements
|
||||
, module GHCup.OptParse
|
||||
) where
|
||||
|
||||
|
||||
import GHCup.OptParse.Common
|
||||
import GHCup.OptParse.Install
|
||||
import GHCup.OptParse.Set
|
||||
import GHCup.OptParse.UnSet
|
||||
import GHCup.OptParse.Rm
|
||||
import GHCup.OptParse.Compile
|
||||
import GHCup.OptParse.Config
|
||||
import GHCup.OptParse.Whereis
|
||||
import GHCup.OptParse.List
|
||||
import GHCup.OptParse.Upgrade
|
||||
import GHCup.OptParse.ChangeLog
|
||||
import GHCup.OptParse.Prefetch
|
||||
import GHCup.OptParse.GC
|
||||
import GHCup.OptParse.DInfo
|
||||
import GHCup.OptParse.ToolRequirements
|
||||
import GHCup.OptParse.Nuke
|
||||
|
||||
import GHCup.Types
|
||||
|
||||
#if !MIN_VERSION_base(4,13,0)
|
||||
import Control.Monad.Fail ( MonadFail )
|
||||
#endif
|
||||
import Control.Monad.Reader
|
||||
import Data.Bifunctor
|
||||
import Data.Either
|
||||
import Data.Functor
|
||||
import Data.Maybe
|
||||
import Options.Applicative hiding ( style )
|
||||
import Options.Applicative.Help.Pretty ( text )
|
||||
import Prelude hiding ( appendFile )
|
||||
import URI.ByteString
|
||||
|
||||
import qualified Data.ByteString.UTF8 as UTF8
|
||||
|
||||
|
||||
|
||||
data Options = Options
|
||||
{
|
||||
-- global options
|
||||
optVerbose :: Maybe Bool
|
||||
, optCache :: Maybe Bool
|
||||
, optMetaCache :: Maybe Integer
|
||||
, optUrlSource :: Maybe URI
|
||||
, optNoVerify :: Maybe Bool
|
||||
, optKeepDirs :: Maybe KeepDirs
|
||||
, optsDownloader :: Maybe Downloader
|
||||
, optNoNetwork :: Maybe Bool
|
||||
, optGpg :: Maybe GPGSetting
|
||||
-- commands
|
||||
, optCommand :: Command
|
||||
}
|
||||
|
||||
data Command
|
||||
= Install (Either InstallCommand InstallOptions)
|
||||
| InstallCabalLegacy InstallOptions
|
||||
| Set (Either SetCommand SetOptions)
|
||||
| UnSet UnsetCommand
|
||||
| List ListOptions
|
||||
| Rm (Either RmCommand RmOptions)
|
||||
| DInfo
|
||||
| Compile CompileCommand
|
||||
| Config ConfigCommand
|
||||
| Whereis WhereisOptions WhereisCommand
|
||||
| Upgrade UpgradeOpts Bool
|
||||
| ToolRequirements
|
||||
| ChangeLog ChangeLogOptions
|
||||
| Nuke
|
||||
#if defined(BRICK)
|
||||
| Interactive
|
||||
#endif
|
||||
| Prefetch PrefetchCommand
|
||||
| GC GCOptions
|
||||
|
||||
|
||||
|
||||
opts :: Parser Options
|
||||
opts =
|
||||
Options
|
||||
<$> invertableSwitch "verbose" 'v' False (help "Enable verbosity (default: disabled)")
|
||||
<*> invertableSwitch "cache" 'c' False (help "Cache downloads in ~/.ghcup/cache (default: disabled)")
|
||||
<*> optional (option auto (long "metadata-caching" <> help "How long the yaml metadata caching interval is (in seconds), 0 to disable" <> internal))
|
||||
<*> optional
|
||||
(option
|
||||
(eitherReader parseUri)
|
||||
( short 's'
|
||||
<> long "url-source"
|
||||
<> metavar "URL"
|
||||
<> help "Alternative ghcup download info url"
|
||||
<> internal
|
||||
)
|
||||
)
|
||||
<*> (fmap . fmap) not (invertableSwitch "verify" 'n' True (help "Disable tarball checksum verification (default: enabled)"))
|
||||
<*> optional (option
|
||||
(eitherReader keepOnParser)
|
||||
( long "keep"
|
||||
<> metavar "<always|errors|never>"
|
||||
<> help
|
||||
"Keep build directories? (default: errors)"
|
||||
<> hidden
|
||||
))
|
||||
<*> optional (option
|
||||
(eitherReader downloaderParser)
|
||||
( long "downloader"
|
||||
#if defined(INTERNAL_DOWNLOADER)
|
||||
<> metavar "<internal|curl|wget>"
|
||||
<> help
|
||||
"Downloader to use (default: internal)"
|
||||
#else
|
||||
<> metavar "<curl|wget>"
|
||||
<> help
|
||||
"Downloader to use (default: curl)"
|
||||
#endif
|
||||
<> hidden
|
||||
))
|
||||
<*> invertableSwitch "offline" 'o' False (help "Don't do any network calls, trying cached assets and failing if missing.")
|
||||
<*> optional (option
|
||||
(eitherReader gpgParser)
|
||||
( long "gpg"
|
||||
<> metavar "<strict|lax|none>"
|
||||
<> help
|
||||
"GPG verification (default: none)"
|
||||
))
|
||||
<*> com
|
||||
where
|
||||
parseUri s' =
|
||||
first show $ parseURI strictURIParserOptions (UTF8.fromString s')
|
||||
|
||||
|
||||
com :: Parser Command
|
||||
com =
|
||||
subparser
|
||||
#if defined(BRICK)
|
||||
( command
|
||||
"tui"
|
||||
( (\_ -> Interactive)
|
||||
<$> info
|
||||
helper
|
||||
( progDesc "Start the interactive GHCup UI"
|
||||
)
|
||||
)
|
||||
<> command
|
||||
#else
|
||||
( command
|
||||
#endif
|
||||
"install"
|
||||
( Install
|
||||
<$> info
|
||||
(installParser <**> helper)
|
||||
( progDesc "Install or update GHC/cabal/HLS/stack"
|
||||
<> footerDoc (Just $ text installToolFooter)
|
||||
)
|
||||
)
|
||||
<> command
|
||||
"set"
|
||||
(info
|
||||
(Set <$> setParser <**> helper)
|
||||
( progDesc "Set currently active GHC/cabal version"
|
||||
<> footerDoc (Just $ text setFooter)
|
||||
)
|
||||
)
|
||||
<> command
|
||||
"unset"
|
||||
(info
|
||||
(UnSet <$> unsetParser <**> helper)
|
||||
( progDesc "Unset currently active GHC/cabal version"
|
||||
<> footerDoc (Just $ text unsetFooter)
|
||||
)
|
||||
)
|
||||
<> command
|
||||
"rm"
|
||||
(info
|
||||
(Rm <$> rmParser <**> helper)
|
||||
( progDesc "Remove a GHC/cabal/HLS/stack version"
|
||||
<> footerDoc (Just $ text rmFooter)
|
||||
)
|
||||
)
|
||||
|
||||
<> command
|
||||
"list"
|
||||
(info (List <$> listOpts <**> helper)
|
||||
(progDesc "Show available GHCs and other tools")
|
||||
)
|
||||
<> command
|
||||
"upgrade"
|
||||
(info
|
||||
( (Upgrade <$> upgradeOptsP <*> switch
|
||||
(short 'f' <> long "force" <> help "Force update")
|
||||
)
|
||||
<**> helper
|
||||
)
|
||||
(progDesc "Upgrade ghcup")
|
||||
)
|
||||
<> command
|
||||
"compile"
|
||||
( Compile
|
||||
<$> info (compileP <**> helper)
|
||||
(progDesc "Compile a tool from source")
|
||||
)
|
||||
<> command
|
||||
"whereis"
|
||||
(info
|
||||
( (Whereis
|
||||
<$> (WhereisOptions <$> switch (short 'd' <> long "directory" <> help "return directory of the binary instead of the binary location"))
|
||||
<*> whereisP
|
||||
) <**> helper
|
||||
)
|
||||
(progDesc "Find a tools location"
|
||||
<> footerDoc ( Just $ text whereisFooter ))
|
||||
)
|
||||
<> command
|
||||
"prefetch"
|
||||
(info
|
||||
( (Prefetch
|
||||
<$> prefetchP
|
||||
) <**> helper
|
||||
)
|
||||
(progDesc "Prefetch assets"
|
||||
<> footerDoc ( Just $ text prefetchFooter ))
|
||||
)
|
||||
<> command
|
||||
"gc"
|
||||
(info
|
||||
( (GC
|
||||
<$> gcP
|
||||
) <**> helper
|
||||
)
|
||||
(progDesc "Garbage collection"
|
||||
<> footerDoc ( Just $ text gcFooter ))
|
||||
)
|
||||
<> commandGroup "Main commands:"
|
||||
)
|
||||
<|> subparser
|
||||
( command
|
||||
"debug-info"
|
||||
((\_ -> DInfo) <$> info helper (progDesc "Show debug info"))
|
||||
<> command
|
||||
"tool-requirements"
|
||||
( (\_ -> ToolRequirements)
|
||||
<$> info helper
|
||||
(progDesc "Show the requirements for ghc/cabal")
|
||||
)
|
||||
<> command
|
||||
"changelog"
|
||||
(info
|
||||
(fmap ChangeLog changelogP <**> helper)
|
||||
( progDesc "Find/show changelog"
|
||||
<> footerDoc (Just $ text changeLogFooter)
|
||||
)
|
||||
)
|
||||
<> command
|
||||
"config"
|
||||
( Config
|
||||
<$> info (configP <**> helper)
|
||||
(progDesc "Show or set config" <> footerDoc (Just $ text configFooter))
|
||||
)
|
||||
<> commandGroup "Other commands:"
|
||||
<> hidden
|
||||
)
|
||||
<|> subparser
|
||||
( command
|
||||
"install-cabal"
|
||||
(info
|
||||
((InstallCabalLegacy <$> installOpts (Just Cabal)) <**> helper)
|
||||
( progDesc "Install or update cabal"
|
||||
<> footerDoc (Just $ text installCabalFooter)
|
||||
)
|
||||
)
|
||||
<> internal
|
||||
)
|
||||
<|> subparser
|
||||
(command
|
||||
"nuke"
|
||||
(info (pure Nuke <**> helper)
|
||||
(progDesc "Completely remove ghcup from your system"))
|
||||
<> commandGroup "Nuclear Commands:"
|
||||
<> hidden
|
||||
)
|
||||
150
app/ghcup/GHCup/OptParse/ChangeLog.hs
Normal file
@@ -0,0 +1,150 @@
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE TypeApplications #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE TemplateHaskell #-}
|
||||
{-# LANGUAGE QuasiQuotes #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE DuplicateRecordFields #-}
|
||||
{-# LANGUAGE RankNTypes #-}
|
||||
|
||||
module GHCup.OptParse.ChangeLog where
|
||||
|
||||
|
||||
import GHCup.Types
|
||||
import GHCup.Logger
|
||||
import GHCup.OptParse.Common
|
||||
import GHCup.QQ.String
|
||||
|
||||
#if !MIN_VERSION_base(4,13,0)
|
||||
import Control.Monad.Fail ( MonadFail )
|
||||
#endif
|
||||
import Control.Monad.Reader
|
||||
import Control.Monad.Trans.Resource
|
||||
import Data.Functor
|
||||
import Data.Maybe
|
||||
import Options.Applicative hiding ( style )
|
||||
import Prelude hiding ( appendFile )
|
||||
import System.Exit
|
||||
import Text.PrettyPrint.HughesPJClass ( prettyShow )
|
||||
|
||||
import qualified Data.Text as T
|
||||
import Control.Exception.Safe (MonadMask)
|
||||
import GHCup.Types.Optics
|
||||
import GHCup.Utils
|
||||
import Data.Versions
|
||||
import URI.ByteString (serializeURIRef')
|
||||
import GHCup.Prelude
|
||||
import GHCup.System.Process (exec)
|
||||
import Data.Char (toLower)
|
||||
|
||||
|
||||
|
||||
---------------
|
||||
--[ Options ]--
|
||||
---------------
|
||||
|
||||
|
||||
data ChangeLogOptions = ChangeLogOptions
|
||||
{ clOpen :: Bool
|
||||
, clTool :: Maybe Tool
|
||||
, clToolVer :: Maybe ToolVersion
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
---------------
|
||||
--[ Parsers ]--
|
||||
---------------
|
||||
|
||||
|
||||
changelogP :: Parser ChangeLogOptions
|
||||
changelogP =
|
||||
(\x y -> ChangeLogOptions x y)
|
||||
<$> switch (short 'o' <> long "open" <> help "xdg-open the changelog url")
|
||||
<*> optional
|
||||
(option
|
||||
(eitherReader
|
||||
(\s' -> case fmap toLower s' of
|
||||
"ghc" -> Right GHC
|
||||
"cabal" -> Right Cabal
|
||||
"ghcup" -> Right GHCup
|
||||
"stack" -> Right Stack
|
||||
e -> Left e
|
||||
)
|
||||
)
|
||||
(short 't' <> long "tool" <> metavar "<ghc|cabal|ghcup>" <> help
|
||||
"Open changelog for given tool (default: ghc)"
|
||||
)
|
||||
)
|
||||
<*> optional (toolVersionArgument Nothing Nothing)
|
||||
|
||||
|
||||
|
||||
--------------
|
||||
--[ Footer ]--
|
||||
--------------
|
||||
|
||||
|
||||
changeLogFooter :: String
|
||||
changeLogFooter = [s|Discussion:
|
||||
By default returns the URI of the ChangeLog of the latest GHC release.
|
||||
Pass '-o' to automatically open via xdg-open.|]
|
||||
|
||||
|
||||
|
||||
------------------
|
||||
--[ Entrypoint ]--
|
||||
------------------
|
||||
|
||||
|
||||
|
||||
changelog :: ( Monad m
|
||||
, MonadMask m
|
||||
, MonadUnliftIO m
|
||||
, MonadFail m
|
||||
)
|
||||
=> ChangeLogOptions
|
||||
-> (forall a . ReaderT AppState m a -> m a)
|
||||
-> (ReaderT LeanAppState m () -> m ())
|
||||
-> m ExitCode
|
||||
changelog ChangeLogOptions{..} runAppState runLogger = do
|
||||
GHCupInfo { _ghcupDownloads = dls } <- runAppState getGHCupInfo
|
||||
let tool = fromMaybe GHC clTool
|
||||
ver' = maybe
|
||||
(Right Latest)
|
||||
(\case
|
||||
ToolVersion tv -> Left (_tvVersion tv) -- FIXME: ugly sharing of ToolVersion
|
||||
ToolTag t -> Right t
|
||||
)
|
||||
clToolVer
|
||||
muri = getChangeLog dls tool ver'
|
||||
case muri of
|
||||
Nothing -> do
|
||||
runLogger
|
||||
(logWarn $
|
||||
"Could not find ChangeLog for " <> T.pack (prettyShow tool) <> ", version " <> either prettyVer (T.pack . show) ver'
|
||||
)
|
||||
pure ExitSuccess
|
||||
Just uri -> do
|
||||
pfreq <- runAppState getPlatformReq
|
||||
let uri' = T.unpack . decUTF8Safe . serializeURIRef' $ uri
|
||||
cmd = case _rPlatform pfreq of
|
||||
Darwin -> "open"
|
||||
Linux _ -> "xdg-open"
|
||||
FreeBSD -> "xdg-open"
|
||||
Windows -> "start"
|
||||
|
||||
if clOpen
|
||||
then do
|
||||
runAppState $
|
||||
exec cmd
|
||||
[T.unpack $ decUTF8Safe $ serializeURIRef' uri]
|
||||
Nothing
|
||||
Nothing
|
||||
>>= \case
|
||||
Right _ -> pure ExitSuccess
|
||||
Left e -> logError (T.pack $ prettyShow e)
|
||||
>> pure (ExitFailure 13)
|
||||
else liftIO $ putStrLn uri' >> pure ExitSuccess
|
||||
513
app/ghcup/GHCup/OptParse/Common.hs
Normal file
@@ -0,0 +1,513 @@
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE DuplicateRecordFields #-}
|
||||
|
||||
module GHCup.OptParse.Common where
|
||||
|
||||
|
||||
import GHCup
|
||||
import GHCup.Download
|
||||
import GHCup.Errors
|
||||
import GHCup.Platform
|
||||
import GHCup.Types
|
||||
import GHCup.Types.Optics
|
||||
import GHCup.Utils
|
||||
import GHCup.Logger
|
||||
import GHCup.MegaParsec
|
||||
import GHCup.Prelude
|
||||
|
||||
import Control.Exception.Safe
|
||||
#if !MIN_VERSION_base(4,13,0)
|
||||
import Control.Monad.Fail ( MonadFail )
|
||||
#endif
|
||||
import Control.Monad.Reader
|
||||
import Data.Bifunctor
|
||||
import Data.Char
|
||||
import Data.Either
|
||||
import Data.Functor
|
||||
import Data.List ( nub, sort, sortBy )
|
||||
import Data.Maybe
|
||||
import Data.Text ( Text )
|
||||
import Data.Versions hiding ( str )
|
||||
import Data.Void
|
||||
import Haskus.Utils.Variant.Excepts
|
||||
import Options.Applicative hiding ( style )
|
||||
import Prelude hiding ( appendFile )
|
||||
import Safe
|
||||
import System.FilePath
|
||||
import URI.ByteString
|
||||
|
||||
import qualified Data.ByteString.UTF8 as UTF8
|
||||
import qualified Data.Map.Strict as M
|
||||
import qualified Data.Text as T
|
||||
import qualified Text.Megaparsec as MP
|
||||
import GHCup.Version
|
||||
|
||||
|
||||
-------------
|
||||
--[ Types ]--
|
||||
-------------
|
||||
|
||||
data ToolVersion = ToolVersion GHCTargetVersion -- target is ignored for cabal
|
||||
| ToolTag Tag
|
||||
|
||||
-- a superset of ToolVersion
|
||||
data SetToolVersion = SetToolVersion GHCTargetVersion
|
||||
| SetToolTag Tag
|
||||
| SetRecommended
|
||||
| SetNext
|
||||
|
||||
prettyToolVer :: ToolVersion -> String
|
||||
prettyToolVer (ToolVersion v') = T.unpack $ tVerToText v'
|
||||
prettyToolVer (ToolTag t) = show t
|
||||
|
||||
toSetToolVer :: Maybe ToolVersion -> SetToolVersion
|
||||
toSetToolVer (Just (ToolVersion v')) = SetToolVersion v'
|
||||
toSetToolVer (Just (ToolTag t')) = SetToolTag t'
|
||||
toSetToolVer Nothing = SetRecommended
|
||||
|
||||
|
||||
|
||||
|
||||
--------------
|
||||
--[ Parser ]--
|
||||
--------------
|
||||
|
||||
|
||||
-- | same as toolVersionParser, except as an argument.
|
||||
toolVersionArgument :: Maybe ListCriteria -> Maybe Tool -> Parser ToolVersion
|
||||
toolVersionArgument criteria tool =
|
||||
argument (eitherReader toolVersionEither)
|
||||
(metavar (mv tool)
|
||||
<> completer (tagCompleter (fromMaybe GHC tool) [])
|
||||
<> foldMap (completer . versionCompleter criteria) tool)
|
||||
where
|
||||
mv (Just GHC) = "GHC_VERSION|TAG"
|
||||
mv (Just HLS) = "HLS_VERSION|TAG"
|
||||
mv _ = "VERSION|TAG"
|
||||
|
||||
|
||||
versionParser :: Parser GHCTargetVersion
|
||||
versionParser = option
|
||||
(eitherReader tVersionEither)
|
||||
(short 'v' <> long "version" <> metavar "VERSION" <> help "The target version"
|
||||
)
|
||||
|
||||
versionParser' :: Maybe ListCriteria -> Maybe Tool -> Parser Version
|
||||
versionParser' criteria tool = argument
|
||||
(eitherReader (first show . version . T.pack))
|
||||
(metavar "VERSION" <> foldMap (completer . versionCompleter criteria) tool)
|
||||
|
||||
versionArgument :: Maybe ListCriteria -> Maybe Tool -> Parser GHCTargetVersion
|
||||
versionArgument criteria tool = argument (eitherReader tVersionEither) (metavar "VERSION" <> foldMap (completer . versionCompleter criteria) tool)
|
||||
|
||||
|
||||
-- https://github.com/pcapriotti/optparse-applicative/issues/148
|
||||
|
||||
-- | A switch that can be enabled using --foo and disabled using --no-foo.
|
||||
--
|
||||
-- The option modifier is applied to only the option that is *not* enabled
|
||||
-- by default. For example:
|
||||
--
|
||||
-- > invertableSwitch "recursive" True (help "do not recurse into directories")
|
||||
--
|
||||
-- This example makes --recursive enabled by default, so
|
||||
-- the help is shown only for --no-recursive.
|
||||
invertableSwitch
|
||||
:: String -- ^ long option
|
||||
-> Char -- ^ short option for the non-default option
|
||||
-> Bool -- ^ is switch enabled by default?
|
||||
-> Mod FlagFields Bool -- ^ option modifier
|
||||
-> Parser (Maybe Bool)
|
||||
invertableSwitch longopt shortopt defv optmod = invertableSwitch' longopt shortopt defv
|
||||
(if defv then mempty else optmod)
|
||||
(if defv then optmod else mempty)
|
||||
|
||||
-- | Allows providing option modifiers for both --foo and --no-foo.
|
||||
invertableSwitch'
|
||||
:: String -- ^ long option (eg "foo")
|
||||
-> Char -- ^ short option for the non-default option
|
||||
-> Bool -- ^ is switch enabled by default?
|
||||
-> Mod FlagFields Bool -- ^ option modifier for --foo
|
||||
-> Mod FlagFields Bool -- ^ option modifier for --no-foo
|
||||
-> Parser (Maybe Bool)
|
||||
invertableSwitch' longopt shortopt defv enmod dismod = optional
|
||||
( flag' True ( enmod <> long longopt <> if defv then mempty else short shortopt)
|
||||
<|> flag' False (dismod <> long nolongopt <> if defv then short shortopt else mempty)
|
||||
)
|
||||
where
|
||||
nolongopt = "no-" ++ longopt
|
||||
|
||||
|
||||
|
||||
---------------------
|
||||
--[ Either Parser ]--
|
||||
---------------------
|
||||
|
||||
|
||||
platformParser :: String -> Either String PlatformRequest
|
||||
platformParser s' = case MP.parse (platformP <* MP.eof) "" (T.pack s') of
|
||||
Right r -> pure r
|
||||
Left e -> Left $ errorBundlePretty e
|
||||
where
|
||||
archP :: MP.Parsec Void Text Architecture
|
||||
archP = MP.try (MP.chunk "x86_64" $> A_64) <|> (MP.chunk "i386" $> A_32)
|
||||
platformP :: MP.Parsec Void Text PlatformRequest
|
||||
platformP = choice'
|
||||
[ (`PlatformRequest` FreeBSD)
|
||||
<$> (archP <* MP.chunk "-")
|
||||
<*> ( MP.chunk "portbld"
|
||||
*> ( MP.try (Just <$> verP (MP.chunk "-freebsd" <* MP.eof))
|
||||
<|> pure Nothing
|
||||
)
|
||||
<* MP.chunk "-freebsd"
|
||||
)
|
||||
, (`PlatformRequest` Darwin)
|
||||
<$> (archP <* MP.chunk "-")
|
||||
<*> ( MP.chunk "apple"
|
||||
*> ( MP.try (Just <$> verP (MP.chunk "-darwin" <* MP.eof))
|
||||
<|> pure Nothing
|
||||
)
|
||||
<* MP.chunk "-darwin"
|
||||
)
|
||||
, (\a d mv -> PlatformRequest a (Linux d) mv)
|
||||
<$> (archP <* MP.chunk "-")
|
||||
<*> distroP
|
||||
<*> ((MP.try (Just <$> verP (MP.chunk "-linux" <* MP.eof)) <|> pure Nothing
|
||||
)
|
||||
<* MP.chunk "-linux"
|
||||
)
|
||||
]
|
||||
distroP :: MP.Parsec Void Text LinuxDistro
|
||||
distroP = choice'
|
||||
[ MP.chunk "debian" $> Debian
|
||||
, MP.chunk "deb" $> Debian
|
||||
, MP.chunk "ubuntu" $> Ubuntu
|
||||
, MP.chunk "mint" $> Mint
|
||||
, MP.chunk "fedora" $> Fedora
|
||||
, MP.chunk "centos" $> CentOS
|
||||
, MP.chunk "redhat" $> RedHat
|
||||
, MP.chunk "alpine" $> Alpine
|
||||
, MP.chunk "gentoo" $> Gentoo
|
||||
, MP.chunk "exherbo" $> Exherbo
|
||||
, MP.chunk "unknown" $> UnknownLinux
|
||||
]
|
||||
|
||||
|
||||
bindistParser :: String -> Either String URI
|
||||
bindistParser = first show . parseURI strictURIParserOptions . UTF8.fromString
|
||||
|
||||
|
||||
absolutePathParser :: FilePath -> Either String FilePath
|
||||
absolutePathParser f = case isValid f && isAbsolute f of
|
||||
True -> Right $ normalise f
|
||||
False -> Left "Please enter a valid absolute filepath."
|
||||
|
||||
isolateParser :: FilePath -> Either String FilePath
|
||||
isolateParser f = case isValid f of
|
||||
True -> Right $ normalise f
|
||||
False -> Left "Please enter a valid filepath for isolate dir."
|
||||
|
||||
toolVersionEither :: String -> Either String ToolVersion
|
||||
toolVersionEither s' =
|
||||
second ToolTag (tagEither s') <|> second ToolVersion (tVersionEither s')
|
||||
|
||||
tagEither :: String -> Either String Tag
|
||||
tagEither s' = case fmap toLower s' of
|
||||
"recommended" -> Right Recommended
|
||||
"latest" -> Right Latest
|
||||
('b':'a':'s':'e':'-':ver') -> case pvp (T.pack ver') of
|
||||
Right x -> Right (Base x)
|
||||
Left _ -> Left $ "Invalid PVP version for base " <> ver'
|
||||
other -> Left $ "Unknown tag " <> other
|
||||
|
||||
|
||||
tVersionEither :: String -> Either String GHCTargetVersion
|
||||
tVersionEither =
|
||||
first (const "Not a valid version") . MP.parse ghcTargetVerP "" . T.pack
|
||||
|
||||
|
||||
toolParser :: String -> Either String Tool
|
||||
toolParser s' | t == T.pack "ghc" = Right GHC
|
||||
| t == T.pack "cabal" = Right Cabal
|
||||
| t == T.pack "hls" = Right HLS
|
||||
| t == T.pack "stack" = Right Stack
|
||||
| otherwise = Left ("Unknown tool: " <> s')
|
||||
where t = T.toLower (T.pack s')
|
||||
|
||||
|
||||
criteriaParser :: String -> Either String ListCriteria
|
||||
criteriaParser s' | t == T.pack "installed" = Right ListInstalled
|
||||
| t == T.pack "set" = Right ListSet
|
||||
| t == T.pack "available" = Right ListAvailable
|
||||
| otherwise = Left ("Unknown criteria: " <> s')
|
||||
where t = T.toLower (T.pack s')
|
||||
|
||||
|
||||
toolVersionParser :: Parser ToolVersion
|
||||
toolVersionParser = verP' <|> toolP
|
||||
where
|
||||
verP' = ToolVersion <$> versionParser
|
||||
toolP =
|
||||
ToolTag
|
||||
<$> option
|
||||
(eitherReader tagEither)
|
||||
(short 't' <> long "tag" <> metavar "TAG" <> help "The target tag")
|
||||
|
||||
|
||||
|
||||
|
||||
keepOnParser :: String -> Either String KeepDirs
|
||||
keepOnParser s' | t == T.pack "always" = Right Always
|
||||
| t == T.pack "errors" = Right Errors
|
||||
| t == T.pack "never" = Right Never
|
||||
| otherwise = Left ("Unknown keep value: " <> s')
|
||||
where t = T.toLower (T.pack s')
|
||||
|
||||
|
||||
downloaderParser :: String -> Either String Downloader
|
||||
downloaderParser s' | t == T.pack "curl" = Right Curl
|
||||
| t == T.pack "wget" = Right Wget
|
||||
#if defined(INTERNAL_DOWNLOADER)
|
||||
| t == T.pack "internal" = Right Internal
|
||||
#endif
|
||||
| otherwise = Left ("Unknown downloader value: " <> s')
|
||||
where t = T.toLower (T.pack s')
|
||||
|
||||
gpgParser :: String -> Either String GPGSetting
|
||||
gpgParser s' | t == T.pack "strict" = Right GPGStrict
|
||||
| t == T.pack "lax" = Right GPGLax
|
||||
| t == T.pack "none" = Right GPGNone
|
||||
| otherwise = Left ("Unknown gpg setting value: " <> s')
|
||||
where t = T.toLower (T.pack s')
|
||||
|
||||
|
||||
|
||||
------------------
|
||||
--[ Completers ]--
|
||||
------------------
|
||||
|
||||
tagCompleter :: Tool -> [String] -> Completer
|
||||
tagCompleter tool add = listIOCompleter $ do
|
||||
dirs' <- liftIO getAllDirs
|
||||
let loggerConfig = LoggerConfig
|
||||
{ lcPrintDebug = False
|
||||
, consoleOutter = mempty
|
||||
, fileOutter = mempty
|
||||
, fancyColors = False
|
||||
}
|
||||
let appState = LeanAppState
|
||||
(defaultSettings { noNetwork = True })
|
||||
dirs'
|
||||
defaultKeyBindings
|
||||
loggerConfig
|
||||
|
||||
mGhcUpInfo <- flip runReaderT appState . runE $ getDownloadsF
|
||||
case mGhcUpInfo of
|
||||
VRight ghcupInfo -> do
|
||||
let allTags = filter (/= Old)
|
||||
$ _viTags =<< M.elems (availableToolVersions (_ghcupDownloads ghcupInfo) tool)
|
||||
pure $ nub $ (add ++) $ fmap tagToString allTags
|
||||
VLeft _ -> pure (nub $ ["recommended", "latest"] ++ add)
|
||||
|
||||
|
||||
versionCompleter :: Maybe ListCriteria -> Tool -> Completer
|
||||
versionCompleter criteria tool = listIOCompleter $ do
|
||||
dirs' <- liftIO getAllDirs
|
||||
let loggerConfig = LoggerConfig
|
||||
{ lcPrintDebug = False
|
||||
, consoleOutter = mempty
|
||||
, fileOutter = mempty
|
||||
, fancyColors = False
|
||||
}
|
||||
let settings = defaultSettings { noNetwork = True }
|
||||
let leanAppState = LeanAppState
|
||||
settings
|
||||
dirs'
|
||||
defaultKeyBindings
|
||||
loggerConfig
|
||||
mpFreq <- flip runReaderT leanAppState . runE $ platformRequest
|
||||
mGhcUpInfo <- flip runReaderT leanAppState . runE $ getDownloadsF
|
||||
forFold mpFreq $ \pfreq -> do
|
||||
forFold mGhcUpInfo $ \ghcupInfo -> do
|
||||
let appState = AppState
|
||||
settings
|
||||
dirs'
|
||||
defaultKeyBindings
|
||||
ghcupInfo
|
||||
pfreq
|
||||
loggerConfig
|
||||
|
||||
runEnv = flip runReaderT appState
|
||||
|
||||
installedVersions <- runEnv $ listVersions (Just tool) criteria
|
||||
return $ T.unpack . prettyVer . lVer <$> installedVersions
|
||||
|
||||
|
||||
|
||||
|
||||
-----------------
|
||||
--[ Utilities ]--
|
||||
-----------------
|
||||
|
||||
|
||||
fromVersion :: ( HasLog env
|
||||
, MonadFail m
|
||||
, MonadReader env m
|
||||
, HasGHCupInfo env
|
||||
, HasDirs env
|
||||
, MonadThrow m
|
||||
, MonadIO m
|
||||
, MonadCatch m
|
||||
)
|
||||
=> Maybe ToolVersion
|
||||
-> Tool
|
||||
-> Excepts
|
||||
'[ TagNotFound
|
||||
, NextVerNotFound
|
||||
, NoToolVersionSet
|
||||
] m (GHCTargetVersion, Maybe VersionInfo)
|
||||
fromVersion tv = fromVersion' (toSetToolVer tv)
|
||||
|
||||
fromVersion' :: ( HasLog env
|
||||
, MonadFail m
|
||||
, MonadReader env m
|
||||
, HasGHCupInfo env
|
||||
, HasDirs env
|
||||
, MonadThrow m
|
||||
, MonadIO m
|
||||
, MonadCatch m
|
||||
)
|
||||
=> SetToolVersion
|
||||
-> Tool
|
||||
-> Excepts
|
||||
'[ TagNotFound
|
||||
, NextVerNotFound
|
||||
, NoToolVersionSet
|
||||
] m (GHCTargetVersion, Maybe VersionInfo)
|
||||
fromVersion' SetRecommended tool = do
|
||||
GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo
|
||||
bimap mkTVer Just <$> getRecommended dls tool
|
||||
?? TagNotFound Recommended tool
|
||||
fromVersion' (SetToolVersion v) tool = do
|
||||
GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo
|
||||
let vi = getVersionInfo (_tvVersion v) tool dls
|
||||
case pvp $ prettyVer (_tvVersion v) of -- need to be strict here
|
||||
Left _ -> pure (v, vi)
|
||||
Right pvpIn ->
|
||||
lift (getLatestToolFor tool pvpIn dls) >>= \case
|
||||
Just (pvp_, vi') -> do
|
||||
v' <- lift $ pvpToVersion pvp_ ""
|
||||
when (v' /= _tvVersion v) $ lift $ logWarn ("Assuming you meant version " <> prettyVer v')
|
||||
pure (GHCTargetVersion (_tvTarget v) v', Just vi')
|
||||
Nothing -> pure (v, vi)
|
||||
fromVersion' (SetToolTag Latest) tool = do
|
||||
GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo
|
||||
bimap mkTVer Just <$> getLatest dls tool ?? TagNotFound Latest tool
|
||||
fromVersion' (SetToolTag Recommended) tool = do
|
||||
GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo
|
||||
bimap mkTVer Just <$> getRecommended dls tool ?? TagNotFound Recommended tool
|
||||
fromVersion' (SetToolTag (Base pvp'')) GHC = do
|
||||
GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo
|
||||
bimap mkTVer Just <$> getLatestBaseVersion dls pvp'' ?? TagNotFound (Base pvp'') GHC
|
||||
fromVersion' SetNext tool = do
|
||||
GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo
|
||||
next <- case tool of
|
||||
GHC -> do
|
||||
set <- fmap _tvVersion $ ghcSet Nothing !? NoToolVersionSet tool
|
||||
ghcs <- rights <$> lift getInstalledGHCs
|
||||
(headMay
|
||||
. tail
|
||||
. dropWhile (\GHCTargetVersion {..} -> _tvVersion /= set)
|
||||
. cycle
|
||||
. sortBy (\x y -> compare (_tvVersion x) (_tvVersion y))
|
||||
. filter (\GHCTargetVersion {..} -> isNothing _tvTarget)
|
||||
$ ghcs) ?? NoToolVersionSet tool
|
||||
Cabal -> do
|
||||
set <- cabalSet !? NoToolVersionSet tool
|
||||
cabals <- rights <$> lift getInstalledCabals
|
||||
(fmap (GHCTargetVersion Nothing)
|
||||
. headMay
|
||||
. tail
|
||||
. dropWhile (/= set)
|
||||
. cycle
|
||||
. sort
|
||||
$ cabals) ?? NoToolVersionSet tool
|
||||
HLS -> do
|
||||
set <- hlsSet !? NoToolVersionSet tool
|
||||
hlses <- rights <$> lift getInstalledHLSs
|
||||
(fmap (GHCTargetVersion Nothing)
|
||||
. headMay
|
||||
. tail
|
||||
. dropWhile (/= set)
|
||||
. cycle
|
||||
. sort
|
||||
$ hlses) ?? NoToolVersionSet tool
|
||||
Stack -> do
|
||||
set <- stackSet !? NoToolVersionSet tool
|
||||
stacks <- rights <$> lift getInstalledStacks
|
||||
(fmap (GHCTargetVersion Nothing)
|
||||
. headMay
|
||||
. tail
|
||||
. dropWhile (/= set)
|
||||
. cycle
|
||||
. sort
|
||||
$ stacks) ?? NoToolVersionSet tool
|
||||
GHCup -> fail "GHCup cannot be set"
|
||||
let vi = getVersionInfo (_tvVersion next) tool dls
|
||||
pure (next, vi)
|
||||
fromVersion' (SetToolTag t') tool =
|
||||
throwE $ TagNotFound t' tool
|
||||
|
||||
|
||||
checkForUpdates :: ( MonadReader env m
|
||||
, HasGHCupInfo env
|
||||
, HasDirs env
|
||||
, HasPlatformReq env
|
||||
, MonadCatch m
|
||||
, HasLog env
|
||||
, MonadThrow m
|
||||
, MonadIO m
|
||||
, MonadFail m
|
||||
)
|
||||
=> m ()
|
||||
checkForUpdates = do
|
||||
GHCupInfo { _ghcupDownloads = dls } <- getGHCupInfo
|
||||
lInstalled <- listVersions Nothing (Just ListInstalled)
|
||||
let latestInstalled tool = (fmap lVer . lastMay . filter (\lr -> lTool lr == tool)) lInstalled
|
||||
|
||||
forM_ (getLatest dls GHCup) $ \(l, _) -> do
|
||||
(Right ghc_ver) <- pure $ version $ prettyPVP ghcUpVer
|
||||
when (l > ghc_ver)
|
||||
$ logWarn $
|
||||
"New GHCup version available: " <> prettyVer l <> ". To upgrade, run 'ghcup upgrade'"
|
||||
|
||||
forM_ (getLatest dls GHC) $ \(l, _) -> do
|
||||
let mghc_ver = latestInstalled GHC
|
||||
forM mghc_ver $ \ghc_ver ->
|
||||
when (l > ghc_ver)
|
||||
$ logWarn $
|
||||
"New GHC version available: " <> prettyVer l <> ". To upgrade, run 'ghcup install ghc " <> prettyVer l <> "'"
|
||||
|
||||
forM_ (getLatest dls Cabal) $ \(l, _) -> do
|
||||
let mcabal_ver = latestInstalled Cabal
|
||||
forM mcabal_ver $ \cabal_ver ->
|
||||
when (l > cabal_ver)
|
||||
$ logWarn $
|
||||
"New Cabal version available: " <> prettyVer l <> ". To upgrade, run 'ghcup install cabal " <> prettyVer l <> "'"
|
||||
|
||||
forM_ (getLatest dls HLS) $ \(l, _) -> do
|
||||
let mhls_ver = latestInstalled HLS
|
||||
forM mhls_ver $ \hls_ver ->
|
||||
when (l > hls_ver)
|
||||
$ logWarn $
|
||||
"New HLS version available: " <> prettyVer l <> ". To upgrade, run 'ghcup install hls " <> prettyVer l <> "'"
|
||||
|
||||
forM_ (getLatest dls Stack) $ \(l, _) -> do
|
||||
let mstack_ver = latestInstalled Stack
|
||||
forM mstack_ver $ \stack_ver ->
|
||||
when (l > stack_ver)
|
||||
$ logWarn $
|
||||
"New Stack version available: " <> prettyVer l <> ". To upgrade, run 'ghcup install stack " <> prettyVer l <> "'"
|
||||
517
app/ghcup/GHCup/OptParse/Compile.hs
Normal file
@@ -0,0 +1,517 @@
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE TypeApplications #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE TemplateHaskell #-}
|
||||
{-# LANGUAGE QuasiQuotes #-}
|
||||
{-# LANGUAGE DuplicateRecordFields #-}
|
||||
{-# LANGUAGE RankNTypes #-}
|
||||
|
||||
module GHCup.OptParse.Compile where
|
||||
|
||||
|
||||
import GHCup
|
||||
import GHCup.Errors
|
||||
import GHCup.Types
|
||||
import GHCup.Types.Optics
|
||||
import GHCup.Utils
|
||||
import GHCup.Logger
|
||||
import GHCup.OptParse.Common
|
||||
import GHCup.QQ.String
|
||||
import GHCup.System.Process
|
||||
|
||||
#if !MIN_VERSION_base(4,13,0)
|
||||
import Control.Monad.Fail ( MonadFail )
|
||||
#endif
|
||||
import Codec.Archive ( ArchiveResult )
|
||||
import Control.Concurrent (threadDelay)
|
||||
import Control.Monad.Reader
|
||||
import Control.Monad.Trans.Resource
|
||||
import Data.Bifunctor
|
||||
import Data.Functor
|
||||
import Data.Maybe
|
||||
import Data.Versions ( Version, prettyVer, version )
|
||||
import Data.Text ( Text )
|
||||
import Haskus.Utils.Variant.Excepts
|
||||
import Options.Applicative hiding ( style )
|
||||
import Options.Applicative.Help.Pretty ( text )
|
||||
import Prelude hiding ( appendFile )
|
||||
import System.Exit
|
||||
import Text.PrettyPrint.HughesPJClass ( prettyShow )
|
||||
|
||||
import qualified Data.Text as T
|
||||
import Control.Exception.Safe (MonadMask)
|
||||
import System.FilePath (isPathSeparator)
|
||||
import Text.Read (readEither)
|
||||
|
||||
|
||||
|
||||
|
||||
----------------
|
||||
--[ Commands ]--
|
||||
----------------
|
||||
|
||||
|
||||
data CompileCommand = CompileGHC GHCCompileOptions
|
||||
| CompileHLS HLSCompileOptions
|
||||
|
||||
|
||||
|
||||
---------------
|
||||
--[ Options ]--
|
||||
---------------
|
||||
|
||||
|
||||
data GHCCompileOptions = GHCCompileOptions
|
||||
{ targetGhc :: Either Version GitBranch
|
||||
, bootstrapGhc :: Either Version FilePath
|
||||
, jobs :: Maybe Int
|
||||
, buildConfig :: Maybe FilePath
|
||||
, patchDir :: Maybe FilePath
|
||||
, crossTarget :: Maybe Text
|
||||
, addConfArgs :: [Text]
|
||||
, setCompile :: Bool
|
||||
, ovewrwiteVer :: Maybe Version
|
||||
, buildFlavour :: Maybe String
|
||||
, hadrian :: Bool
|
||||
, isolateDir :: Maybe FilePath
|
||||
}
|
||||
|
||||
data HLSCompileOptions = HLSCompileOptions
|
||||
{ targetHLS :: Either Version GitBranch
|
||||
, jobs :: Maybe Int
|
||||
, setCompile :: Bool
|
||||
, ovewrwiteVer :: Maybe Version
|
||||
, isolateDir :: Maybe FilePath
|
||||
, cabalProject :: Maybe FilePath
|
||||
, cabalProjectLocal :: Maybe FilePath
|
||||
, patchDir :: Maybe FilePath
|
||||
, targetGHCs :: [ToolVersion]
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
---------------
|
||||
--[ Parsers ]--
|
||||
---------------
|
||||
|
||||
|
||||
compileP :: Parser CompileCommand
|
||||
compileP = subparser
|
||||
( command
|
||||
"ghc"
|
||||
( CompileGHC
|
||||
<$> info
|
||||
(ghcCompileOpts <**> helper)
|
||||
( progDesc "Compile GHC from source"
|
||||
<> footerDoc (Just $ text compileFooter)
|
||||
)
|
||||
)
|
||||
<> command
|
||||
"hls"
|
||||
( CompileHLS
|
||||
<$> info
|
||||
(hlsCompileOpts <**> helper)
|
||||
( progDesc "Compile HLS from source"
|
||||
<> footerDoc (Just $ text compileHLSFooter)
|
||||
)
|
||||
)
|
||||
)
|
||||
where
|
||||
compileFooter = [s|Discussion:
|
||||
Compiles and installs the specified GHC version into
|
||||
a self-contained "~/.ghcup/ghc/<ghcver>" directory
|
||||
and symlinks the ghc binaries to "~/.ghcup/bin/<binary>-<ghcver>".
|
||||
|
||||
This also allows building a cross-compiler. Consult the documentation
|
||||
first: <https://gitlab.haskell.org/ghc/ghc/-/wikis/building/cross-compiling#configuring-the-build>
|
||||
|
||||
ENV variables:
|
||||
Various toolchain variables will be passed onto the ghc build system,
|
||||
such as: CC, LD, OBJDUMP, NM, AR, RANLIB.
|
||||
|
||||
Examples:
|
||||
# compile from known version
|
||||
ghcup compile ghc -j 4 -v 8.4.2 -b 8.2.2
|
||||
# compile from git commit/reference
|
||||
ghcup compile ghc -j 4 -g master -b 8.2.2
|
||||
# specify path to bootstrap ghc
|
||||
ghcup compile ghc -j 4 -v 8.4.2 -b /usr/bin/ghc-8.2.2
|
||||
# build cross compiler
|
||||
ghcup compile ghc -j 4 -v 8.4.2 -b 8.2.2 -x armv7-unknown-linux-gnueabihf --config $(pwd)/build.mk -- --enable-unregisterised|]
|
||||
|
||||
compileHLSFooter = [s|Discussion:
|
||||
Compiles and installs the specified HLS version.
|
||||
The last argument is a list of GHC versions to compile for.
|
||||
These need to be available in PATH prior to compilation.
|
||||
|
||||
Examples:
|
||||
ghcup compile hls -v 1.4.0 -j 12 8.10.5 8.10.7 9.0.1|]
|
||||
|
||||
|
||||
ghcCompileOpts :: Parser GHCCompileOptions
|
||||
ghcCompileOpts =
|
||||
GHCCompileOptions
|
||||
<$> ((Left <$> option
|
||||
(eitherReader
|
||||
(first (const "Not a valid version") . version . T.pack)
|
||||
)
|
||||
(short 'v' <> long "version" <> metavar "VERSION" <> help
|
||||
"The tool version to compile"
|
||||
)
|
||||
) <|>
|
||||
(Right <$> (GitBranch <$> option
|
||||
str
|
||||
(short 'g' <> long "git-ref" <> metavar "GIT_REFERENCE" <> help
|
||||
"The git commit/branch/ref to build from"
|
||||
) <*>
|
||||
optional (option str (short 'r' <> long "repository" <> metavar "GIT_REPOSITORY" <> help "The git repository to build from (defaults to GHC upstream)"))
|
||||
)))
|
||||
<*> option
|
||||
(eitherReader
|
||||
(\x ->
|
||||
(bimap (const "Not a valid version") Left . version . T.pack $ x) <|> (if isPathSeparator (head x) then pure $ Right x else Left "Not an absolute Path")
|
||||
)
|
||||
)
|
||||
( short 'b'
|
||||
<> long "bootstrap-ghc"
|
||||
<> metavar "BOOTSTRAP_GHC"
|
||||
<> help
|
||||
"The GHC version (or full path) to bootstrap with (must be installed)"
|
||||
)
|
||||
<*> optional
|
||||
(option
|
||||
(eitherReader (readEither @Int))
|
||||
(short 'j' <> long "jobs" <> metavar "JOBS" <> help
|
||||
"How many jobs to use for make"
|
||||
)
|
||||
)
|
||||
<*> optional
|
||||
(option
|
||||
str
|
||||
(short 'c' <> long "config" <> metavar "CONFIG" <> help
|
||||
"Absolute path to build config file"
|
||||
)
|
||||
)
|
||||
<*> optional
|
||||
(option
|
||||
str
|
||||
(short 'p' <> long "patchdir" <> metavar "PATCH_DIR" <> help
|
||||
"Absolute path to patch directory (applies all .patch and .diff files in order using -p1)"
|
||||
)
|
||||
)
|
||||
<*> optional
|
||||
(option
|
||||
str
|
||||
(short 'x' <> long "cross-target" <> metavar "CROSS_TARGET" <> help
|
||||
"Build cross-compiler for this platform"
|
||||
)
|
||||
)
|
||||
<*> many (argument str (metavar "CONFIGURE_ARGS" <> help "Additional arguments to configure, prefix with '-- ' (longopts)"))
|
||||
<*> flag
|
||||
False
|
||||
True
|
||||
(long "set" <> help
|
||||
"Set as active version after install"
|
||||
)
|
||||
<*> optional
|
||||
(option
|
||||
(eitherReader
|
||||
(first (const "Not a valid version") . version . T.pack)
|
||||
)
|
||||
(short 'o' <> long "overwrite-version" <> metavar "OVERWRITE_VERSION" <> help
|
||||
"Allows to overwrite the finally installed VERSION with a different one, e.g. when you build 8.10.4 with your own patches, you might want to set this to '8.10.4-p1'"
|
||||
)
|
||||
)
|
||||
<*> optional
|
||||
(option
|
||||
str
|
||||
(short 'f' <> long "flavour" <> metavar "BUILD_FLAVOUR" <> help
|
||||
"Set the compile build flavour (this value depends on the build system type: 'make' vs 'hadrian')"
|
||||
)
|
||||
)
|
||||
<*> switch
|
||||
(long "hadrian" <> help "Use the hadrian build system instead of make (only git versions seem to be properly supported atm)"
|
||||
)
|
||||
<*> optional
|
||||
(option
|
||||
(eitherReader isolateParser)
|
||||
( short 'i'
|
||||
<> long "isolate"
|
||||
<> metavar "DIR"
|
||||
<> help "install in an isolated directory instead of the default one, no symlinks to this installation will be made"
|
||||
)
|
||||
)
|
||||
|
||||
hlsCompileOpts :: Parser HLSCompileOptions
|
||||
hlsCompileOpts =
|
||||
HLSCompileOptions
|
||||
<$> ((Left <$> option
|
||||
(eitherReader
|
||||
(first (const "Not a valid version") . version . T.pack)
|
||||
)
|
||||
(short 'v' <> long "version" <> metavar "VERSION" <> help
|
||||
"The tool version to compile"
|
||||
)
|
||||
) <|>
|
||||
(Right <$> (GitBranch <$> option
|
||||
str
|
||||
(short 'g' <> long "git-ref" <> metavar "GIT_REFERENCE" <> help
|
||||
"The git commit/branch/ref to build from"
|
||||
) <*>
|
||||
optional (option str (short 'r' <> long "repository" <> metavar "GIT_REPOSITORY" <> help "The git repository to build from (defaults to GHC upstream)"))
|
||||
)))
|
||||
<*> optional
|
||||
(option
|
||||
(eitherReader (readEither @Int))
|
||||
(short 'j' <> long "jobs" <> metavar "JOBS" <> help
|
||||
"How many jobs to use for make"
|
||||
)
|
||||
)
|
||||
<*> flag
|
||||
False
|
||||
True
|
||||
(long "set" <> help
|
||||
"Set as active version after install"
|
||||
)
|
||||
<*> optional
|
||||
(option
|
||||
(eitherReader
|
||||
(first (const "Not a valid version") . version . T.pack)
|
||||
)
|
||||
(short 'o' <> long "overwrite-version" <> metavar "OVERWRITE_VERSION" <> help
|
||||
"Allows to overwrite the finally installed VERSION with a different one, e.g. when you build 8.10.4 with your own patches, you might want to set this to '8.10.4-p1'"
|
||||
)
|
||||
)
|
||||
<*> optional
|
||||
(option
|
||||
(eitherReader isolateParser)
|
||||
( short 'i'
|
||||
<> long "isolate"
|
||||
<> metavar "DIR"
|
||||
<> help "install in an isolated directory instead of the default one, no symlinks to this installation will be made"
|
||||
)
|
||||
)
|
||||
<*> optional
|
||||
(option
|
||||
str
|
||||
(long "cabal-project" <> metavar "CABAL_PROJECT" <> help
|
||||
"If relative, specifies the path to cabal.project inside the unpacked HLS tarball/checkout. If absolute, will copy the file over."
|
||||
)
|
||||
)
|
||||
<*> optional
|
||||
(option
|
||||
(eitherReader absolutePathParser)
|
||||
(long "cabal-project-local" <> metavar "CABAL_PROJECT_LOCAL" <> help
|
||||
"Absolute path to a cabal.project.local to be used for the build. Will be copied over."
|
||||
)
|
||||
)
|
||||
<*> optional
|
||||
(option
|
||||
(eitherReader absolutePathParser)
|
||||
(short 'p' <> long "patchdir" <> metavar "PATCH_DIR" <> help
|
||||
"Absolute path to patch directory (applies all .patch and .diff files in order using -p1)"
|
||||
)
|
||||
)
|
||||
<*> some (toolVersionArgument Nothing (Just GHC))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
---------------------------
|
||||
--[ Effect interpreters ]--
|
||||
---------------------------
|
||||
|
||||
|
||||
type GHCEffects = '[ AlreadyInstalled
|
||||
, BuildFailed
|
||||
, DigestError
|
||||
, GPGError
|
||||
, DownloadFailed
|
||||
, GHCupSetError
|
||||
, NoDownload
|
||||
, NotFoundInPATH
|
||||
, PatchFailed
|
||||
, UnknownArchive
|
||||
, TarDirDoesNotExist
|
||||
, NotInstalled
|
||||
, DirNotEmpty
|
||||
, ArchiveResult
|
||||
, FileDoesNotExistError
|
||||
, HadrianNotFound
|
||||
, InvalidBuildConfig
|
||||
, ProcessError
|
||||
, CopyError
|
||||
, BuildFailed
|
||||
]
|
||||
type HLSEffects = '[ AlreadyInstalled
|
||||
, BuildFailed
|
||||
, DigestError
|
||||
, GPGError
|
||||
, DownloadFailed
|
||||
, GHCupSetError
|
||||
, NoDownload
|
||||
, NotFoundInPATH
|
||||
, PatchFailed
|
||||
, UnknownArchive
|
||||
, TarDirDoesNotExist
|
||||
, TagNotFound
|
||||
, NextVerNotFound
|
||||
, NoToolVersionSet
|
||||
, NotInstalled
|
||||
, DirNotEmpty
|
||||
, ArchiveResult
|
||||
]
|
||||
|
||||
|
||||
|
||||
runCompileGHC :: (MonadUnliftIO m, MonadIO m)
|
||||
=> (ReaderT AppState m (VEither GHCEffects a) -> m (VEither GHCEffects a))
|
||||
-> Excepts GHCEffects (ResourceT (ReaderT AppState m)) a
|
||||
-> m (VEither GHCEffects a)
|
||||
runCompileGHC runAppState =
|
||||
runAppState
|
||||
. runResourceT
|
||||
. runE
|
||||
@GHCEffects
|
||||
|
||||
runCompileHLS :: (MonadUnliftIO m, MonadIO m)
|
||||
=> (ReaderT AppState m (VEither HLSEffects a) -> m (VEither HLSEffects a))
|
||||
-> Excepts HLSEffects (ResourceT (ReaderT AppState m)) a
|
||||
-> m (VEither HLSEffects a)
|
||||
runCompileHLS runAppState =
|
||||
runAppState
|
||||
. runResourceT
|
||||
. runE
|
||||
@HLSEffects
|
||||
|
||||
|
||||
|
||||
------------------
|
||||
--[ Entrypoint ]--
|
||||
------------------
|
||||
|
||||
|
||||
|
||||
compile :: ( Monad m
|
||||
, MonadMask m
|
||||
, MonadUnliftIO m
|
||||
, MonadFail m
|
||||
)
|
||||
=> CompileCommand
|
||||
-> Settings
|
||||
-> (forall eff a . ReaderT AppState m (VEither eff a) -> m (VEither eff a))
|
||||
-> (ReaderT LeanAppState m () -> m ())
|
||||
-> m ExitCode
|
||||
compile compileCommand settings runAppState runLogger = do
|
||||
VRight Dirs{ .. } <- runAppState (VRight <$> getDirs)
|
||||
case compileCommand of
|
||||
(CompileHLS HLSCompileOptions { .. }) -> do
|
||||
runCompileHLS runAppState (do
|
||||
case targetHLS of
|
||||
Left targetVer -> do
|
||||
GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo
|
||||
let vi = getVersionInfo targetVer HLS dls
|
||||
forM_ (_viPreCompile =<< vi) $ \msg -> do
|
||||
lift $ logInfo msg
|
||||
lift $ logInfo
|
||||
"...waiting for 5 seconds, you can still abort..."
|
||||
liftIO $ threadDelay 5000000 -- for compilation, give the user a sec to intervene
|
||||
Right _ -> pure ()
|
||||
ghcs <- liftE $ forM targetGHCs (\ghc -> fmap (_tvVersion . fst) . fromVersion (Just ghc) $ GHC)
|
||||
targetVer <- liftE $ compileHLS
|
||||
targetHLS
|
||||
ghcs
|
||||
jobs
|
||||
ovewrwiteVer
|
||||
isolateDir
|
||||
cabalProject
|
||||
cabalProjectLocal
|
||||
patchDir
|
||||
GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo
|
||||
let vi = getVersionInfo targetVer HLS dls
|
||||
when setCompile $ void $ liftE $
|
||||
setHLS targetVer
|
||||
pure (vi, targetVer)
|
||||
)
|
||||
>>= \case
|
||||
VRight (vi, tv) -> do
|
||||
runLogger $ logInfo
|
||||
"HLS successfully compiled and installed"
|
||||
forM_ (_viPostInstall =<< vi) $ \msg ->
|
||||
runLogger $ logInfo msg
|
||||
liftIO $ putStr (T.unpack $ prettyVer tv)
|
||||
pure ExitSuccess
|
||||
VLeft err@(V (BuildFailed tmpdir _)) -> do
|
||||
case keepDirs settings of
|
||||
Never -> runLogger $ logError $ T.pack $ prettyShow err
|
||||
_ -> runLogger (logError $ T.pack (prettyShow err) <> "\n" <>
|
||||
"Check the logs at " <> T.pack logsDir <> " and the build directory "
|
||||
<> T.pack tmpdir <> " for more clues." <> "\n" <>
|
||||
"Make sure to clean up " <> T.pack tmpdir <> " afterwards.")
|
||||
pure $ ExitFailure 9
|
||||
VLeft e -> do
|
||||
runLogger $ logError $ T.pack $ prettyShow e
|
||||
pure $ ExitFailure 9
|
||||
(CompileGHC GHCCompileOptions { hadrian = True, crossTarget = Just _ }) -> do
|
||||
runLogger $ logError "Hadrian cross compile support is not yet implemented!"
|
||||
pure $ ExitFailure 9
|
||||
(CompileGHC GHCCompileOptions {..}) ->
|
||||
runCompileGHC runAppState (do
|
||||
case targetGhc of
|
||||
Left targetVer -> do
|
||||
GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo
|
||||
let vi = getVersionInfo targetVer GHC dls
|
||||
forM_ (_viPreCompile =<< vi) $ \msg -> do
|
||||
lift $ logInfo msg
|
||||
lift $ logInfo
|
||||
"...waiting for 5 seconds, you can still abort..."
|
||||
liftIO $ threadDelay 5000000 -- for compilation, give the user a sec to intervene
|
||||
Right _ -> pure ()
|
||||
targetVer <- liftE $ compileGHC
|
||||
(first (GHCTargetVersion crossTarget) targetGhc)
|
||||
ovewrwiteVer
|
||||
bootstrapGhc
|
||||
jobs
|
||||
buildConfig
|
||||
patchDir
|
||||
addConfArgs
|
||||
buildFlavour
|
||||
hadrian
|
||||
isolateDir
|
||||
GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo
|
||||
let vi = getVersionInfo (_tvVersion targetVer) GHC dls
|
||||
when setCompile $ void $ liftE $
|
||||
setGHC targetVer SetGHCOnly
|
||||
pure (vi, targetVer)
|
||||
)
|
||||
>>= \case
|
||||
VRight (vi, tv) -> do
|
||||
runLogger $ logInfo
|
||||
"GHC successfully compiled and installed"
|
||||
forM_ (_viPostInstall =<< vi) $ \msg ->
|
||||
runLogger $ logInfo msg
|
||||
liftIO $ putStr (T.unpack $ tVerToText tv)
|
||||
pure ExitSuccess
|
||||
VLeft (V (AlreadyInstalled _ v)) -> do
|
||||
runLogger $ logWarn $
|
||||
"GHC ver " <> prettyVer v <> " already installed; if you really want to reinstall it, you may want to run 'ghcup install ghc --force " <> prettyVer v <> "'"
|
||||
pure ExitSuccess
|
||||
VLeft (V (DirNotEmpty fp)) -> do
|
||||
runLogger $ logWarn $
|
||||
"Install directory " <> T.pack fp <> " is not empty. Use 'ghcup install ghc --isolate " <> T.pack fp <> " --force ..." <> "' to install regardless."
|
||||
pure $ ExitFailure 3
|
||||
VLeft err@(V (BuildFailed tmpdir _)) -> do
|
||||
case keepDirs settings of
|
||||
Never -> runLogger $ logError $ T.pack $ prettyShow err
|
||||
_ -> runLogger (logError $ T.pack (prettyShow err) <> "\n" <>
|
||||
"Check the logs at " <> T.pack logsDir <> " and the build directory "
|
||||
<> T.pack tmpdir <> " for more clues." <> "\n" <>
|
||||
"Make sure to clean up " <> T.pack tmpdir <> " afterwards.")
|
||||
pure $ ExitFailure 9
|
||||
VLeft e -> do
|
||||
runLogger $ logError $ T.pack $ prettyShow e
|
||||
pure $ ExitFailure 9
|
||||
187
app/ghcup/GHCup/OptParse/Config.hs
Normal file
@@ -0,0 +1,187 @@
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE TypeApplications #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE TemplateHaskell #-}
|
||||
{-# LANGUAGE QuasiQuotes #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE DuplicateRecordFields #-}
|
||||
{-# LANGUAGE RankNTypes #-}
|
||||
|
||||
module GHCup.OptParse.Config where
|
||||
|
||||
|
||||
import GHCup.Errors
|
||||
import GHCup.Types
|
||||
import GHCup.Utils
|
||||
import GHCup.Prelude
|
||||
import GHCup.Logger
|
||||
import GHCup.QQ.String
|
||||
|
||||
#if !MIN_VERSION_base(4,13,0)
|
||||
import Control.Monad.Fail ( MonadFail )
|
||||
#endif
|
||||
import Control.Exception ( displayException )
|
||||
import Control.Monad.Reader
|
||||
import Control.Monad.Trans.Resource
|
||||
import Data.Functor
|
||||
import Data.Maybe
|
||||
import Haskus.Utils.Variant.Excepts
|
||||
import Options.Applicative hiding ( style )
|
||||
import Options.Applicative.Help.Pretty ( text )
|
||||
import Prelude hiding ( appendFile )
|
||||
import System.Exit
|
||||
|
||||
import qualified Data.Text as T
|
||||
import qualified Data.ByteString.UTF8 as UTF8
|
||||
import qualified Data.Yaml.Aeson as Y
|
||||
import Control.Exception.Safe (MonadMask)
|
||||
|
||||
|
||||
|
||||
|
||||
----------------
|
||||
--[ Commands ]--
|
||||
----------------
|
||||
|
||||
|
||||
data ConfigCommand
|
||||
= ShowConfig
|
||||
| SetConfig String (Maybe String)
|
||||
| InitConfig
|
||||
|
||||
|
||||
|
||||
---------------
|
||||
--[ Parsers ]--
|
||||
---------------
|
||||
|
||||
|
||||
configP :: Parser ConfigCommand
|
||||
configP = subparser
|
||||
( command "init" initP
|
||||
<> command "set" setP -- [set] KEY VALUE at help lhs
|
||||
<> command "show" showP
|
||||
)
|
||||
<|> argsP -- add show for a single option
|
||||
<|> pure ShowConfig
|
||||
where
|
||||
initP = info (pure InitConfig) (progDesc "Write default config to ~/.ghcup/config.yaml")
|
||||
showP = info (pure ShowConfig) (progDesc "Show current config (default)")
|
||||
setP = info argsP (progDesc "Set config KEY to VALUE (or specify as single json value)" <> footerDoc (Just $ text configSetFooter))
|
||||
argsP = SetConfig <$> argument str (metavar "<JSON_VALUE | YAML_KEY>") <*> optional (argument str (metavar "YAML_VALUE"))
|
||||
|
||||
|
||||
|
||||
|
||||
--------------
|
||||
--[ Footer ]--
|
||||
--------------
|
||||
|
||||
|
||||
configFooter :: String
|
||||
configFooter = [s|Examples:
|
||||
|
||||
# show current config
|
||||
ghcup config
|
||||
|
||||
# initialize config
|
||||
ghcup config init
|
||||
|
||||
# set <key> <value> configuration pair
|
||||
ghcup config set <key> <value>|]
|
||||
|
||||
|
||||
configSetFooter :: String
|
||||
configSetFooter = [s|Examples:
|
||||
# disable caching
|
||||
ghcup config set cache false
|
||||
|
||||
# switch downloader to wget
|
||||
ghcup config set downloader Wget
|
||||
|
||||
# set mirror for ghcup metadata
|
||||
ghcup config set '{url-source: { OwnSource: "<url>"}}'|]
|
||||
|
||||
|
||||
|
||||
-----------------
|
||||
--[ Utilities ]--
|
||||
-----------------
|
||||
|
||||
|
||||
formatConfig :: UserSettings -> String
|
||||
formatConfig = UTF8.toString . Y.encode
|
||||
|
||||
|
||||
updateSettings :: Monad m => UTF8.ByteString -> Settings -> Excepts '[JSONError] m Settings
|
||||
updateSettings config' settings = do
|
||||
settings' <- lE' (JSONDecodeError . displayException) . Y.decodeEither' $ config'
|
||||
pure $ mergeConf settings' settings
|
||||
where
|
||||
mergeConf :: UserSettings -> Settings -> Settings
|
||||
mergeConf UserSettings{..} Settings{..} =
|
||||
let cache' = fromMaybe cache uCache
|
||||
metaCache' = fromMaybe metaCache uMetaCache
|
||||
noVerify' = fromMaybe noVerify uNoVerify
|
||||
keepDirs' = fromMaybe keepDirs uKeepDirs
|
||||
downloader' = fromMaybe downloader uDownloader
|
||||
verbose' = fromMaybe verbose uVerbose
|
||||
urlSource' = fromMaybe urlSource uUrlSource
|
||||
noNetwork' = fromMaybe noNetwork uNoNetwork
|
||||
gpgSetting' = fromMaybe gpgSetting uGPGSetting
|
||||
in Settings cache' metaCache' noVerify' keepDirs' downloader' verbose' urlSource' noNetwork' gpgSetting' noColor
|
||||
|
||||
|
||||
|
||||
------------------
|
||||
--[ Entrypoint ]--
|
||||
------------------
|
||||
|
||||
|
||||
|
||||
config :: ( Monad m
|
||||
, MonadMask m
|
||||
, MonadUnliftIO m
|
||||
, MonadFail m
|
||||
)
|
||||
=> ConfigCommand
|
||||
-> Settings
|
||||
-> KeyBindings
|
||||
-> (ReaderT LeanAppState m () -> m ())
|
||||
-> m ExitCode
|
||||
config configCommand settings keybindings runLogger = case configCommand of
|
||||
InitConfig -> do
|
||||
path <- getConfigFilePath
|
||||
liftIO $ writeFile path $ formatConfig $ fromSettings settings (Just keybindings)
|
||||
runLogger $ logDebug $ "config.yaml initialized at " <> T.pack path
|
||||
pure ExitSuccess
|
||||
|
||||
ShowConfig -> do
|
||||
liftIO $ putStrLn $ formatConfig $ fromSettings settings (Just keybindings)
|
||||
pure ExitSuccess
|
||||
|
||||
(SetConfig k (Just v)) ->
|
||||
case v of
|
||||
"" -> do
|
||||
runLogger $ logError "Empty values are not allowed"
|
||||
pure $ ExitFailure 55
|
||||
_ -> doConfig (k <> ": " <> v <> "\n")
|
||||
|
||||
(SetConfig json Nothing) -> doConfig json
|
||||
|
||||
where
|
||||
doConfig val = do
|
||||
r <- runE @'[JSONError] $ do
|
||||
settings' <- updateSettings (UTF8.fromString val) settings
|
||||
path <- liftIO getConfigFilePath
|
||||
liftIO $ writeFile path $ formatConfig $ fromSettings settings' (Just keybindings)
|
||||
lift $ runLogger $ logDebug $ T.pack $ show settings'
|
||||
pure ()
|
||||
|
||||
case r of
|
||||
VRight _ -> pure ExitSuccess
|
||||
VLeft (V (JSONDecodeError e)) -> do
|
||||
runLogger $ logError $ "Error decoding config: " <> T.pack e
|
||||
pure $ ExitFailure 65
|
||||
VLeft _ -> pure $ ExitFailure 65
|
||||
119
app/ghcup/GHCup/OptParse/DInfo.hs
Normal file
@@ -0,0 +1,119 @@
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE TypeApplications #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE TemplateHaskell #-}
|
||||
{-# LANGUAGE QuasiQuotes #-}
|
||||
{-# LANGUAGE DuplicateRecordFields #-}
|
||||
{-# LANGUAGE RankNTypes #-}
|
||||
|
||||
module GHCup.OptParse.DInfo where
|
||||
|
||||
|
||||
|
||||
|
||||
import GHCup
|
||||
import GHCup.Errors
|
||||
import GHCup.Version
|
||||
import GHCup.Types
|
||||
import GHCup.Prelude
|
||||
import GHCup.Directories
|
||||
import GHCup.Logger
|
||||
import GHCup.System.Process
|
||||
|
||||
#if !MIN_VERSION_base(4,13,0)
|
||||
import Control.Monad.Fail ( MonadFail )
|
||||
#endif
|
||||
import Control.Monad.Reader
|
||||
import Control.Monad.Trans.Resource
|
||||
import Data.Functor
|
||||
import Data.Maybe
|
||||
import Haskus.Utils.Variant.Excepts
|
||||
import Options.Applicative hiding ( style )
|
||||
import Prelude hiding ( appendFile )
|
||||
import System.Exit
|
||||
import Text.PrettyPrint.HughesPJClass ( prettyShow )
|
||||
|
||||
import qualified Data.Text as T
|
||||
import Control.Exception.Safe (MonadMask)
|
||||
import Language.Haskell.TH
|
||||
|
||||
|
||||
|
||||
-----------------
|
||||
--[ Utilities ]--
|
||||
-----------------
|
||||
|
||||
|
||||
describe_result :: String
|
||||
describe_result = $( LitE . StringL <$>
|
||||
runIO (do
|
||||
CapturedProcess{..} <- do
|
||||
dirs <- liftIO getAllDirs
|
||||
let settings = AppState (defaultSettings { noNetwork = True })
|
||||
dirs
|
||||
defaultKeyBindings
|
||||
flip runReaderT settings $ executeOut "git" ["describe"] Nothing
|
||||
case _exitCode of
|
||||
ExitSuccess -> pure . T.unpack . decUTF8Safe' $ _stdOut
|
||||
ExitFailure _ -> pure numericVer
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
prettyDebugInfo :: DebugInfo -> String
|
||||
prettyDebugInfo DebugInfo {..} = "Debug Info" <> "\n" <>
|
||||
"==========" <> "\n" <>
|
||||
"GHCup base dir: " <> diBaseDir <> "\n" <>
|
||||
"GHCup bin dir: " <> diBinDir <> "\n" <>
|
||||
"GHCup GHC directory: " <> diGHCDir <> "\n" <>
|
||||
"GHCup cache directory: " <> diCacheDir <> "\n" <>
|
||||
"Architecture: " <> prettyShow diArch <> "\n" <>
|
||||
"Platform: " <> prettyShow diPlatform <> "\n" <>
|
||||
"Version: " <> describe_result
|
||||
|
||||
|
||||
|
||||
---------------------------
|
||||
--[ Effect interpreters ]--
|
||||
---------------------------
|
||||
|
||||
|
||||
type DInfoEffects = '[ NoCompatiblePlatform , NoCompatibleArch , DistroNotFound ]
|
||||
|
||||
runDebugInfo :: (ReaderT env m (VEither DInfoEffects a) -> m (VEither DInfoEffects a))
|
||||
-> Excepts DInfoEffects (ReaderT env m) a
|
||||
-> m (VEither DInfoEffects a)
|
||||
runDebugInfo runAppState =
|
||||
runAppState
|
||||
. runE
|
||||
@DInfoEffects
|
||||
|
||||
|
||||
|
||||
------------------
|
||||
--[ Entrypoint ]--
|
||||
------------------
|
||||
|
||||
|
||||
|
||||
dinfo :: ( Monad m
|
||||
, MonadMask m
|
||||
, MonadUnliftIO m
|
||||
, MonadFail m
|
||||
, Alternative m
|
||||
)
|
||||
=> (ReaderT AppState m (VEither DInfoEffects DebugInfo)
|
||||
-> m (VEither DInfoEffects DebugInfo))
|
||||
-> (ReaderT LeanAppState m () -> m ())
|
||||
-> m ExitCode
|
||||
dinfo runAppState runLogger = do
|
||||
runDebugInfo runAppState (liftE getDebugInfo)
|
||||
>>= \case
|
||||
VRight di -> do
|
||||
liftIO $ putStrLn $ prettyDebugInfo di
|
||||
pure ExitSuccess
|
||||
VLeft e -> do
|
||||
runLogger $ logError $ T.pack $ prettyShow e
|
||||
pure $ ExitFailure 8
|
||||
143
app/ghcup/GHCup/OptParse/GC.hs
Normal file
@@ -0,0 +1,143 @@
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE TypeApplications #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE TemplateHaskell #-}
|
||||
{-# LANGUAGE QuasiQuotes #-}
|
||||
{-# LANGUAGE DuplicateRecordFields #-}
|
||||
{-# LANGUAGE RankNTypes #-}
|
||||
|
||||
module GHCup.OptParse.GC where
|
||||
|
||||
|
||||
import GHCup
|
||||
import GHCup.Errors
|
||||
import GHCup.Types
|
||||
import GHCup.Logger
|
||||
import GHCup.QQ.String
|
||||
|
||||
#if !MIN_VERSION_base(4,13,0)
|
||||
import Control.Monad.Fail ( MonadFail )
|
||||
#endif
|
||||
import Control.Monad.Reader
|
||||
import Control.Monad.Trans.Resource
|
||||
import Data.Functor
|
||||
import Haskus.Utils.Variant.Excepts
|
||||
import Options.Applicative hiding ( style )
|
||||
import Prelude hiding ( appendFile )
|
||||
import System.Exit
|
||||
import Text.PrettyPrint.HughesPJClass ( prettyShow )
|
||||
|
||||
import qualified Data.Text as T
|
||||
import Control.Exception.Safe (MonadMask)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
---------------
|
||||
--[ Options ]--
|
||||
---------------
|
||||
|
||||
|
||||
data GCOptions = GCOptions
|
||||
{ gcOldGHC :: Bool
|
||||
, gcProfilingLibs :: Bool
|
||||
, gcShareDir :: Bool
|
||||
, gcHLSNoGHC :: Bool
|
||||
, gcCache :: Bool
|
||||
, gcTmp :: Bool
|
||||
}
|
||||
|
||||
|
||||
|
||||
---------------
|
||||
--[ Parsers ]--
|
||||
---------------
|
||||
|
||||
|
||||
gcP :: Parser GCOptions
|
||||
gcP =
|
||||
GCOptions
|
||||
<$>
|
||||
switch
|
||||
(short 'o' <> long "ghc-old" <> help "Remove GHC versions marked as 'old'")
|
||||
<*>
|
||||
switch
|
||||
(short 'p' <> long "profiling-libs" <> help "Remove profiling libs of GHC versions")
|
||||
<*>
|
||||
switch
|
||||
(short 's' <> long "share-dir" <> help "Remove GHC share directories (documentation)")
|
||||
<*>
|
||||
switch
|
||||
(short 'h' <> long "hls-no-ghc" <> help "Remove HLS versions that don't have a corresponding installed GHC version")
|
||||
<*>
|
||||
switch
|
||||
(short 'c' <> long "cache" <> help "GC the GHCup cache")
|
||||
<*>
|
||||
switch
|
||||
(short 't' <> long "tmpdirs" <> help "Remove tmpdir leftovers")
|
||||
|
||||
|
||||
|
||||
--------------
|
||||
--[ Footer ]--
|
||||
--------------
|
||||
|
||||
|
||||
gcFooter :: String
|
||||
gcFooter = [s|Discussion:
|
||||
Performs garbage collection. If no switches are specified, does nothing.|]
|
||||
|
||||
|
||||
|
||||
|
||||
---------------------------
|
||||
--[ Effect interpreters ]--
|
||||
---------------------------
|
||||
|
||||
|
||||
type GCEffects = '[ NotInstalled ]
|
||||
|
||||
|
||||
runGC :: MonadUnliftIO m
|
||||
=> (ReaderT AppState m (VEither GCEffects a) -> m (VEither GCEffects a))
|
||||
-> Excepts GCEffects (ResourceT (ReaderT AppState m)) a
|
||||
-> m (VEither GCEffects a)
|
||||
runGC runAppState =
|
||||
runAppState
|
||||
. runResourceT
|
||||
. runE
|
||||
@GCEffects
|
||||
|
||||
|
||||
|
||||
------------------
|
||||
--[ Entrypoint ]--
|
||||
------------------
|
||||
|
||||
|
||||
|
||||
gc :: ( Monad m
|
||||
, MonadMask m
|
||||
, MonadUnliftIO m
|
||||
, MonadFail m
|
||||
)
|
||||
=> GCOptions
|
||||
-> (forall a. ReaderT AppState m (VEither GCEffects a) -> m (VEither GCEffects a))
|
||||
-> (ReaderT LeanAppState m () -> m ())
|
||||
-> m ExitCode
|
||||
gc GCOptions{..} runAppState runLogger = runGC runAppState (do
|
||||
when gcOldGHC rmOldGHC
|
||||
lift $ when gcProfilingLibs rmProfilingLibs
|
||||
lift $ when gcShareDir rmShareDir
|
||||
lift $ when gcHLSNoGHC rmHLSNoGHC
|
||||
lift $ when gcCache rmCache
|
||||
lift $ when gcTmp rmTmp
|
||||
) >>= \case
|
||||
VRight _ -> do
|
||||
pure ExitSuccess
|
||||
VLeft e -> do
|
||||
runLogger $ logError $ T.pack $ prettyShow e
|
||||
pure $ ExitFailure 27
|
||||
464
app/ghcup/GHCup/OptParse/Install.hs
Normal file
@@ -0,0 +1,464 @@
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE TypeApplications #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE TemplateHaskell #-}
|
||||
{-# LANGUAGE QuasiQuotes #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE DuplicateRecordFields #-}
|
||||
|
||||
module GHCup.OptParse.Install where
|
||||
|
||||
|
||||
|
||||
|
||||
import GHCup.OptParse.Common
|
||||
|
||||
import GHCup
|
||||
import GHCup.Errors
|
||||
import GHCup.Types
|
||||
import GHCup.Logger
|
||||
import GHCup.QQ.String
|
||||
import GHCup.System.Process
|
||||
|
||||
import Codec.Archive
|
||||
#if !MIN_VERSION_base(4,13,0)
|
||||
import Control.Monad.Fail ( MonadFail )
|
||||
#endif
|
||||
import Control.Monad.Reader
|
||||
import Control.Monad.Trans.Resource
|
||||
import Data.Either
|
||||
import Data.Functor
|
||||
import Data.Maybe
|
||||
import Data.Versions hiding ( str )
|
||||
import Haskus.Utils.Variant.Excepts
|
||||
import Options.Applicative hiding ( style )
|
||||
import Options.Applicative.Help.Pretty ( text )
|
||||
import Prelude hiding ( appendFile )
|
||||
import System.Exit
|
||||
import Text.PrettyPrint.HughesPJClass ( prettyShow )
|
||||
import URI.ByteString
|
||||
|
||||
import qualified Data.Text as T
|
||||
|
||||
|
||||
|
||||
|
||||
----------------
|
||||
--[ Commands ]--
|
||||
----------------
|
||||
|
||||
|
||||
data InstallCommand = InstallGHC InstallOptions
|
||||
| InstallCabal InstallOptions
|
||||
| InstallHLS InstallOptions
|
||||
| InstallStack InstallOptions
|
||||
|
||||
|
||||
|
||||
|
||||
---------------
|
||||
--[ Options ]--
|
||||
---------------
|
||||
|
||||
|
||||
data InstallOptions = InstallOptions
|
||||
{ instVer :: Maybe ToolVersion
|
||||
, instPlatform :: Maybe PlatformRequest
|
||||
, instBindist :: Maybe URI
|
||||
, instSet :: Bool
|
||||
, isolateDir :: Maybe FilePath
|
||||
, forceInstall :: Bool
|
||||
}
|
||||
|
||||
|
||||
|
||||
---------------
|
||||
--[ Footers ]--
|
||||
---------------
|
||||
|
||||
installCabalFooter :: String
|
||||
installCabalFooter = [s|Discussion:
|
||||
Installs the specified cabal-install version (or a recommended default one)
|
||||
into "~/.ghcup/bin", so it can be overwritten by later
|
||||
"cabal install cabal-install", which installs into "~/.cabal/bin" by
|
||||
default. Make sure to set up your PATH appropriately, so the cabal
|
||||
installation takes precedence.|]
|
||||
|
||||
|
||||
|
||||
---------------
|
||||
--[ Parsers ]--
|
||||
---------------
|
||||
|
||||
installParser :: Parser (Either InstallCommand InstallOptions)
|
||||
installParser =
|
||||
(Left <$> subparser
|
||||
( command
|
||||
"ghc"
|
||||
( InstallGHC
|
||||
<$> info
|
||||
(installOpts (Just GHC) <**> helper)
|
||||
( progDesc "Install GHC"
|
||||
<> footerDoc (Just $ text installGHCFooter)
|
||||
)
|
||||
)
|
||||
<> command
|
||||
"cabal"
|
||||
( InstallCabal
|
||||
<$> info
|
||||
(installOpts (Just Cabal) <**> helper)
|
||||
( progDesc "Install Cabal"
|
||||
<> footerDoc (Just $ text installCabalFooter)
|
||||
)
|
||||
)
|
||||
<> command
|
||||
"hls"
|
||||
( InstallHLS
|
||||
<$> info
|
||||
(installOpts (Just HLS) <**> helper)
|
||||
( progDesc "Install haskell-language-server"
|
||||
<> footerDoc (Just $ text installHLSFooter)
|
||||
)
|
||||
)
|
||||
<> command
|
||||
"stack"
|
||||
( InstallStack
|
||||
<$> info
|
||||
(installOpts (Just Stack) <**> helper)
|
||||
( progDesc "Install stack"
|
||||
<> footerDoc (Just $ text installStackFooter)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
<|> (Right <$> installOpts Nothing)
|
||||
where
|
||||
installHLSFooter :: String
|
||||
installHLSFooter = [s|Discussion:
|
||||
Installs haskell-language-server binaries and wrapper
|
||||
into "~/.ghcup/bin"
|
||||
|
||||
Examples:
|
||||
# install recommended HLS
|
||||
ghcup install hls|]
|
||||
|
||||
installStackFooter :: String
|
||||
installStackFooter = [s|Discussion:
|
||||
Installs stack binaries into "~/.ghcup/bin"
|
||||
|
||||
Examples:
|
||||
# install recommended Stack
|
||||
ghcup install stack|]
|
||||
|
||||
installGHCFooter :: String
|
||||
installGHCFooter = [s|Discussion:
|
||||
Installs the specified GHC version (or a recommended default one) into
|
||||
a self-contained "~/.ghcup/ghc/<ghcver>" directory
|
||||
and symlinks the ghc binaries to "~/.ghcup/bin/<binary>-<ghcver>".
|
||||
|
||||
Examples:
|
||||
# install recommended GHC
|
||||
ghcup install ghc
|
||||
|
||||
# install latest GHC
|
||||
ghcup install ghc latest
|
||||
|
||||
# install GHC 8.10.2
|
||||
ghcup install ghc 8.10.2
|
||||
|
||||
# install GHC head fedora bindist
|
||||
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|]
|
||||
|
||||
|
||||
installOpts :: Maybe Tool -> Parser InstallOptions
|
||||
installOpts tool =
|
||||
(\p (u, v) b is f -> InstallOptions v p u b is f)
|
||||
<$> optional
|
||||
(option
|
||||
(eitherReader platformParser)
|
||||
( short 'p'
|
||||
<> long "platform"
|
||||
<> metavar "PLATFORM"
|
||||
<> help
|
||||
"Override for platform (triple matching ghc tarball names), e.g. x86_64-fedora27-linux"
|
||||
)
|
||||
)
|
||||
<*> ( ( (,)
|
||||
<$> optional
|
||||
(option
|
||||
(eitherReader bindistParser)
|
||||
(short 'u' <> long "url" <> metavar "BINDIST_URL" <> help
|
||||
"Install the specified version from this bindist"
|
||||
)
|
||||
)
|
||||
<*> (Just <$> toolVersionArgument Nothing tool)
|
||||
)
|
||||
<|> pure (Nothing, Nothing)
|
||||
)
|
||||
<*> flag
|
||||
False
|
||||
True
|
||||
(long "set" <> help
|
||||
"Set as active version after install"
|
||||
)
|
||||
<*> optional
|
||||
(option
|
||||
(eitherReader isolateParser)
|
||||
( short 'i'
|
||||
<> long "isolate"
|
||||
<> metavar "DIR"
|
||||
<> help "install in an isolated dir instead of the default one"
|
||||
)
|
||||
)
|
||||
<*> switch
|
||||
(short 'f' <> long "force" <> help "Force install")
|
||||
|
||||
|
||||
|
||||
|
||||
--------------
|
||||
--[ Footer ]--
|
||||
--------------
|
||||
|
||||
|
||||
installToolFooter :: String
|
||||
installToolFooter = [s|Discussion:
|
||||
Installs GHC or cabal. When no command is given, installs GHC
|
||||
with the specified version/tag.
|
||||
It is recommended to always specify a subcommand (ghc/cabal/hls/stack).|]
|
||||
|
||||
|
||||
|
||||
|
||||
---------------------------
|
||||
--[ Effect interpreters ]--
|
||||
---------------------------
|
||||
|
||||
type InstallEffects = '[ AlreadyInstalled
|
||||
, UnknownArchive
|
||||
, ArchiveResult
|
||||
, FileDoesNotExistError
|
||||
, CopyError
|
||||
, NotInstalled
|
||||
, DirNotEmpty
|
||||
, NoDownload
|
||||
, NotInstalled
|
||||
, BuildFailed
|
||||
, TagNotFound
|
||||
, DigestError
|
||||
, GPGError
|
||||
, DownloadFailed
|
||||
, TarDirDoesNotExist
|
||||
, NextVerNotFound
|
||||
, NoToolVersionSet
|
||||
, FileAlreadyExistsError
|
||||
, ProcessError
|
||||
]
|
||||
|
||||
|
||||
runInstTool :: AppState
|
||||
-> Maybe PlatformRequest
|
||||
-> Excepts InstallEffects (ResourceT (ReaderT AppState IO)) a
|
||||
-> IO (VEither InstallEffects a)
|
||||
runInstTool appstate' mInstPlatform =
|
||||
flip runReaderT (maybe appstate' (\x -> appstate'{ pfreq = x } :: AppState) mInstPlatform)
|
||||
. runResourceT
|
||||
. runE
|
||||
@InstallEffects
|
||||
|
||||
|
||||
|
||||
-------------------
|
||||
--[ Entrypoints ]--
|
||||
-------------------
|
||||
|
||||
|
||||
install :: Either InstallCommand InstallOptions -> Settings -> IO AppState -> (ReaderT LeanAppState IO () -> IO ()) -> IO ExitCode
|
||||
install installCommand settings getAppState' runLogger = case installCommand of
|
||||
(Right iopts) -> do
|
||||
runLogger (logWarn "This is an old-style command for installing GHC. Use 'ghcup install ghc' instead.")
|
||||
installGHC iopts
|
||||
(Left (InstallGHC iopts)) -> installGHC iopts
|
||||
(Left (InstallCabal iopts)) -> installCabal iopts
|
||||
(Left (InstallHLS iopts)) -> installHLS iopts
|
||||
(Left (InstallStack iopts)) -> installStack iopts
|
||||
where
|
||||
installGHC :: InstallOptions -> IO ExitCode
|
||||
installGHC InstallOptions{..} = do
|
||||
s'@AppState{ dirs = Dirs{ .. } } <- liftIO getAppState'
|
||||
(case instBindist of
|
||||
Nothing -> runInstTool s' instPlatform $ do
|
||||
(v, vi) <- liftE $ fromVersion instVer GHC
|
||||
liftE $ installGHCBin
|
||||
(_tvVersion v)
|
||||
isolateDir
|
||||
forceInstall
|
||||
when instSet $ void $ liftE $ setGHC v SetGHCOnly
|
||||
pure vi
|
||||
Just uri -> do
|
||||
runInstTool s'{ settings = settings {noVerify = True}} instPlatform $ do
|
||||
(v, vi) <- liftE $ fromVersion instVer GHC
|
||||
liftE $ installGHCBindist
|
||||
(DownloadInfo uri (Just $ RegexDir "ghc-.*") "")
|
||||
(_tvVersion v)
|
||||
isolateDir
|
||||
forceInstall
|
||||
when instSet $ void $ liftE $ setGHC v SetGHCOnly
|
||||
pure vi
|
||||
)
|
||||
>>= \case
|
||||
VRight vi -> do
|
||||
runLogger $ logInfo "GHC installation successful"
|
||||
forM_ (_viPostInstall =<< vi) $ \msg ->
|
||||
runLogger $ logInfo msg
|
||||
pure ExitSuccess
|
||||
VLeft (V (AlreadyInstalled _ v)) -> do
|
||||
runLogger $ logWarn $
|
||||
"GHC ver " <> prettyVer v <> " already installed; if you really want to reinstall it, you may want to run 'ghcup install ghc --force " <> prettyVer v <> "'"
|
||||
pure ExitSuccess
|
||||
VLeft (V (DirNotEmpty fp)) -> do
|
||||
runLogger $ logWarn $
|
||||
"Install directory " <> T.pack fp <> " is not empty. Use 'ghcup install ghc --isolate " <> T.pack fp <> " --force ..." <> "' to install regardless."
|
||||
pure $ ExitFailure 3
|
||||
VLeft err@(V (BuildFailed tmpdir _)) -> do
|
||||
case keepDirs settings of
|
||||
Never -> runLogger (logError $ T.pack $ prettyShow err)
|
||||
_ -> runLogger (logError $ T.pack (prettyShow err) <> "\n" <>
|
||||
"Check the logs at " <> T.pack logsDir <> " and the build directory " <> T.pack tmpdir <> " for more clues." <> "\n" <>
|
||||
"Make sure to clean up " <> T.pack tmpdir <> " afterwards.")
|
||||
pure $ ExitFailure 3
|
||||
VLeft e -> do
|
||||
runLogger $ do
|
||||
logError $ T.pack $ prettyShow e
|
||||
logError $ "Also check the logs in " <> T.pack logsDir
|
||||
pure $ ExitFailure 3
|
||||
|
||||
|
||||
installCabal :: InstallOptions -> IO ExitCode
|
||||
installCabal InstallOptions{..} = do
|
||||
s'@AppState{ dirs = Dirs{ .. } } <- liftIO getAppState'
|
||||
(case instBindist of
|
||||
Nothing -> runInstTool s' instPlatform $ do
|
||||
(v, vi) <- liftE $ fromVersion instVer Cabal
|
||||
liftE $ installCabalBin
|
||||
(_tvVersion v)
|
||||
isolateDir
|
||||
forceInstall
|
||||
pure vi
|
||||
Just uri -> do
|
||||
runInstTool s'{ settings = settings { noVerify = True}} instPlatform $ do
|
||||
(v, vi) <- liftE $ fromVersion instVer Cabal
|
||||
liftE $ installCabalBindist
|
||||
(DownloadInfo uri Nothing "")
|
||||
(_tvVersion v)
|
||||
isolateDir
|
||||
forceInstall
|
||||
pure vi
|
||||
)
|
||||
>>= \case
|
||||
VRight vi -> do
|
||||
runLogger $ logInfo "Cabal installation successful"
|
||||
forM_ (_viPostInstall =<< vi) $ \msg ->
|
||||
runLogger $ logInfo msg
|
||||
pure ExitSuccess
|
||||
VLeft (V (AlreadyInstalled _ v)) -> do
|
||||
runLogger $ logWarn $
|
||||
"Cabal ver " <> prettyVer v <> " already installed; if you really want to reinstall it, you may want to run 'ghcup install cabal --force " <> prettyVer v <> "'"
|
||||
pure ExitSuccess
|
||||
VLeft (V (FileAlreadyExistsError fp)) -> do
|
||||
runLogger $ logWarn $
|
||||
"File " <> T.pack fp <> " already exists. Use 'ghcup install cabal --isolate " <> T.pack fp <> " --force ..." <> "' if you want to overwrite."
|
||||
pure $ ExitFailure 3
|
||||
VLeft e -> do
|
||||
runLogger $ do
|
||||
logError $ T.pack $ prettyShow e
|
||||
logError $ "Also check the logs in " <> T.pack logsDir
|
||||
pure $ ExitFailure 4
|
||||
|
||||
installHLS :: InstallOptions -> IO ExitCode
|
||||
installHLS InstallOptions{..} = do
|
||||
s'@AppState{ dirs = Dirs{ .. } } <- liftIO getAppState'
|
||||
(case instBindist of
|
||||
Nothing -> runInstTool s' instPlatform $ do
|
||||
(v, vi) <- liftE $ fromVersion instVer HLS
|
||||
liftE $ installHLSBin
|
||||
(_tvVersion v)
|
||||
isolateDir
|
||||
forceInstall
|
||||
pure vi
|
||||
Just uri -> do
|
||||
runInstTool s'{ settings = settings { noVerify = True}} instPlatform $ do
|
||||
(v, vi) <- liftE $ fromVersion instVer HLS
|
||||
liftE $ installHLSBindist
|
||||
(DownloadInfo uri Nothing "")
|
||||
(_tvVersion v)
|
||||
isolateDir
|
||||
forceInstall
|
||||
pure vi
|
||||
)
|
||||
>>= \case
|
||||
VRight vi -> do
|
||||
runLogger $ logInfo "HLS installation successful"
|
||||
forM_ (_viPostInstall =<< vi) $ \msg ->
|
||||
runLogger $ logInfo msg
|
||||
pure ExitSuccess
|
||||
VLeft (V (AlreadyInstalled _ v)) -> do
|
||||
runLogger $ logWarn $
|
||||
"HLS ver "
|
||||
<> prettyVer v
|
||||
<> " already installed; if you really want to reinstall it, you may want to run 'ghcup install hls --force "
|
||||
<> prettyVer v
|
||||
<> "'"
|
||||
pure ExitSuccess
|
||||
VLeft (V (FileAlreadyExistsError fp)) -> do
|
||||
runLogger $ logWarn $
|
||||
"File " <> T.pack fp <> " already exists. Use 'ghcup install hls --isolate " <> T.pack fp <> " --force ..." <> "' if you want to overwrite."
|
||||
pure $ ExitFailure 3
|
||||
VLeft e -> do
|
||||
runLogger $ do
|
||||
logError $ T.pack $ prettyShow e
|
||||
logError $ "Also check the logs in " <> T.pack logsDir
|
||||
pure $ ExitFailure 4
|
||||
|
||||
installStack :: InstallOptions -> IO ExitCode
|
||||
installStack InstallOptions{..} = do
|
||||
s'@AppState{ dirs = Dirs{ .. } } <- liftIO getAppState'
|
||||
(case instBindist of
|
||||
Nothing -> runInstTool s' instPlatform $ do
|
||||
(v, vi) <- liftE $ fromVersion instVer Stack
|
||||
liftE $ installStackBin
|
||||
(_tvVersion v)
|
||||
isolateDir
|
||||
forceInstall
|
||||
pure vi
|
||||
Just uri -> do
|
||||
runInstTool s'{ settings = settings { noVerify = True}} instPlatform $ do
|
||||
(v, vi) <- liftE $ fromVersion instVer Stack
|
||||
liftE $ installStackBindist
|
||||
(DownloadInfo uri Nothing "")
|
||||
(_tvVersion v)
|
||||
isolateDir
|
||||
forceInstall
|
||||
pure vi
|
||||
)
|
||||
>>= \case
|
||||
VRight vi -> do
|
||||
runLogger $ logInfo "Stack installation successful"
|
||||
forM_ (_viPostInstall =<< vi) $ \msg ->
|
||||
runLogger $ logInfo msg
|
||||
pure ExitSuccess
|
||||
VLeft (V (AlreadyInstalled _ v)) -> do
|
||||
runLogger $ logWarn $
|
||||
"Stack ver " <> prettyVer v <> " already installed; if you really want to reinstall it, you may want to run 'ghcup install stack --force " <> prettyVer v <> "'"
|
||||
pure ExitSuccess
|
||||
VLeft (V (FileAlreadyExistsError fp)) -> do
|
||||
runLogger $ logWarn $
|
||||
"File " <> T.pack fp <> " already exists. Use 'ghcup install stack --isolate " <> T.pack fp <> " --force ..." <> "' if you want to overwrite."
|
||||
pure $ ExitFailure 3
|
||||
VLeft e -> do
|
||||
runLogger $ do
|
||||
logError $ T.pack $ prettyShow e
|
||||
logError $ "Also check the logs in " <> T.pack logsDir
|
||||
pure $ ExitFailure 4
|
||||
|
||||
263
app/ghcup/GHCup/OptParse/List.hs
Normal file
@@ -0,0 +1,263 @@
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE DuplicateRecordFields #-}
|
||||
{-# LANGUAGE RankNTypes #-}
|
||||
|
||||
module GHCup.OptParse.List where
|
||||
|
||||
|
||||
|
||||
|
||||
import GHCup
|
||||
import GHCup.Prelude
|
||||
import GHCup.Types
|
||||
import GHCup.OptParse.Common
|
||||
|
||||
#if !MIN_VERSION_base(4,13,0)
|
||||
import Control.Monad.Fail ( MonadFail )
|
||||
#endif
|
||||
import Control.Monad.Reader
|
||||
import Control.Monad.Trans.Resource
|
||||
import Data.Char
|
||||
import Data.List ( intercalate, sort )
|
||||
import Data.Functor
|
||||
import Data.Maybe
|
||||
import Data.Versions hiding ( str )
|
||||
import Data.Void
|
||||
import Options.Applicative hiding ( style )
|
||||
import Prelude hiding ( appendFile )
|
||||
import System.Exit
|
||||
import System.Console.Pretty hiding ( color )
|
||||
|
||||
import qualified Data.Text as T
|
||||
import qualified System.Console.Pretty as Pretty
|
||||
import Control.Exception.Safe (MonadMask)
|
||||
import qualified Text.Megaparsec as MP
|
||||
import qualified Text.Megaparsec.Char as MPC
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
---------------
|
||||
--[ Options ]--
|
||||
---------------
|
||||
|
||||
|
||||
data ListOptions = ListOptions
|
||||
{ loTool :: Maybe Tool
|
||||
, lCriteria :: Maybe ListCriteria
|
||||
, lRawFormat :: Bool
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
---------------
|
||||
--[ Parsers ]--
|
||||
---------------
|
||||
|
||||
|
||||
listOpts :: Parser ListOptions
|
||||
listOpts =
|
||||
ListOptions
|
||||
<$> optional
|
||||
(option
|
||||
(eitherReader toolParser)
|
||||
(short 't' <> long "tool" <> metavar "<ghc|cabal|hls|stack>" <> help
|
||||
"Tool to list versions for. Default is all"
|
||||
)
|
||||
)
|
||||
<*> optional
|
||||
(option
|
||||
(eitherReader criteriaParser)
|
||||
( short 'c'
|
||||
<> long "show-criteria"
|
||||
<> metavar "<installed|set|available>"
|
||||
<> help "Show only installed/set/available tool versions"
|
||||
)
|
||||
)
|
||||
<*> switch
|
||||
(short 'r' <> long "raw-format" <> help "More machine-parsable format"
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
-----------------
|
||||
--[ Utilities ]--
|
||||
-----------------
|
||||
|
||||
|
||||
printListResult :: Bool -> Bool -> [ListResult] -> IO ()
|
||||
printListResult no_color raw lr = do
|
||||
|
||||
let
|
||||
color | raw || no_color = (\_ x -> x)
|
||||
| otherwise = Pretty.color
|
||||
|
||||
let
|
||||
printTag Recommended = color Green "recommended"
|
||||
printTag Latest = color Yellow "latest"
|
||||
printTag Prerelease = color Red "prerelease"
|
||||
printTag (Base pvp'') = "base-" ++ T.unpack (prettyPVP pvp'')
|
||||
printTag (UnknownTag t ) = t
|
||||
printTag Old = ""
|
||||
|
||||
let
|
||||
rows =
|
||||
(\x -> if raw
|
||||
then x
|
||||
else [color Green "", "Tool", "Version", "Tags", "Notes"] : x
|
||||
)
|
||||
. fmap
|
||||
(\ListResult {..} ->
|
||||
let marks = if
|
||||
| lSet -> (color Green (if isWindows then "IS" else "✔✔"))
|
||||
| lInstalled -> (color Green (if isWindows then "I " else "✓ "))
|
||||
| otherwise -> (color Red (if isWindows then "X " else "✗ "))
|
||||
in
|
||||
(if raw then [] else [marks])
|
||||
++ [ fmap toLower . show $ lTool
|
||||
, case lCross of
|
||||
Nothing -> T.unpack . prettyVer $ lVer
|
||||
Just c -> T.unpack (c <> "-" <> prettyVer lVer)
|
||||
, intercalate "," (filter (/= "") . fmap printTag $ sort lTag)
|
||||
, intercalate ","
|
||||
$ (if hlsPowered
|
||||
then [color Green "hls-powered"]
|
||||
else mempty
|
||||
)
|
||||
++ (if fromSrc then [color Blue "compiled"] else mempty)
|
||||
++ (if lStray then [color Yellow "stray"] else mempty)
|
||||
++ (if lNoBindist
|
||||
then [color Red "no-bindist"]
|
||||
else mempty
|
||||
)
|
||||
]
|
||||
)
|
||||
$ lr
|
||||
let cols =
|
||||
foldr (\xs ys -> zipWith (:) xs ys) (replicate (length rows) []) rows
|
||||
lengths = fmap (maximum . fmap strWidth) cols
|
||||
padded = fmap (\xs -> zipWith padTo xs lengths) rows
|
||||
|
||||
forM_ padded $ \row -> putStrLn $ unwords row
|
||||
where
|
||||
|
||||
padTo str' x =
|
||||
let lstr = strWidth str'
|
||||
add' = x - lstr
|
||||
in if add' < 0 then str' else str' ++ replicate add' ' '
|
||||
|
||||
-- | Calculate the render width of a string, considering
|
||||
-- wide characters (counted as double width), ANSI escape codes
|
||||
-- (not counted), and line breaks (in a multi-line string, the longest
|
||||
-- line determines the width).
|
||||
strWidth :: String -> Int
|
||||
strWidth =
|
||||
maximum
|
||||
. (0 :)
|
||||
. map (foldr (\a b -> charWidth a + b) 0)
|
||||
. lines
|
||||
. stripAnsi
|
||||
|
||||
-- | Strip ANSI escape sequences from a string.
|
||||
--
|
||||
-- >>> stripAnsi "\ESC[31m-1\ESC[m"
|
||||
-- "-1"
|
||||
stripAnsi :: String -> String
|
||||
stripAnsi s' =
|
||||
case
|
||||
MP.parseMaybe (many $ "" <$ MP.try ansi <|> pure <$> MP.anySingle) s'
|
||||
of
|
||||
Nothing -> error "Bad ansi escape" -- PARTIAL: should not happen
|
||||
Just xs -> concat xs
|
||||
where
|
||||
-- This parses lots of invalid ANSI escape codes, but that should be fine
|
||||
ansi =
|
||||
MPC.string "\ESC[" *> digitSemicolons *> suffix MP.<?> "ansi" :: MP.Parsec
|
||||
Void
|
||||
String
|
||||
Char
|
||||
digitSemicolons = MP.takeWhileP Nothing (\c -> isDigit c || c == ';')
|
||||
suffix = MP.oneOf ['A', 'B', 'C', 'D', 'H', 'J', 'K', 'f', 'm', 's', 'u']
|
||||
|
||||
-- | Get the designated render width of a character: 0 for a combining
|
||||
-- character, 1 for a regular character, 2 for a wide character.
|
||||
-- (Wide characters are rendered as exactly double width in apps and
|
||||
-- fonts that support it.) (From Pandoc.)
|
||||
charWidth :: Char -> Int
|
||||
charWidth c = case c of
|
||||
_ | c < '\x0300' -> 1
|
||||
| c >= '\x0300' && c <= '\x036F' -> 0
|
||||
| -- combining
|
||||
c >= '\x0370' && c <= '\x10FC' -> 1
|
||||
| c >= '\x1100' && c <= '\x115F' -> 2
|
||||
| c >= '\x1160' && c <= '\x11A2' -> 1
|
||||
| c >= '\x11A3' && c <= '\x11A7' -> 2
|
||||
| c >= '\x11A8' && c <= '\x11F9' -> 1
|
||||
| c >= '\x11FA' && c <= '\x11FF' -> 2
|
||||
| c >= '\x1200' && c <= '\x2328' -> 1
|
||||
| c >= '\x2329' && c <= '\x232A' -> 2
|
||||
| c >= '\x232B' && c <= '\x2E31' -> 1
|
||||
| c >= '\x2E80' && c <= '\x303E' -> 2
|
||||
| c == '\x303F' -> 1
|
||||
| c >= '\x3041' && c <= '\x3247' -> 2
|
||||
| c >= '\x3248' && c <= '\x324F' -> 1
|
||||
| -- ambiguous
|
||||
c >= '\x3250' && c <= '\x4DBF' -> 2
|
||||
| c >= '\x4DC0' && c <= '\x4DFF' -> 1
|
||||
| c >= '\x4E00' && c <= '\xA4C6' -> 2
|
||||
| c >= '\xA4D0' && c <= '\xA95F' -> 1
|
||||
| c >= '\xA960' && c <= '\xA97C' -> 2
|
||||
| c >= '\xA980' && c <= '\xABF9' -> 1
|
||||
| c >= '\xAC00' && c <= '\xD7FB' -> 2
|
||||
| c >= '\xD800' && c <= '\xDFFF' -> 1
|
||||
| c >= '\xE000' && c <= '\xF8FF' -> 1
|
||||
| -- ambiguous
|
||||
c >= '\xF900' && c <= '\xFAFF' -> 2
|
||||
| c >= '\xFB00' && c <= '\xFDFD' -> 1
|
||||
| c >= '\xFE00' && c <= '\xFE0F' -> 1
|
||||
| -- ambiguous
|
||||
c >= '\xFE10' && c <= '\xFE19' -> 2
|
||||
| c >= '\xFE20' && c <= '\xFE26' -> 1
|
||||
| c >= '\xFE30' && c <= '\xFE6B' -> 2
|
||||
| c >= '\xFE70' && c <= '\xFEFF' -> 1
|
||||
| c >= '\xFF01' && c <= '\xFF60' -> 2
|
||||
| c >= '\xFF61' && c <= '\x16A38' -> 1
|
||||
| c >= '\x1B000' && c <= '\x1B001' -> 2
|
||||
| c >= '\x1D000' && c <= '\x1F1FF' -> 1
|
||||
| c >= '\x1F200' && c <= '\x1F251' -> 2
|
||||
| c >= '\x1F300' && c <= '\x1F773' -> 1
|
||||
| c >= '\x20000' && c <= '\x3FFFD' -> 2
|
||||
| otherwise -> 1
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
------------------
|
||||
--[ Entrypoint ]--
|
||||
------------------
|
||||
|
||||
|
||||
|
||||
list :: ( Monad m
|
||||
, MonadMask m
|
||||
, MonadUnliftIO m
|
||||
, MonadFail m
|
||||
)
|
||||
=> ListOptions
|
||||
-> Bool
|
||||
-> (ReaderT AppState m ExitCode -> m ExitCode)
|
||||
-> m ExitCode
|
||||
list ListOptions{..} no_color runAppState =
|
||||
runAppState (do
|
||||
l <- listVersions loTool lCriteria
|
||||
liftIO $ printListResult no_color lRawFormat l
|
||||
pure ExitSuccess
|
||||
)
|
||||
99
app/ghcup/GHCup/OptParse/Nuke.hs
Normal file
@@ -0,0 +1,99 @@
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE TypeApplications #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE DuplicateRecordFields #-}
|
||||
{-# LANGUAGE RankNTypes #-}
|
||||
|
||||
module GHCup.OptParse.Nuke where
|
||||
|
||||
|
||||
|
||||
|
||||
import GHCup
|
||||
import GHCup.Errors
|
||||
import GHCup.Types
|
||||
import GHCup.Logger
|
||||
|
||||
#if !MIN_VERSION_base(4,13,0)
|
||||
import Control.Monad.Fail ( MonadFail )
|
||||
#endif
|
||||
import Control.Monad.Reader
|
||||
import Control.Monad.Trans.Resource
|
||||
import Data.Maybe
|
||||
import Haskus.Utils.Variant.Excepts
|
||||
import Options.Applicative hiding ( style )
|
||||
import Prelude hiding ( appendFile )
|
||||
import System.Exit
|
||||
import Text.PrettyPrint.HughesPJClass ( prettyShow )
|
||||
|
||||
import qualified Data.Text as T
|
||||
import Control.Exception.Safe (MonadMask)
|
||||
import Control.DeepSeq
|
||||
import Control.Exception
|
||||
import Control.Concurrent (threadDelay)
|
||||
|
||||
|
||||
|
||||
|
||||
---------------------------
|
||||
--[ Effect interpreters ]--
|
||||
---------------------------
|
||||
|
||||
|
||||
type NukeEffects = '[ NotInstalled ]
|
||||
|
||||
|
||||
runNuke :: AppState
|
||||
-> Excepts NukeEffects (ReaderT AppState m) a
|
||||
-> m (VEither NukeEffects a)
|
||||
runNuke s' =
|
||||
flip runReaderT s' . runE @NukeEffects
|
||||
|
||||
|
||||
|
||||
------------------
|
||||
--[ Entrypoint ]--
|
||||
------------------
|
||||
|
||||
|
||||
|
||||
nuke :: ( Monad m
|
||||
, MonadMask m
|
||||
, MonadUnliftIO m
|
||||
, MonadFail m
|
||||
)
|
||||
=> IO AppState
|
||||
-> (ReaderT LeanAppState m () -> m ())
|
||||
-> m ExitCode
|
||||
nuke appState runLogger = do
|
||||
s' <- liftIO appState
|
||||
void $ liftIO $ evaluate $ force s'
|
||||
runNuke s' (do
|
||||
lift $ logWarn "WARNING: This will remove GHCup and all installed components from your system."
|
||||
lift $ logWarn "Waiting 10 seconds before commencing, if you want to cancel it, now would be the time."
|
||||
liftIO $ threadDelay 10000000 -- wait 10s
|
||||
|
||||
lift $ logInfo "Initiating Nuclear Sequence 🚀🚀🚀"
|
||||
lift $ logInfo "Nuking in 3...2...1"
|
||||
|
||||
lInstalled <- lift $ listVersions Nothing (Just ListInstalled)
|
||||
|
||||
forM_ lInstalled (liftE . rmTool)
|
||||
|
||||
lift rmGhcupDirs
|
||||
|
||||
) >>= \case
|
||||
VRight leftOverFiles
|
||||
| null leftOverFiles -> do
|
||||
runLogger $ logInfo "Nuclear Annihilation complete!"
|
||||
pure ExitSuccess
|
||||
| otherwise -> do
|
||||
runLogger $ logError "These Files have survived Nuclear Annihilation, you may remove them manually."
|
||||
liftIO $ forM_ leftOverFiles putStrLn
|
||||
pure ExitSuccess
|
||||
|
||||
VLeft e -> do
|
||||
runLogger $ logError $ T.pack $ prettyShow e
|
||||
pure $ ExitFailure 15
|
||||
219
app/ghcup/GHCup/OptParse/Prefetch.hs
Normal file
@@ -0,0 +1,219 @@
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE TypeApplications #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE TemplateHaskell #-}
|
||||
{-# LANGUAGE QuasiQuotes #-}
|
||||
{-# LANGUAGE DuplicateRecordFields #-}
|
||||
{-# LANGUAGE RankNTypes #-}
|
||||
|
||||
module GHCup.OptParse.Prefetch where
|
||||
|
||||
|
||||
import GHCup
|
||||
import GHCup.Errors
|
||||
import GHCup.Types
|
||||
import GHCup.Logger
|
||||
import GHCup.OptParse.Common
|
||||
import GHCup.QQ.String
|
||||
|
||||
#if !MIN_VERSION_base(4,13,0)
|
||||
import Control.Monad.Fail ( MonadFail )
|
||||
#endif
|
||||
import Control.Monad.Reader
|
||||
import Control.Monad.Trans.Resource
|
||||
import Data.Functor
|
||||
import Data.Maybe
|
||||
import Haskus.Utils.Variant.Excepts
|
||||
import Options.Applicative hiding ( style )
|
||||
import Prelude hiding ( appendFile )
|
||||
import System.Exit
|
||||
import Text.PrettyPrint.HughesPJClass ( prettyShow )
|
||||
|
||||
import qualified Data.Text as T
|
||||
import Control.Exception.Safe (MonadMask)
|
||||
import GHCup.Prelude
|
||||
import GHCup.Download (getDownloadsF)
|
||||
|
||||
|
||||
|
||||
|
||||
----------------
|
||||
--[ Commands ]--
|
||||
----------------
|
||||
|
||||
|
||||
data PrefetchCommand = PrefetchGHC PrefetchGHCOptions (Maybe ToolVersion)
|
||||
| PrefetchCabal PrefetchOptions (Maybe ToolVersion)
|
||||
| PrefetchHLS PrefetchOptions (Maybe ToolVersion)
|
||||
| PrefetchStack PrefetchOptions (Maybe ToolVersion)
|
||||
| PrefetchMetadata
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
---------------
|
||||
--[ Options ]--
|
||||
---------------
|
||||
|
||||
|
||||
data PrefetchOptions = PrefetchOptions {
|
||||
pfCacheDir :: Maybe FilePath
|
||||
}
|
||||
|
||||
data PrefetchGHCOptions = PrefetchGHCOptions {
|
||||
pfGHCSrc :: Bool
|
||||
, pfGHCCacheDir :: Maybe FilePath
|
||||
}
|
||||
|
||||
|
||||
|
||||
---------------
|
||||
--[ Parsers ]--
|
||||
---------------
|
||||
|
||||
|
||||
prefetchP :: Parser PrefetchCommand
|
||||
prefetchP = subparser
|
||||
( command
|
||||
"ghc"
|
||||
(info
|
||||
(PrefetchGHC
|
||||
<$> (PrefetchGHCOptions
|
||||
<$> ( switch (short 's' <> long "source" <> help "Download source tarball instead of bindist") <**> helper )
|
||||
<*> optional (option str (short 'd' <> long "directory" <> help "directory to download into (default: ~/.ghcup/cache/)")))
|
||||
<*> optional (toolVersionArgument Nothing (Just GHC)) )
|
||||
( progDesc "Download GHC assets for installation")
|
||||
)
|
||||
<>
|
||||
command
|
||||
"cabal"
|
||||
(info
|
||||
(PrefetchCabal
|
||||
<$> fmap PrefetchOptions (optional (option str (short 'd' <> long "directory" <> help "directory to download into (default: ~/.ghcup/cache/)")))
|
||||
<*> ( optional (toolVersionArgument Nothing (Just Cabal)) <**> helper ))
|
||||
( progDesc "Download cabal assets for installation")
|
||||
)
|
||||
<>
|
||||
command
|
||||
"hls"
|
||||
(info
|
||||
(PrefetchHLS
|
||||
<$> fmap PrefetchOptions (optional (option str (short 'd' <> long "directory" <> help "directory to download into (default: ~/.ghcup/cache/)")))
|
||||
<*> ( optional (toolVersionArgument Nothing (Just HLS)) <**> helper ))
|
||||
( progDesc "Download HLS assets for installation")
|
||||
)
|
||||
<>
|
||||
command
|
||||
"stack"
|
||||
(info
|
||||
(PrefetchStack
|
||||
<$> fmap PrefetchOptions (optional (option str (short 'd' <> long "directory" <> help "directory to download into (default: ~/.ghcup/cache/)")))
|
||||
<*> ( optional (toolVersionArgument Nothing (Just Stack)) <**> helper ))
|
||||
( progDesc "Download stack assets for installation")
|
||||
)
|
||||
<>
|
||||
command
|
||||
"metadata"
|
||||
(PrefetchMetadata <$ info
|
||||
helper
|
||||
( progDesc "Download ghcup's metadata, needed for various operations")
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
|
||||
--------------
|
||||
--[ Footer ]--
|
||||
--------------
|
||||
|
||||
|
||||
prefetchFooter :: String
|
||||
prefetchFooter = [s|Discussion:
|
||||
Prefetches tools or assets into "~/.ghcup/cache" directory. This can
|
||||
be then combined later with '--offline' flag, ensuring all assets that
|
||||
are required for offline use have been prefetched.
|
||||
|
||||
Examples:
|
||||
ghcup prefetch metadata
|
||||
ghcup prefetch ghc 8.10.5
|
||||
ghcup --offline install ghc 8.10.5|]
|
||||
|
||||
|
||||
|
||||
---------------------------
|
||||
--[ Effect interpreters ]--
|
||||
---------------------------
|
||||
|
||||
|
||||
type PrefetchEffects = '[ TagNotFound
|
||||
, NextVerNotFound
|
||||
, NoToolVersionSet
|
||||
, NoDownload
|
||||
, DigestError
|
||||
, GPGError
|
||||
, DownloadFailed
|
||||
, JSONError
|
||||
, FileDoesNotExistError ]
|
||||
|
||||
|
||||
runPrefetch :: MonadUnliftIO m
|
||||
=> (ReaderT AppState m (VEither PrefetchEffects a) -> m (VEither PrefetchEffects a))
|
||||
-> Excepts PrefetchEffects (ResourceT (ReaderT AppState m)) a
|
||||
-> m (VEither PrefetchEffects a)
|
||||
runPrefetch runAppState =
|
||||
runAppState
|
||||
. runResourceT
|
||||
. runE
|
||||
@PrefetchEffects
|
||||
|
||||
|
||||
|
||||
------------------
|
||||
--[ Entrypoint ]--
|
||||
------------------
|
||||
|
||||
|
||||
|
||||
prefetch :: ( Monad m
|
||||
, MonadMask m
|
||||
, MonadUnliftIO m
|
||||
, MonadFail m
|
||||
)
|
||||
=> PrefetchCommand
|
||||
-> (forall a. ReaderT AppState m (VEither PrefetchEffects a) -> m (VEither PrefetchEffects a))
|
||||
-> (ReaderT LeanAppState m () -> m ())
|
||||
-> m ExitCode
|
||||
prefetch prefetchCommand runAppState runLogger =
|
||||
runPrefetch runAppState (do
|
||||
case prefetchCommand of
|
||||
PrefetchGHC
|
||||
(PrefetchGHCOptions pfGHCSrc pfCacheDir) mt -> do
|
||||
forM_ pfCacheDir (liftIO . createDirRecursive')
|
||||
(v, _) <- liftE $ fromVersion mt GHC
|
||||
if pfGHCSrc
|
||||
then liftE $ fetchGHCSrc (_tvVersion v) pfCacheDir
|
||||
else liftE $ fetchToolBindist (_tvVersion v) GHC pfCacheDir
|
||||
PrefetchCabal PrefetchOptions {pfCacheDir} mt -> do
|
||||
forM_ pfCacheDir (liftIO . createDirRecursive')
|
||||
(v, _) <- liftE $ fromVersion mt Cabal
|
||||
liftE $ fetchToolBindist (_tvVersion v) Cabal pfCacheDir
|
||||
PrefetchHLS PrefetchOptions {pfCacheDir} mt -> do
|
||||
forM_ pfCacheDir (liftIO . createDirRecursive')
|
||||
(v, _) <- liftE $ fromVersion mt HLS
|
||||
liftE $ fetchToolBindist (_tvVersion v) HLS pfCacheDir
|
||||
PrefetchStack PrefetchOptions {pfCacheDir} mt -> do
|
||||
forM_ pfCacheDir (liftIO . createDirRecursive')
|
||||
(v, _) <- liftE $ fromVersion mt Stack
|
||||
liftE $ fetchToolBindist (_tvVersion v) Stack pfCacheDir
|
||||
PrefetchMetadata -> do
|
||||
_ <- liftE getDownloadsF
|
||||
pure ""
|
||||
) >>= \case
|
||||
VRight _ -> do
|
||||
pure ExitSuccess
|
||||
VLeft e -> do
|
||||
runLogger $ logError $ T.pack $ prettyShow e
|
||||
pure $ ExitFailure 15
|
||||
232
app/ghcup/GHCup/OptParse/Rm.hs
Normal file
@@ -0,0 +1,232 @@
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE TypeApplications #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE TemplateHaskell #-}
|
||||
{-# LANGUAGE QuasiQuotes #-}
|
||||
{-# LANGUAGE DuplicateRecordFields #-}
|
||||
{-# LANGUAGE RankNTypes #-}
|
||||
|
||||
module GHCup.OptParse.Rm where
|
||||
|
||||
|
||||
|
||||
|
||||
import GHCup
|
||||
import GHCup.Errors
|
||||
import GHCup.Types
|
||||
import GHCup.Types.Optics
|
||||
import GHCup.Utils
|
||||
import GHCup.Logger
|
||||
import GHCup.OptParse.Common
|
||||
import GHCup.QQ.String
|
||||
|
||||
#if !MIN_VERSION_base(4,13,0)
|
||||
import Control.Monad.Fail ( MonadFail )
|
||||
#endif
|
||||
import Control.Monad.Reader
|
||||
import Control.Monad.Trans.Resource
|
||||
import Data.Functor
|
||||
import Data.Maybe
|
||||
import Data.Versions hiding ( str )
|
||||
import Haskus.Utils.Variant.Excepts
|
||||
import Options.Applicative hiding ( style )
|
||||
import Prelude hiding ( appendFile )
|
||||
import System.Exit
|
||||
import Text.PrettyPrint.HughesPJClass ( prettyShow )
|
||||
|
||||
import qualified Data.Text as T
|
||||
import Control.Exception.Safe (MonadMask)
|
||||
|
||||
|
||||
|
||||
|
||||
----------------
|
||||
--[ Commands ]--
|
||||
----------------
|
||||
|
||||
|
||||
data RmCommand = RmGHC RmOptions
|
||||
| RmCabal Version
|
||||
| RmHLS Version
|
||||
| RmStack Version
|
||||
|
||||
|
||||
|
||||
|
||||
---------------
|
||||
--[ Options ]--
|
||||
---------------
|
||||
|
||||
|
||||
data RmOptions = RmOptions
|
||||
{ ghcVer :: GHCTargetVersion
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
---------------
|
||||
--[ Parsers ]--
|
||||
---------------
|
||||
|
||||
|
||||
rmParser :: Parser (Either RmCommand RmOptions)
|
||||
rmParser =
|
||||
(Left <$> subparser
|
||||
( command
|
||||
"ghc"
|
||||
(RmGHC <$> info (rmOpts (Just GHC) <**> helper) (progDesc "Remove GHC version"))
|
||||
<> command
|
||||
"cabal"
|
||||
( RmCabal
|
||||
<$> info (versionParser' (Just ListInstalled) (Just Cabal) <**> helper)
|
||||
(progDesc "Remove Cabal version")
|
||||
)
|
||||
<> command
|
||||
"hls"
|
||||
( RmHLS
|
||||
<$> info (versionParser' (Just ListInstalled) (Just HLS) <**> helper)
|
||||
(progDesc "Remove haskell-language-server version")
|
||||
)
|
||||
<> command
|
||||
"stack"
|
||||
( RmStack
|
||||
<$> info (versionParser' (Just ListInstalled) (Just Stack) <**> helper)
|
||||
(progDesc "Remove stack version")
|
||||
)
|
||||
)
|
||||
)
|
||||
<|> (Right <$> rmOpts Nothing)
|
||||
|
||||
|
||||
|
||||
rmOpts :: Maybe Tool -> Parser RmOptions
|
||||
rmOpts tool = RmOptions <$> versionArgument (Just ListInstalled) tool
|
||||
|
||||
|
||||
|
||||
|
||||
--------------
|
||||
--[ Footer ]--
|
||||
--------------
|
||||
|
||||
|
||||
rmFooter :: String
|
||||
rmFooter = [s|Discussion:
|
||||
Remove the given GHC or cabal version. When no command is given,
|
||||
defaults to removing GHC with the specified version.
|
||||
It is recommended to always specify a subcommand (ghc/cabal/hls/stack).|]
|
||||
|
||||
|
||||
|
||||
|
||||
---------------------------
|
||||
--[ Effect interpreters ]--
|
||||
---------------------------
|
||||
|
||||
|
||||
type RmEffects = '[ NotInstalled ]
|
||||
|
||||
|
||||
runRm :: (ReaderT env m (VEither RmEffects a) -> m (VEither RmEffects a))
|
||||
-> Excepts RmEffects (ReaderT env m) a
|
||||
-> m (VEither RmEffects a)
|
||||
runRm runAppState =
|
||||
runAppState
|
||||
. runE
|
||||
@RmEffects
|
||||
|
||||
|
||||
|
||||
------------------
|
||||
--[ Entrypoint ]--
|
||||
------------------
|
||||
|
||||
|
||||
|
||||
rm :: ( Monad m
|
||||
, MonadMask m
|
||||
, MonadUnliftIO m
|
||||
, MonadFail m
|
||||
)
|
||||
=> Either RmCommand RmOptions
|
||||
-> (ReaderT AppState m (VEither RmEffects (Maybe VersionInfo))
|
||||
-> m (VEither RmEffects (Maybe VersionInfo)))
|
||||
-> (ReaderT LeanAppState m () -> m ())
|
||||
-> m ExitCode
|
||||
rm rmCommand runAppState runLogger = case rmCommand of
|
||||
(Right rmopts) -> do
|
||||
runLogger (logWarn "This is an old-style command for removing GHC. Use 'ghcup rm ghc' instead.")
|
||||
rmGHC' rmopts
|
||||
(Left (RmGHC rmopts)) -> rmGHC' rmopts
|
||||
(Left (RmCabal rmopts)) -> rmCabal' rmopts
|
||||
(Left (RmHLS rmopts)) -> rmHLS' rmopts
|
||||
(Left (RmStack rmopts)) -> rmStack' rmopts
|
||||
|
||||
where
|
||||
rmGHC' RmOptions{..} =
|
||||
runRm runAppState (do
|
||||
liftE $
|
||||
rmGHCVer ghcVer
|
||||
GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo
|
||||
pure (getVersionInfo (_tvVersion ghcVer) GHC dls)
|
||||
)
|
||||
>>= \case
|
||||
VRight vi -> do
|
||||
forM_ (_viPostRemove =<< vi) $ \msg ->
|
||||
runLogger $ logInfo msg
|
||||
pure ExitSuccess
|
||||
VLeft e -> do
|
||||
runLogger $ logError $ T.pack $ prettyShow e
|
||||
pure $ ExitFailure 7
|
||||
|
||||
rmCabal' tv =
|
||||
runRm runAppState (do
|
||||
liftE $
|
||||
rmCabalVer tv
|
||||
GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo
|
||||
pure (getVersionInfo tv Cabal dls)
|
||||
)
|
||||
>>= \case
|
||||
VRight vi -> do
|
||||
forM_ (_viPostRemove =<< vi) $ \msg ->
|
||||
runLogger $ logInfo msg
|
||||
pure ExitSuccess
|
||||
VLeft e -> do
|
||||
runLogger $ logError $ T.pack $ prettyShow e
|
||||
pure $ ExitFailure 15
|
||||
|
||||
rmHLS' tv =
|
||||
runRm runAppState (do
|
||||
liftE $
|
||||
rmHLSVer tv
|
||||
GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo
|
||||
pure (getVersionInfo tv HLS dls)
|
||||
)
|
||||
>>= \case
|
||||
VRight vi -> do
|
||||
forM_ (_viPostRemove =<< vi) $ \msg ->
|
||||
runLogger $ logInfo msg
|
||||
pure ExitSuccess
|
||||
VLeft e -> do
|
||||
runLogger $ logError $ T.pack $ prettyShow e
|
||||
pure $ ExitFailure 15
|
||||
|
||||
rmStack' tv =
|
||||
runRm runAppState (do
|
||||
liftE $
|
||||
rmStackVer tv
|
||||
GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo
|
||||
pure (getVersionInfo tv Stack dls)
|
||||
)
|
||||
>>= \case
|
||||
VRight vi -> do
|
||||
forM_ (_viPostRemove =<< vi) $ \msg ->
|
||||
runLogger $ logInfo msg
|
||||
pure ExitSuccess
|
||||
VLeft e -> do
|
||||
runLogger $ logError $ T.pack $ prettyShow e
|
||||
pure $ ExitFailure 15
|
||||
|
||||
349
app/ghcup/GHCup/OptParse/Set.hs
Normal file
@@ -0,0 +1,349 @@
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE TypeApplications #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE QuasiQuotes #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE DuplicateRecordFields #-}
|
||||
{-# LANGUAGE RankNTypes #-}
|
||||
|
||||
module GHCup.OptParse.Set where
|
||||
|
||||
|
||||
|
||||
|
||||
import GHCup.OptParse.Common
|
||||
|
||||
import GHCup
|
||||
import GHCup.Errors
|
||||
import GHCup.Types
|
||||
import GHCup.Logger
|
||||
import GHCup.QQ.String
|
||||
|
||||
#if !MIN_VERSION_base(4,13,0)
|
||||
import Control.Monad.Fail ( MonadFail )
|
||||
#endif
|
||||
import Control.Monad.Reader
|
||||
import Control.Monad.Trans.Resource
|
||||
import Data.Either
|
||||
import Data.Functor
|
||||
import Data.Maybe
|
||||
import Data.Versions hiding ( str )
|
||||
import GHC.Unicode
|
||||
import Haskus.Utils.Variant.Excepts
|
||||
import Options.Applicative hiding ( style )
|
||||
import Options.Applicative.Help.Pretty ( text )
|
||||
import Prelude hiding ( appendFile )
|
||||
import System.Exit
|
||||
import Text.PrettyPrint.HughesPJClass ( prettyShow )
|
||||
|
||||
import qualified Data.Text as T
|
||||
import Data.Bifunctor (second)
|
||||
import Control.Exception.Safe (MonadMask)
|
||||
import GHCup.Types.Optics
|
||||
|
||||
|
||||
|
||||
|
||||
----------------
|
||||
--[ Commands ]--
|
||||
----------------
|
||||
|
||||
|
||||
data SetCommand = SetGHC SetOptions
|
||||
| SetCabal SetOptions
|
||||
| SetHLS SetOptions
|
||||
| SetStack SetOptions
|
||||
|
||||
|
||||
|
||||
|
||||
---------------
|
||||
--[ Options ]--
|
||||
---------------
|
||||
|
||||
|
||||
data SetOptions = SetOptions
|
||||
{ sToolVer :: SetToolVersion
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
---------------
|
||||
--[ Parsers ]--
|
||||
---------------
|
||||
|
||||
|
||||
setParser :: Parser (Either SetCommand SetOptions)
|
||||
setParser =
|
||||
(Left <$> subparser
|
||||
( command
|
||||
"ghc"
|
||||
( SetGHC
|
||||
<$> info
|
||||
(setOpts (Just GHC) <**> helper)
|
||||
( progDesc "Set GHC version"
|
||||
<> footerDoc (Just $ text setGHCFooter)
|
||||
)
|
||||
)
|
||||
<> command
|
||||
"cabal"
|
||||
( SetCabal
|
||||
<$> info
|
||||
(setOpts (Just Cabal) <**> helper)
|
||||
( progDesc "Set Cabal version"
|
||||
<> footerDoc (Just $ text setCabalFooter)
|
||||
)
|
||||
)
|
||||
<> command
|
||||
"hls"
|
||||
( SetHLS
|
||||
<$> info
|
||||
(setOpts (Just HLS) <**> helper)
|
||||
( progDesc "Set haskell-language-server version"
|
||||
<> footerDoc (Just $ text setHLSFooter)
|
||||
)
|
||||
)
|
||||
<> command
|
||||
"stack"
|
||||
( SetStack
|
||||
<$> info
|
||||
(setOpts (Just Stack) <**> helper)
|
||||
( progDesc "Set stack version"
|
||||
<> footerDoc (Just $ text setStackFooter)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
<|> (Right <$> setOpts Nothing)
|
||||
where
|
||||
setGHCFooter :: String
|
||||
setGHCFooter = [s|Discussion:
|
||||
Sets the the current GHC version by creating non-versioned
|
||||
symlinks for all ghc binaries of the specified version in
|
||||
"~/.ghcup/bin/<binary>".|]
|
||||
|
||||
setCabalFooter :: String
|
||||
setCabalFooter = [s|Discussion:
|
||||
Sets the the current Cabal version.|]
|
||||
|
||||
setStackFooter :: String
|
||||
setStackFooter = [s|Discussion:
|
||||
Sets the the current Stack version.|]
|
||||
|
||||
setHLSFooter :: String
|
||||
setHLSFooter = [s|Discussion:
|
||||
Sets the the current haskell-language-server version.|]
|
||||
|
||||
|
||||
setOpts :: Maybe Tool -> Parser SetOptions
|
||||
setOpts tool = SetOptions <$>
|
||||
(fromMaybe SetRecommended <$>
|
||||
optional (setVersionArgument (Just ListInstalled) tool))
|
||||
|
||||
setVersionArgument :: Maybe ListCriteria -> Maybe Tool -> Parser SetToolVersion
|
||||
setVersionArgument criteria tool =
|
||||
argument (eitherReader setEither)
|
||||
(metavar "VERSION|TAG|next"
|
||||
<> completer (tagCompleter (fromMaybe GHC tool) ["next"])
|
||||
<> foldMap (completer . versionCompleter criteria) tool)
|
||||
where
|
||||
setEither s' =
|
||||
parseSet s'
|
||||
<|> second SetToolTag (tagEither s')
|
||||
<|> second SetToolVersion (tVersionEither s')
|
||||
parseSet s' = case fmap toLower s' of
|
||||
"next" -> Right SetNext
|
||||
other -> Left $ "Unknown tag/version " <> other
|
||||
|
||||
|
||||
|
||||
|
||||
--------------
|
||||
--[ Footer ]--
|
||||
--------------
|
||||
|
||||
|
||||
setFooter :: String
|
||||
setFooter = [s|Discussion:
|
||||
Sets the currently active GHC or cabal version. When no command is given,
|
||||
defaults to setting GHC with the specified version/tag (if no tag
|
||||
is given, sets GHC to 'recommended' version).
|
||||
It is recommended to always specify a subcommand (ghc/cabal/hls/stack).|]
|
||||
|
||||
|
||||
|
||||
---------------------------
|
||||
--[ Effect interpreters ]--
|
||||
---------------------------
|
||||
|
||||
|
||||
type SetGHCEffects = '[ FileDoesNotExistError
|
||||
, NotInstalled
|
||||
, TagNotFound
|
||||
, NextVerNotFound
|
||||
, NoToolVersionSet]
|
||||
|
||||
runSetGHC :: (ReaderT env m (VEither SetGHCEffects a) -> m (VEither SetGHCEffects a))
|
||||
-> Excepts SetGHCEffects (ReaderT env m) a
|
||||
-> m (VEither SetGHCEffects a)
|
||||
runSetGHC runAppState =
|
||||
runAppState
|
||||
. runE
|
||||
@SetGHCEffects
|
||||
|
||||
|
||||
type SetCabalEffects = '[ NotInstalled
|
||||
, TagNotFound
|
||||
, NextVerNotFound
|
||||
, NoToolVersionSet]
|
||||
|
||||
runSetCabal :: (ReaderT env m (VEither SetCabalEffects a) -> m (VEither SetCabalEffects a))
|
||||
-> Excepts SetCabalEffects (ReaderT env m) a
|
||||
-> m (VEither SetCabalEffects a)
|
||||
runSetCabal runAppState =
|
||||
runAppState
|
||||
. runE
|
||||
@SetCabalEffects
|
||||
|
||||
|
||||
type SetHLSEffects = '[ NotInstalled
|
||||
, TagNotFound
|
||||
, NextVerNotFound
|
||||
, NoToolVersionSet]
|
||||
|
||||
runSetHLS :: (ReaderT env m (VEither SetHLSEffects a) -> m (VEither SetHLSEffects a))
|
||||
-> Excepts SetHLSEffects (ReaderT env m) a
|
||||
-> m (VEither SetHLSEffects a)
|
||||
runSetHLS runAppState =
|
||||
runAppState
|
||||
. runE
|
||||
@SetHLSEffects
|
||||
|
||||
|
||||
type SetStackEffects = '[ NotInstalled
|
||||
, TagNotFound
|
||||
, NextVerNotFound
|
||||
, NoToolVersionSet]
|
||||
|
||||
runSetStack :: (ReaderT env m (VEither SetStackEffects a) -> m (VEither SetStackEffects a))
|
||||
-> Excepts SetStackEffects (ReaderT env m) a
|
||||
-> m (VEither SetStackEffects a)
|
||||
runSetStack runAppState =
|
||||
runAppState
|
||||
. runE
|
||||
@SetStackEffects
|
||||
|
||||
|
||||
|
||||
-------------------
|
||||
--[ Entrypoints ]--
|
||||
-------------------
|
||||
|
||||
|
||||
set :: forall m env.
|
||||
( Monad m
|
||||
, MonadMask m
|
||||
, MonadUnliftIO m
|
||||
, MonadFail m
|
||||
, HasDirs env
|
||||
, HasLog env
|
||||
)
|
||||
=> Either SetCommand SetOptions
|
||||
-> (forall eff . ReaderT AppState m (VEither eff GHCTargetVersion)
|
||||
-> m (VEither eff GHCTargetVersion))
|
||||
-> (forall eff. ReaderT env m (VEither eff GHCTargetVersion)
|
||||
-> m (VEither eff GHCTargetVersion))
|
||||
-> (ReaderT LeanAppState m () -> m ())
|
||||
-> m ExitCode
|
||||
set setCommand runAppState runLeanAppState runLogger = case setCommand of
|
||||
(Right sopts) -> do
|
||||
runLogger (logWarn "This is an old-style command for setting GHC. Use 'ghcup set ghc' instead.")
|
||||
setGHC' sopts
|
||||
(Left (SetGHC sopts)) -> setGHC' sopts
|
||||
(Left (SetCabal sopts)) -> setCabal' sopts
|
||||
(Left (SetHLS sopts)) -> setHLS' sopts
|
||||
(Left (SetStack sopts)) -> setStack' sopts
|
||||
|
||||
where
|
||||
setGHC' :: SetOptions
|
||||
-> m ExitCode
|
||||
setGHC' SetOptions{ sToolVer } =
|
||||
case sToolVer of
|
||||
(SetToolVersion v) -> runSetGHC runLeanAppState (liftE $ setGHC v SetGHCOnly >> pure v)
|
||||
_ -> runSetGHC runAppState (do
|
||||
v <- liftE $ fst <$> fromVersion' sToolVer GHC
|
||||
liftE $ setGHC v SetGHCOnly
|
||||
)
|
||||
>>= \case
|
||||
VRight GHCTargetVersion{..} -> do
|
||||
runLogger
|
||||
$ logInfo $
|
||||
"GHC " <> prettyVer _tvVersion <> " successfully set as default version" <> maybe "" (" for cross target " <>) _tvTarget
|
||||
pure ExitSuccess
|
||||
VLeft e -> do
|
||||
runLogger $ logError $ T.pack $ prettyShow e
|
||||
pure $ ExitFailure 5
|
||||
|
||||
|
||||
setCabal' :: SetOptions
|
||||
-> m ExitCode
|
||||
setCabal' SetOptions{ sToolVer } =
|
||||
case sToolVer of
|
||||
(SetToolVersion v) -> runSetCabal runLeanAppState (liftE $ setCabal (_tvVersion v) >> pure v)
|
||||
_ -> runSetCabal runAppState (do
|
||||
v <- liftE $ fst <$> fromVersion' sToolVer Cabal
|
||||
liftE $ setCabal (_tvVersion v)
|
||||
pure v
|
||||
)
|
||||
>>= \case
|
||||
VRight GHCTargetVersion{..} -> do
|
||||
runLogger
|
||||
$ logInfo $
|
||||
"Cabal " <> prettyVer _tvVersion <> " successfully set as default version"
|
||||
pure ExitSuccess
|
||||
VLeft e -> do
|
||||
runLogger $ logError $ T.pack $ prettyShow e
|
||||
pure $ ExitFailure 14
|
||||
|
||||
setHLS' :: SetOptions
|
||||
-> m ExitCode
|
||||
setHLS' SetOptions{ sToolVer } =
|
||||
case sToolVer of
|
||||
(SetToolVersion v) -> runSetHLS runLeanAppState (liftE $ setHLS (_tvVersion v) >> pure v)
|
||||
_ -> runSetHLS runAppState (do
|
||||
v <- liftE $ fst <$> fromVersion' sToolVer HLS
|
||||
liftE $ setHLS (_tvVersion v)
|
||||
pure v
|
||||
)
|
||||
>>= \case
|
||||
VRight GHCTargetVersion{..} -> do
|
||||
runLogger
|
||||
$ logInfo $
|
||||
"HLS " <> prettyVer _tvVersion <> " successfully set as default version"
|
||||
pure ExitSuccess
|
||||
VLeft e -> do
|
||||
runLogger $ logError $ T.pack $ prettyShow e
|
||||
pure $ ExitFailure 14
|
||||
|
||||
|
||||
setStack' :: SetOptions
|
||||
-> m ExitCode
|
||||
setStack' SetOptions{ sToolVer } =
|
||||
case sToolVer of
|
||||
(SetToolVersion v) -> runSetStack runLeanAppState (liftE $ setStack (_tvVersion v) >> pure v)
|
||||
_ -> runSetStack runAppState (do
|
||||
v <- liftE $ fst <$> fromVersion' sToolVer Stack
|
||||
liftE $ setStack (_tvVersion v)
|
||||
pure v
|
||||
)
|
||||
>>= \case
|
||||
VRight GHCTargetVersion{..} -> do
|
||||
runLogger
|
||||
$ logInfo $
|
||||
"Stack " <> prettyVer _tvVersion <> " successfully set as default version"
|
||||
pure ExitSuccess
|
||||
VLeft e -> do
|
||||
runLogger $ logError $ T.pack $ prettyShow e
|
||||
pure $ ExitFailure 14
|
||||
82
app/ghcup/GHCup/OptParse/ToolRequirements.hs
Normal file
@@ -0,0 +1,82 @@
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE TypeApplications #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE DuplicateRecordFields #-}
|
||||
{-# LANGUAGE RankNTypes #-}
|
||||
|
||||
module GHCup.OptParse.ToolRequirements where
|
||||
|
||||
|
||||
import GHCup.Errors
|
||||
import GHCup.Types
|
||||
import GHCup.Logger
|
||||
|
||||
#if !MIN_VERSION_base(4,13,0)
|
||||
import Control.Monad.Fail ( MonadFail )
|
||||
#endif
|
||||
import Control.Monad.Reader
|
||||
import Control.Monad.Trans.Resource
|
||||
import Haskus.Utils.Variant.Excepts
|
||||
import Options.Applicative hiding ( style )
|
||||
import Prelude hiding ( appendFile )
|
||||
import System.Exit
|
||||
import Text.PrettyPrint.HughesPJClass ( prettyShow )
|
||||
|
||||
import qualified Data.Text as T
|
||||
import qualified Data.Text.IO as T
|
||||
import Control.Exception.Safe (MonadMask)
|
||||
import GHCup.Types.Optics
|
||||
import GHCup.Platform
|
||||
import GHCup.Prelude
|
||||
import GHCup.Requirements
|
||||
import System.IO
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
---------------------------
|
||||
--[ Effect interpreters ]--
|
||||
---------------------------
|
||||
|
||||
|
||||
type ToolRequirementsEffects = '[ NoCompatiblePlatform , DistroNotFound , NoToolRequirements ]
|
||||
|
||||
|
||||
runToolRequirements :: (ReaderT env m (VEither ToolRequirementsEffects a) -> m (VEither ToolRequirementsEffects a))
|
||||
-> Excepts ToolRequirementsEffects (ReaderT env m) a
|
||||
-> m (VEither ToolRequirementsEffects a)
|
||||
runToolRequirements runAppState =
|
||||
runAppState
|
||||
. runE
|
||||
@ToolRequirementsEffects
|
||||
|
||||
|
||||
|
||||
------------------
|
||||
--[ Entrypoint ]--
|
||||
------------------
|
||||
|
||||
|
||||
|
||||
toolRequirements :: ( Monad m
|
||||
, MonadMask m
|
||||
, MonadUnliftIO m
|
||||
, MonadFail m
|
||||
, Alternative m
|
||||
)
|
||||
=> (ReaderT AppState m (VEither ToolRequirementsEffects ()) -> m (VEither ToolRequirementsEffects ()))
|
||||
-> (ReaderT LeanAppState m () -> m ())
|
||||
-> m ExitCode
|
||||
toolRequirements runAppState runLogger = runToolRequirements runAppState (do
|
||||
GHCupInfo { .. } <- lift getGHCupInfo
|
||||
platform' <- liftE getPlatform
|
||||
req <- getCommonRequirements platform' _toolRequirements ?? NoToolRequirements
|
||||
liftIO $ T.hPutStr stdout (prettyRequirements req)
|
||||
)
|
||||
>>= \case
|
||||
VRight _ -> pure ExitSuccess
|
||||
VLeft e -> do
|
||||
runLogger $ logError $ T.pack $ prettyShow e
|
||||
pure $ ExitFailure 12
|
||||
205
app/ghcup/GHCup/OptParse/UnSet.hs
Normal file
@@ -0,0 +1,205 @@
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE TypeApplications #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE TemplateHaskell #-}
|
||||
{-# LANGUAGE QuasiQuotes #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE DuplicateRecordFields #-}
|
||||
{-# LANGUAGE RankNTypes #-}
|
||||
|
||||
module GHCup.OptParse.UnSet where
|
||||
|
||||
|
||||
|
||||
|
||||
import GHCup
|
||||
import GHCup.Errors
|
||||
import GHCup.Types
|
||||
import GHCup.Logger
|
||||
import GHCup.QQ.String
|
||||
|
||||
#if !MIN_VERSION_base(4,13,0)
|
||||
import Control.Monad.Fail ( MonadFail )
|
||||
#endif
|
||||
import Control.Monad.Reader
|
||||
import Control.Monad.Trans.Resource
|
||||
import Data.Functor
|
||||
import Data.Maybe
|
||||
import Haskus.Utils.Variant.Excepts
|
||||
import Options.Applicative hiding ( style )
|
||||
import Options.Applicative.Help.Pretty ( text )
|
||||
import Prelude hiding ( appendFile )
|
||||
import System.Exit
|
||||
import Text.PrettyPrint.HughesPJClass ( prettyShow )
|
||||
|
||||
import qualified Data.Text as T
|
||||
import Control.Exception.Safe (MonadMask)
|
||||
import GHCup.Types.Optics
|
||||
|
||||
|
||||
|
||||
|
||||
----------------
|
||||
--[ Commands ]--
|
||||
----------------
|
||||
|
||||
|
||||
data UnsetCommand = UnsetGHC UnsetOptions
|
||||
| UnsetCabal UnsetOptions
|
||||
| UnsetHLS UnsetOptions
|
||||
| UnsetStack UnsetOptions
|
||||
|
||||
|
||||
|
||||
|
||||
---------------
|
||||
--[ Options ]--
|
||||
---------------
|
||||
|
||||
|
||||
data UnsetOptions = UnsetOptions
|
||||
{ sToolVer :: Maybe T.Text -- target platform triple
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
---------------
|
||||
--[ Parsers ]--
|
||||
---------------
|
||||
|
||||
|
||||
unsetParser :: Parser UnsetCommand
|
||||
unsetParser =
|
||||
subparser
|
||||
( command
|
||||
"ghc"
|
||||
( UnsetGHC
|
||||
<$> info
|
||||
(unsetOpts <**> helper)
|
||||
( progDesc "Unset GHC version"
|
||||
<> footerDoc (Just $ text unsetGHCFooter)
|
||||
)
|
||||
)
|
||||
<> command
|
||||
"cabal"
|
||||
( UnsetCabal
|
||||
<$> info
|
||||
(unsetOpts <**> helper)
|
||||
( progDesc "Unset Cabal version"
|
||||
<> footerDoc (Just $ text unsetCabalFooter)
|
||||
)
|
||||
)
|
||||
<> command
|
||||
"hls"
|
||||
( UnsetHLS
|
||||
<$> info
|
||||
(unsetOpts <**> helper)
|
||||
( progDesc "Unset haskell-language-server version"
|
||||
<> footerDoc (Just $ text unsetHLSFooter)
|
||||
)
|
||||
)
|
||||
<> command
|
||||
"stack"
|
||||
( UnsetStack
|
||||
<$> info
|
||||
(unsetOpts <**> helper)
|
||||
( progDesc "Unset stack version"
|
||||
<> footerDoc (Just $ text unsetStackFooter)
|
||||
)
|
||||
)
|
||||
)
|
||||
where
|
||||
unsetGHCFooter :: String
|
||||
unsetGHCFooter = [s|Discussion:
|
||||
Unsets the the current GHC version. That means there won't
|
||||
be a ~/.ghcup/bin/ghc anymore.|]
|
||||
|
||||
unsetCabalFooter :: String
|
||||
unsetCabalFooter = [s|Discussion:
|
||||
Unsets the the current Cabal version.|]
|
||||
|
||||
unsetStackFooter :: String
|
||||
unsetStackFooter = [s|Discussion:
|
||||
Unsets the the current Stack version.|]
|
||||
|
||||
unsetHLSFooter :: String
|
||||
unsetHLSFooter = [s|Discussion:
|
||||
Unsets the the current haskell-language-server version.|]
|
||||
|
||||
|
||||
unsetOpts :: Parser UnsetOptions
|
||||
unsetOpts = UnsetOptions . fmap T.pack <$> optional (argument str (metavar "TRIPLE"))
|
||||
|
||||
|
||||
|
||||
--------------
|
||||
--[ Footer ]--
|
||||
--------------
|
||||
|
||||
|
||||
unsetFooter :: String
|
||||
unsetFooter = [s|Discussion:
|
||||
Unsets the currently active GHC or cabal version.|]
|
||||
|
||||
|
||||
|
||||
|
||||
---------------------------
|
||||
--[ Effect interpreters ]--
|
||||
---------------------------
|
||||
|
||||
|
||||
type UnsetEffects = '[ NotInstalled ]
|
||||
|
||||
|
||||
runUnsetGHC :: (ReaderT env m (VEither UnsetEffects a) -> m (VEither UnsetEffects a))
|
||||
-> Excepts UnsetEffects (ReaderT env m) a
|
||||
-> m (VEither UnsetEffects a)
|
||||
runUnsetGHC runLeanAppState =
|
||||
runLeanAppState
|
||||
. runE
|
||||
@UnsetEffects
|
||||
|
||||
|
||||
|
||||
------------------
|
||||
--[ Entrypoint ]--
|
||||
------------------
|
||||
|
||||
|
||||
|
||||
unset :: ( Monad m
|
||||
, MonadMask m
|
||||
, MonadUnliftIO m
|
||||
, MonadFail m
|
||||
, HasDirs env
|
||||
, HasLog env
|
||||
)
|
||||
=> UnsetCommand
|
||||
-> (ReaderT env m (VEither UnsetEffects ())
|
||||
-> m (VEither UnsetEffects ()))
|
||||
-> (ReaderT LeanAppState m () -> m ())
|
||||
-> m ExitCode
|
||||
unset unsetCommand runLeanAppState runLogger = case unsetCommand of
|
||||
(UnsetGHC (UnsetOptions triple)) -> runUnsetGHC runLeanAppState (unsetGHC triple)
|
||||
>>= \case
|
||||
VRight _ -> do
|
||||
runLogger $ logInfo "GHC successfully unset"
|
||||
pure ExitSuccess
|
||||
VLeft e -> do
|
||||
runLogger $ logError $ T.pack $ prettyShow e
|
||||
pure $ ExitFailure 14
|
||||
(UnsetCabal (UnsetOptions _)) -> do
|
||||
void $ runLeanAppState (VRight <$> unsetCabal)
|
||||
runLogger $ logInfo "Cabal successfully unset"
|
||||
pure ExitSuccess
|
||||
(UnsetHLS (UnsetOptions _)) -> do
|
||||
void $ runLeanAppState (VRight <$> unsetHLS)
|
||||
runLogger $ logInfo "HLS successfully unset"
|
||||
pure ExitSuccess
|
||||
(UnsetStack (UnsetOptions _)) -> do
|
||||
void $ runLeanAppState (VRight <$> unsetStack)
|
||||
runLogger $ logInfo "Stack successfully unset"
|
||||
pure ExitSuccess
|
||||
150
app/ghcup/GHCup/OptParse/Upgrade.hs
Normal file
@@ -0,0 +1,150 @@
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE TypeApplications #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE DuplicateRecordFields #-}
|
||||
{-# LANGUAGE RankNTypes #-}
|
||||
|
||||
module GHCup.OptParse.Upgrade where
|
||||
|
||||
|
||||
|
||||
|
||||
import GHCup
|
||||
import GHCup.Errors
|
||||
import GHCup.Types
|
||||
import GHCup.Logger
|
||||
|
||||
#if !MIN_VERSION_base(4,13,0)
|
||||
import Control.Monad.Fail ( MonadFail )
|
||||
#endif
|
||||
import Control.Monad.Reader
|
||||
import Control.Monad.Trans.Resource
|
||||
import Data.Functor
|
||||
import Data.Maybe
|
||||
import Haskus.Utils.Variant.Excepts
|
||||
import Options.Applicative hiding ( style )
|
||||
import Prelude hiding ( appendFile )
|
||||
import System.Exit
|
||||
import Text.PrettyPrint.HughesPJClass ( prettyShow )
|
||||
|
||||
import qualified Data.Text as T
|
||||
import Control.Exception.Safe (MonadMask)
|
||||
import System.Environment
|
||||
import GHCup.Utils
|
||||
import System.FilePath
|
||||
import GHCup.Types.Optics
|
||||
import Data.Versions hiding (str)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
---------------
|
||||
--[ Options ]--
|
||||
---------------
|
||||
|
||||
|
||||
data UpgradeOpts = UpgradeInplace
|
||||
| UpgradeAt FilePath
|
||||
| UpgradeGHCupDir
|
||||
deriving Show
|
||||
|
||||
|
||||
|
||||
|
||||
---------------
|
||||
--[ Parsers ]--
|
||||
---------------
|
||||
|
||||
|
||||
upgradeOptsP :: Parser UpgradeOpts
|
||||
upgradeOptsP =
|
||||
flag'
|
||||
UpgradeInplace
|
||||
(short 'i' <> long "inplace" <> help
|
||||
"Upgrade ghcup in-place (wherever it's at)"
|
||||
)
|
||||
<|> ( UpgradeAt
|
||||
<$> option
|
||||
str
|
||||
(short 't' <> long "target" <> metavar "TARGET_DIR" <> help
|
||||
"Absolute filepath to write ghcup into"
|
||||
)
|
||||
)
|
||||
<|> pure UpgradeGHCupDir
|
||||
|
||||
|
||||
|
||||
|
||||
---------------------------
|
||||
--[ Effect interpreters ]--
|
||||
---------------------------
|
||||
|
||||
|
||||
type UpgradeEffects = '[ DigestError
|
||||
, GPGError
|
||||
, NoDownload
|
||||
, NoUpdate
|
||||
, FileDoesNotExistError
|
||||
, CopyError
|
||||
, DownloadFailed
|
||||
]
|
||||
|
||||
|
||||
runUpgrade :: MonadUnliftIO m
|
||||
=> (ReaderT AppState m (VEither UpgradeEffects a) -> m (VEither UpgradeEffects a))
|
||||
-> Excepts UpgradeEffects (ResourceT (ReaderT AppState m)) a
|
||||
-> m (VEither UpgradeEffects a)
|
||||
runUpgrade runAppState =
|
||||
runAppState
|
||||
. runResourceT
|
||||
. runE
|
||||
@UpgradeEffects
|
||||
|
||||
|
||||
|
||||
------------------
|
||||
--[ Entrypoint ]--
|
||||
------------------
|
||||
|
||||
|
||||
|
||||
upgrade :: ( Monad m
|
||||
, MonadMask m
|
||||
, MonadUnliftIO m
|
||||
, MonadFail m
|
||||
)
|
||||
=> UpgradeOpts
|
||||
-> Bool
|
||||
-> (forall a. ReaderT AppState m (VEither UpgradeEffects a) -> m (VEither UpgradeEffects a))
|
||||
-> (ReaderT LeanAppState m () -> m ())
|
||||
-> m ExitCode
|
||||
upgrade uOpts force' runAppState runLogger = do
|
||||
VRight Dirs{ .. } <- runAppState (VRight <$> getDirs)
|
||||
target <- case uOpts of
|
||||
UpgradeInplace -> Just <$> liftIO getExecutablePath
|
||||
(UpgradeAt p) -> pure $ Just p
|
||||
UpgradeGHCupDir -> pure (Just (binDir </> "ghcup" <> exeExt))
|
||||
|
||||
runUpgrade runAppState (do
|
||||
v' <- liftE $ upgradeGHCup target force'
|
||||
GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo
|
||||
pure (v', dls)
|
||||
) >>= \case
|
||||
VRight (v', dls) -> do
|
||||
let pretty_v = prettyVer v'
|
||||
let vi = fromJust $ snd <$> getLatest dls GHCup
|
||||
runLogger $ logInfo $
|
||||
"Successfully upgraded GHCup to version " <> pretty_v
|
||||
forM_ (_viPostInstall vi) $ \msg ->
|
||||
runLogger $ logInfo msg
|
||||
pure ExitSuccess
|
||||
VLeft (V NoUpdate) -> do
|
||||
runLogger $ logWarn "No GHCup update available"
|
||||
pure ExitSuccess
|
||||
VLeft e -> do
|
||||
runLogger $ logError $ T.pack $ prettyShow e
|
||||
pure $ ExitFailure 11
|
||||
319
app/ghcup/GHCup/OptParse/Whereis.hs
Normal file
@@ -0,0 +1,319 @@
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE TypeApplications #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE TemplateHaskell #-}
|
||||
{-# LANGUAGE QuasiQuotes #-}
|
||||
{-# LANGUAGE DuplicateRecordFields #-}
|
||||
{-# LANGUAGE RankNTypes #-}
|
||||
|
||||
module GHCup.OptParse.Whereis where
|
||||
|
||||
|
||||
|
||||
|
||||
import GHCup
|
||||
import GHCup.Errors
|
||||
import GHCup.OptParse.Common
|
||||
import GHCup.Types
|
||||
import GHCup.Logger
|
||||
import GHCup.QQ.String
|
||||
|
||||
#if !MIN_VERSION_base(4,13,0)
|
||||
import Control.Monad.Fail ( MonadFail )
|
||||
#endif
|
||||
import Control.Monad.Reader
|
||||
import Control.Monad.Trans.Resource
|
||||
import Data.Functor
|
||||
import Data.Maybe
|
||||
import Haskus.Utils.Variant.Excepts
|
||||
import Options.Applicative hiding ( style )
|
||||
import Options.Applicative.Help.Pretty ( text )
|
||||
import Prelude hiding ( appendFile )
|
||||
import System.Exit
|
||||
import Text.PrettyPrint.HughesPJClass ( prettyShow )
|
||||
|
||||
import qualified Data.Text as T
|
||||
import Control.Exception.Safe (MonadMask)
|
||||
import System.FilePath (takeDirectory)
|
||||
import GHCup.Types.Optics
|
||||
|
||||
|
||||
|
||||
|
||||
----------------
|
||||
--[ Commands ]--
|
||||
----------------
|
||||
|
||||
|
||||
data WhereisCommand = WhereisTool Tool (Maybe ToolVersion)
|
||||
| WhereisBaseDir
|
||||
| WhereisBinDir
|
||||
| WhereisCacheDir
|
||||
| WhereisLogsDir
|
||||
| WhereisConfDir
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
---------------
|
||||
--[ Options ]--
|
||||
---------------
|
||||
|
||||
|
||||
data WhereisOptions = WhereisOptions {
|
||||
directory :: Bool
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
---------------
|
||||
--[ Parsers ]--
|
||||
---------------
|
||||
|
||||
|
||||
whereisP :: Parser WhereisCommand
|
||||
whereisP = subparser
|
||||
(commandGroup "Tools locations:" <>
|
||||
command
|
||||
"ghc"
|
||||
(WhereisTool GHC <$> info
|
||||
( optional (toolVersionArgument Nothing (Just GHC)) <**> helper )
|
||||
( progDesc "Get GHC location"
|
||||
<> footerDoc (Just $ text whereisGHCFooter ))
|
||||
)
|
||||
<>
|
||||
command
|
||||
"cabal"
|
||||
(WhereisTool Cabal <$> info
|
||||
( optional (toolVersionArgument Nothing (Just Cabal)) <**> helper )
|
||||
( progDesc "Get cabal location"
|
||||
<> footerDoc (Just $ text whereisCabalFooter ))
|
||||
)
|
||||
<>
|
||||
command
|
||||
"hls"
|
||||
(WhereisTool HLS <$> info
|
||||
( optional (toolVersionArgument Nothing (Just HLS)) <**> helper )
|
||||
( progDesc "Get HLS location"
|
||||
<> footerDoc (Just $ text whereisHLSFooter ))
|
||||
)
|
||||
<>
|
||||
command
|
||||
"stack"
|
||||
(WhereisTool Stack <$> info
|
||||
( optional (toolVersionArgument Nothing (Just Stack)) <**> helper )
|
||||
( progDesc "Get stack location"
|
||||
<> footerDoc (Just $ text whereisStackFooter ))
|
||||
)
|
||||
<>
|
||||
command
|
||||
"ghcup"
|
||||
(WhereisTool GHCup <$> info ( pure Nothing <**> helper ) ( progDesc "Get ghcup location" ))
|
||||
) <|> subparser ( commandGroup "Directory locations:"
|
||||
<>
|
||||
command
|
||||
"basedir"
|
||||
(info (pure WhereisBaseDir <**> helper)
|
||||
( progDesc "Get ghcup base directory location" )
|
||||
)
|
||||
<>
|
||||
command
|
||||
"bindir"
|
||||
(info (pure WhereisBinDir <**> helper)
|
||||
( progDesc "Get ghcup binary directory location" )
|
||||
)
|
||||
<>
|
||||
command
|
||||
"cachedir"
|
||||
(info (pure WhereisCacheDir <**> helper)
|
||||
( progDesc "Get ghcup cache directory location" )
|
||||
)
|
||||
<>
|
||||
command
|
||||
"logsdir"
|
||||
(info (pure WhereisLogsDir <**> helper)
|
||||
( progDesc "Get ghcup logs directory location" )
|
||||
)
|
||||
<>
|
||||
command
|
||||
"confdir"
|
||||
(info (pure WhereisConfDir <**> helper)
|
||||
( progDesc "Get ghcup config directory location" )
|
||||
)
|
||||
)
|
||||
where
|
||||
whereisGHCFooter = [s|Discussion:
|
||||
Finds the location of a GHC executable, which usually resides in
|
||||
a self-contained "~/.ghcup/ghc/<ghcver>" directory.
|
||||
|
||||
Examples:
|
||||
# outputs ~/.ghcup/ghc/8.10.5/bin/ghc.exe
|
||||
ghcup whereis ghc 8.10.5
|
||||
# outputs ~/.ghcup/ghc/8.10.5/bin/
|
||||
ghcup whereis --directory ghc 8.10.5 |]
|
||||
|
||||
whereisCabalFooter = [s|Discussion:
|
||||
Finds the location of a Cabal executable, which usually resides in
|
||||
"~/.ghcup/bin/".
|
||||
|
||||
Examples:
|
||||
# outputs ~/.ghcup/bin/cabal-3.4.0.0
|
||||
ghcup whereis cabal 3.4.0.0
|
||||
# outputs ~/.ghcup/bin
|
||||
ghcup whereis --directory cabal 3.4.0.0|]
|
||||
|
||||
whereisHLSFooter = [s|Discussion:
|
||||
Finds the location of a HLS executable, which usually resides in
|
||||
"~/.ghcup/bin/".
|
||||
|
||||
Examples:
|
||||
# outputs ~/.ghcup/bin/haskell-language-server-wrapper-1.2.0
|
||||
ghcup whereis hls 1.2.0
|
||||
# outputs ~/.ghcup/bin/
|
||||
ghcup whereis --directory hls 1.2.0|]
|
||||
|
||||
whereisStackFooter = [s|Discussion:
|
||||
Finds the location of a stack executable, which usually resides in
|
||||
"~/.ghcup/bin/".
|
||||
|
||||
Examples:
|
||||
# outputs ~/.ghcup/bin/stack-2.7.1
|
||||
ghcup whereis stack 2.7.1
|
||||
# outputs ~/.ghcup/bin/
|
||||
ghcup whereis --directory stack 2.7.1|]
|
||||
|
||||
|
||||
|
||||
--------------
|
||||
--[ Footer ]--
|
||||
--------------
|
||||
|
||||
|
||||
whereisFooter :: String
|
||||
whereisFooter = [s|Discussion:
|
||||
Finds the location of a tool. For GHC, this is the ghc binary, that
|
||||
usually resides in a self-contained "~/.ghcup/ghc/<ghcver>" directory.
|
||||
For cabal/stack/hls this the binary usually at "~/.ghcup/bin/<tool>-<ver>".
|
||||
|
||||
Examples:
|
||||
# outputs ~/.ghcup/ghc/8.10.5/bin/ghc.exe
|
||||
ghcup whereis ghc 8.10.5
|
||||
# outputs ~/.ghcup/ghc/8.10.5/bin/
|
||||
ghcup whereis --directory ghc 8.10.5
|
||||
# outputs ~/.ghcup/bin/cabal-3.4.0.0
|
||||
ghcup whereis cabal 3.4.0.0
|
||||
# outputs ~/.ghcup/bin/
|
||||
ghcup whereis --directory cabal 3.4.0.0|]
|
||||
|
||||
|
||||
|
||||
|
||||
---------------------------
|
||||
--[ Effect interpreters ]--
|
||||
---------------------------
|
||||
|
||||
|
||||
type WhereisEffects = '[ NotInstalled
|
||||
, NoToolVersionSet
|
||||
, NextVerNotFound
|
||||
, TagNotFound
|
||||
]
|
||||
|
||||
|
||||
runLeanWhereIs :: (MonadUnliftIO m, MonadIO m)
|
||||
=> LeanAppState
|
||||
-> Excepts WhereisEffects (ReaderT LeanAppState m) a
|
||||
-> m (VEither WhereisEffects a)
|
||||
runLeanWhereIs leanAppstate =
|
||||
-- Don't use runLeanAppState here, which is disabled on windows.
|
||||
-- This is the only command on all platforms that doesn't need full appstate.
|
||||
flip runReaderT leanAppstate
|
||||
. runE
|
||||
@WhereisEffects
|
||||
|
||||
|
||||
runWhereIs :: (MonadUnliftIO m, MonadIO m)
|
||||
=> (ReaderT AppState m (VEither WhereisEffects a) -> m (VEither WhereisEffects a))
|
||||
-> Excepts WhereisEffects (ReaderT AppState m) a
|
||||
-> m (VEither WhereisEffects a)
|
||||
runWhereIs runAppState =
|
||||
runAppState
|
||||
. runE
|
||||
@WhereisEffects
|
||||
|
||||
|
||||
|
||||
------------------
|
||||
--[ Entrypoint ]--
|
||||
------------------
|
||||
|
||||
|
||||
|
||||
whereis :: ( Monad m
|
||||
, MonadMask m
|
||||
, MonadUnliftIO m
|
||||
, MonadFail m
|
||||
)
|
||||
=> WhereisCommand
|
||||
-> WhereisOptions
|
||||
-> (forall a. ReaderT AppState m (VEither WhereisEffects a) -> m (VEither WhereisEffects a))
|
||||
-> LeanAppState
|
||||
-> (ReaderT LeanAppState m () -> m ())
|
||||
-> m ExitCode
|
||||
whereis whereisCommand whereisOptions runAppState leanAppstate runLogger = do
|
||||
Dirs{ .. } <- runReaderT getDirs leanAppstate
|
||||
case (whereisCommand, whereisOptions) of
|
||||
(WhereisTool tool (Just (ToolVersion v)), WhereisOptions{..}) ->
|
||||
runLeanWhereIs leanAppstate (do
|
||||
loc <- liftE $ whereIsTool tool v
|
||||
if directory
|
||||
then pure $ takeDirectory loc
|
||||
else pure loc
|
||||
)
|
||||
>>= \case
|
||||
VRight r -> do
|
||||
liftIO $ putStr r
|
||||
pure ExitSuccess
|
||||
VLeft e -> do
|
||||
runLogger $ logError $ T.pack $ prettyShow e
|
||||
pure $ ExitFailure 30
|
||||
|
||||
(WhereisTool tool whereVer, WhereisOptions{..}) -> do
|
||||
runWhereIs runAppState (do
|
||||
(v, _) <- liftE $ fromVersion whereVer tool
|
||||
loc <- liftE $ whereIsTool tool v
|
||||
if directory
|
||||
then pure $ takeDirectory loc
|
||||
else pure loc
|
||||
)
|
||||
>>= \case
|
||||
VRight r -> do
|
||||
liftIO $ putStr r
|
||||
pure ExitSuccess
|
||||
VLeft e -> do
|
||||
runLogger $ logError $ T.pack $ prettyShow e
|
||||
pure $ ExitFailure 30
|
||||
|
||||
(WhereisBaseDir, _) -> do
|
||||
liftIO $ putStr baseDir
|
||||
pure ExitSuccess
|
||||
|
||||
(WhereisBinDir, _) -> do
|
||||
liftIO $ putStr binDir
|
||||
pure ExitSuccess
|
||||
|
||||
(WhereisCacheDir, _) -> do
|
||||
liftIO $ putStr cacheDir
|
||||
pure ExitSuccess
|
||||
|
||||
(WhereisLogsDir, _) -> do
|
||||
liftIO $ putStr logsDir
|
||||
pure ExitSuccess
|
||||
|
||||
(WhereisConfDir, _) -> do
|
||||
liftIO $ putStr confDir
|
||||
pure ExitSuccess
|
||||
@@ -1,5 +1,7 @@
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE TypeApplications #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE TemplateHaskell #-}
|
||||
{-# LANGUAGE QuasiQuotes #-}
|
||||
@@ -8,695 +10,281 @@
|
||||
|
||||
module Main where
|
||||
|
||||
import GHCup
|
||||
#if defined(BRICK)
|
||||
import BrickMain ( brickMain )
|
||||
#endif
|
||||
|
||||
import GHCup.OptParse
|
||||
|
||||
import GHCup.Download
|
||||
import GHCup.Errors
|
||||
import GHCup.Platform
|
||||
import GHCup.Types
|
||||
import GHCup.Utils
|
||||
import GHCup.Utils.Logger
|
||||
import GHCup.Utils.Prelude
|
||||
import GHCup.Utils.String.QQ
|
||||
import GHCup.Logger
|
||||
import GHCup.Prelude
|
||||
import GHCup.QQ.String
|
||||
import GHCup.Version
|
||||
|
||||
import Control.Monad.Logger
|
||||
import Cabal.Plan ( findPlanJson, SearchPlanJson(..) )
|
||||
import Control.Concurrent
|
||||
import Control.Concurrent.Async
|
||||
import Control.Exception.Safe
|
||||
#if !MIN_VERSION_base(4,13,0)
|
||||
import Control.Monad.Fail ( MonadFail )
|
||||
#endif
|
||||
import Control.Monad.Reader
|
||||
import Control.Monad.Trans.Resource
|
||||
import Data.Bifunctor
|
||||
import Data.Char
|
||||
import Data.List ( intercalate )
|
||||
import Data.Semigroup ( (<>) )
|
||||
import Data.String.Interpolate
|
||||
import Data.Versions
|
||||
import Data.Aeson ( decodeStrict', Value )
|
||||
import Data.Aeson.Encode.Pretty ( encodePretty )
|
||||
import Data.Either
|
||||
import Data.Functor
|
||||
import Data.Maybe
|
||||
import GHC.IO.Encoding
|
||||
import Haskus.Utils.Variant.Excepts
|
||||
import HPath
|
||||
import HPath.IO
|
||||
import Language.Haskell.TH
|
||||
import Language.Haskell.TH.Syntax ( Quasi(qAddDependentFile) )
|
||||
import Options.Applicative hiding ( style )
|
||||
import Options.Applicative.Help.Pretty ( text )
|
||||
import Prelude hiding ( appendFile )
|
||||
import System.Console.Pretty
|
||||
import System.Environment
|
||||
import System.Exit
|
||||
import System.IO hiding ( appendFile )
|
||||
import Text.Read
|
||||
import Text.Layout.Table
|
||||
import URI.ByteString
|
||||
import Text.PrettyPrint.HughesPJClass ( prettyShow )
|
||||
|
||||
import qualified Data.ByteString as B
|
||||
import qualified Data.ByteString.UTF8 as UTF8
|
||||
import qualified Data.Text as T
|
||||
import qualified Data.Text.IO as T
|
||||
import qualified Data.Text.Encoding as E
|
||||
import qualified GHCup.Types as Types
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
data Options = Options
|
||||
{
|
||||
-- global options
|
||||
optVerbose :: Bool
|
||||
, optCache :: Bool
|
||||
, optUrlSource :: Maybe URI
|
||||
, optNoVerify :: Bool
|
||||
-- commands
|
||||
, optCommand :: Command
|
||||
}
|
||||
|
||||
data Command
|
||||
= Install InstallCommand
|
||||
| SetGHC SetGHCOptions
|
||||
| List ListOptions
|
||||
| Rm RmOptions
|
||||
| DInfo
|
||||
| Compile CompileCommand
|
||||
| Upgrade UpgradeOpts
|
||||
| NumericVersion
|
||||
|
||||
data ToolVersion = ToolVersion Version
|
||||
| ToolTag Tag
|
||||
|
||||
|
||||
data InstallCommand = InstallGHC InstallOptions
|
||||
| InstallCabal InstallOptions
|
||||
|
||||
data InstallOptions = InstallOptions
|
||||
{ instVer :: Maybe ToolVersion
|
||||
}
|
||||
|
||||
data SetGHCOptions = SetGHCOptions
|
||||
{ ghcVer :: Maybe ToolVersion
|
||||
}
|
||||
|
||||
data ListOptions = ListOptions
|
||||
{ lTool :: Maybe Tool
|
||||
, lCriteria :: Maybe ListCriteria
|
||||
}
|
||||
|
||||
data RmOptions = RmOptions
|
||||
{ ghcVer :: Version
|
||||
}
|
||||
|
||||
|
||||
data CompileCommand = CompileGHC CompileOptions
|
||||
| CompileCabal CompileOptions
|
||||
|
||||
|
||||
data CompileOptions = CompileOptions
|
||||
{ targetVer :: Version
|
||||
, bootstrapVer :: Version
|
||||
, jobs :: Maybe Int
|
||||
, buildConfig :: Maybe (Path Abs)
|
||||
}
|
||||
|
||||
data UpgradeOpts = UpgradeInplace
|
||||
| UpgradeAt (Path Abs)
|
||||
| UpgradeGHCupDir
|
||||
deriving Show
|
||||
|
||||
|
||||
opts :: Parser Options
|
||||
opts =
|
||||
Options
|
||||
<$> switch
|
||||
(short 'v' <> long "verbose" <> help
|
||||
"Whether to enable verbosity (default: False)"
|
||||
)
|
||||
<*> switch
|
||||
(short 'c' <> long "cache" <> help
|
||||
"Whether to cache downloads (default: False)"
|
||||
)
|
||||
<*> (optional
|
||||
(option
|
||||
(eitherReader parseUri)
|
||||
(short 's' <> long "url-source" <> metavar "URL" <> help
|
||||
"Alternative ghcup download info url" <> internal
|
||||
)
|
||||
)
|
||||
)
|
||||
<*> switch
|
||||
(short 'n' <> long "no-verify" <> help
|
||||
"Skip tarball checksum verification (default: False)"
|
||||
)
|
||||
<*> com
|
||||
toSettings :: Options -> IO (Settings, KeyBindings)
|
||||
toSettings options = do
|
||||
noColor <- isJust <$> lookupEnv "NO_COLOR"
|
||||
userConf <- runE @'[ JSONError ] ghcupConfigFile >>= \case
|
||||
VRight r -> pure r
|
||||
VLeft (V (JSONDecodeError e)) -> do
|
||||
B.hPut stderr ("Error decoding config file: " <> (E.encodeUtf8 . T.pack . show $ e))
|
||||
pure defaultUserSettings
|
||||
_ -> do
|
||||
die "Unexpected error!"
|
||||
pure $ mergeConf options userConf noColor
|
||||
where
|
||||
parseUri s' =
|
||||
bimap show id $ parseURI strictURIParserOptions (UTF8.fromString s')
|
||||
mergeConf :: Options -> UserSettings -> Bool -> (Settings, KeyBindings)
|
||||
mergeConf Options{..} UserSettings{..} noColor =
|
||||
let cache = fromMaybe (fromMaybe (Types.cache defaultSettings) uCache) optCache
|
||||
metaCache = fromMaybe (fromMaybe (Types.metaCache defaultSettings) uMetaCache) optMetaCache
|
||||
noVerify = fromMaybe (fromMaybe (Types.noVerify defaultSettings) uNoVerify) optNoVerify
|
||||
verbose = fromMaybe (fromMaybe (Types.verbose defaultSettings) uVerbose) optVerbose
|
||||
keepDirs = fromMaybe (fromMaybe (Types.keepDirs defaultSettings) uKeepDirs) optKeepDirs
|
||||
downloader = fromMaybe (fromMaybe defaultDownloader uDownloader) optsDownloader
|
||||
keyBindings = maybe defaultKeyBindings mergeKeys uKeyBindings
|
||||
urlSource = maybe (fromMaybe (Types.urlSource defaultSettings) uUrlSource) OwnSource optUrlSource
|
||||
noNetwork = fromMaybe (fromMaybe (Types.noNetwork defaultSettings) uNoNetwork) optNoNetwork
|
||||
gpgSetting = fromMaybe (fromMaybe (Types.gpgSetting defaultSettings) uGPGSetting) optGpg
|
||||
in (Settings {..}, keyBindings)
|
||||
#if defined(INTERNAL_DOWNLOADER)
|
||||
defaultDownloader = Internal
|
||||
#else
|
||||
defaultDownloader = Curl
|
||||
#endif
|
||||
mergeKeys :: UserKeyBindings -> KeyBindings
|
||||
mergeKeys UserKeyBindings {..} =
|
||||
let KeyBindings {..} = defaultKeyBindings
|
||||
in KeyBindings {
|
||||
bUp = fromMaybe bUp kUp
|
||||
, bDown = fromMaybe bDown kDown
|
||||
, bQuit = fromMaybe bQuit kQuit
|
||||
, bInstall = fromMaybe bInstall kInstall
|
||||
, bUninstall = fromMaybe bUninstall kUninstall
|
||||
, bSet = fromMaybe bSet kSet
|
||||
, bChangelog = fromMaybe bChangelog kChangelog
|
||||
, bShowAllVersions = fromMaybe bShowAllVersions kShowAll
|
||||
, bShowAllTools = fromMaybe bShowAllTools kShowAllTools
|
||||
}
|
||||
|
||||
|
||||
com :: Parser Command
|
||||
com =
|
||||
subparser
|
||||
( command
|
||||
"install"
|
||||
( Install
|
||||
<$> (info (installP <**> helper)
|
||||
(progDesc "Install or update GHC/cabal")
|
||||
)
|
||||
)
|
||||
<> command
|
||||
"list"
|
||||
( List
|
||||
<$> (info (listOpts <**> helper)
|
||||
(progDesc "Show available GHCs and other tools")
|
||||
)
|
||||
)
|
||||
<> command
|
||||
"upgrade"
|
||||
( Upgrade
|
||||
<$> (info
|
||||
(upgradeOptsP <**> helper)
|
||||
(progDesc "Upgrade ghcup (per default in ~/.ghcup/bin/)")
|
||||
)
|
||||
)
|
||||
<> command
|
||||
"compile"
|
||||
( Compile
|
||||
<$> (info (compileP <**> helper)
|
||||
(progDesc "Compile a tool from source")
|
||||
)
|
||||
)
|
||||
<> commandGroup "Main commands:"
|
||||
)
|
||||
<|> subparser
|
||||
( command
|
||||
"set"
|
||||
( SetGHC
|
||||
<$> (info (setGHCOpts <**> helper)
|
||||
(progDesc "Set the currently active GHC version")
|
||||
)
|
||||
)
|
||||
<> command
|
||||
"rm"
|
||||
( Rm
|
||||
<$> (info
|
||||
(rmOpts <**> helper)
|
||||
(progDesc "Remove a GHC version installed by ghcup")
|
||||
)
|
||||
)
|
||||
<> commandGroup "GHC commands:"
|
||||
<> hidden
|
||||
)
|
||||
<|> subparser
|
||||
( command
|
||||
"debug-info"
|
||||
((\_ -> DInfo) <$> (info (helper) (progDesc "Show debug info")))
|
||||
<> command
|
||||
"numeric-version"
|
||||
( (\_ -> NumericVersion)
|
||||
<$> (info (helper) (progDesc "Show the numeric version"))
|
||||
)
|
||||
<> commandGroup "Other commands:"
|
||||
<> hidden
|
||||
)
|
||||
|
||||
|
||||
installP :: Parser InstallCommand
|
||||
installP = subparser
|
||||
( command
|
||||
"ghc"
|
||||
( InstallGHC
|
||||
<$> (info (installOpts <**> helper) (progDesc "Install a GHC version"))
|
||||
)
|
||||
<> command
|
||||
"cabal"
|
||||
( InstallCabal
|
||||
<$> (info (installOpts <**> helper)
|
||||
(progDesc "Install or update a Cabal version")
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
installOpts :: Parser InstallOptions
|
||||
installOpts = InstallOptions <$> optional toolVersionParser
|
||||
|
||||
setGHCOpts :: Parser SetGHCOptions
|
||||
setGHCOpts = SetGHCOptions <$> optional toolVersionParser
|
||||
|
||||
listOpts :: Parser ListOptions
|
||||
listOpts =
|
||||
ListOptions
|
||||
<$> optional
|
||||
(option
|
||||
(eitherReader toolParser)
|
||||
(short 't' <> long "tool" <> metavar "<ghc|cabal>" <> help
|
||||
"Tool to list versions for. Default is all"
|
||||
)
|
||||
)
|
||||
<*> (optional
|
||||
(option
|
||||
(eitherReader criteriaParser)
|
||||
( short 'c'
|
||||
<> long "show-criteria"
|
||||
<> metavar "<installed|set>"
|
||||
<> help "Show only installed or set tool versions"
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
rmOpts :: Parser RmOptions
|
||||
rmOpts = RmOptions <$> versionParser
|
||||
|
||||
|
||||
compileP :: Parser CompileCommand
|
||||
compileP = subparser
|
||||
( command
|
||||
"ghc"
|
||||
( CompileGHC
|
||||
<$> (info (compileOpts <**> helper) (progDesc "Compile GHC from source")
|
||||
)
|
||||
)
|
||||
<> command
|
||||
"cabal"
|
||||
( CompileCabal
|
||||
<$> (info (compileOpts <**> helper)
|
||||
(progDesc "Compile Cabal from source")
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
compileOpts :: Parser CompileOptions
|
||||
compileOpts =
|
||||
CompileOptions
|
||||
<$> (option
|
||||
(eitherReader
|
||||
(bimap (const "Not a valid version") id . version . T.pack)
|
||||
)
|
||||
(short 'v' <> long "version" <> metavar "VERSION" <> help
|
||||
"The tool version to compile"
|
||||
)
|
||||
)
|
||||
<*> (option
|
||||
(eitherReader
|
||||
(bimap (const "Not a valid version") id . version . T.pack)
|
||||
)
|
||||
( short 'b'
|
||||
<> long "bootstrap-version"
|
||||
<> metavar "BOOTSTRAP_VERSION"
|
||||
<> help "The GHC version to bootstrap with (must be installed)"
|
||||
)
|
||||
)
|
||||
<*> optional
|
||||
(option
|
||||
(eitherReader (readEither @Int))
|
||||
(short 'j' <> long "jobs" <> metavar "JOBS" <> help
|
||||
"How many jobs to use for make"
|
||||
)
|
||||
)
|
||||
<*> optional
|
||||
(option
|
||||
(eitherReader
|
||||
(\x ->
|
||||
bimap show id . parseAbs . E.encodeUtf8 . T.pack $ x :: Either
|
||||
String
|
||||
(Path Abs)
|
||||
)
|
||||
)
|
||||
(short 'c' <> long "config" <> metavar "CONFIG" <> help
|
||||
"Absolute path to build config file"
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
versionParser :: Parser Version
|
||||
versionParser = option
|
||||
(eitherReader (bimap (const "Not a valid version") id . version . T.pack))
|
||||
(short 'v' <> long "version" <> metavar "VERSION" <> help "The target version"
|
||||
)
|
||||
|
||||
|
||||
toolVersionParser :: Parser ToolVersion
|
||||
toolVersionParser = verP <|> toolP
|
||||
where
|
||||
verP = ToolVersion <$> versionParser
|
||||
toolP =
|
||||
ToolTag
|
||||
<$> (option
|
||||
(eitherReader
|
||||
(\s' -> case fmap toLower s' of
|
||||
"recommended" -> Right Recommended
|
||||
"latest" -> Right Latest
|
||||
other -> Left ([i|Unknown tag #{other}|])
|
||||
)
|
||||
)
|
||||
(short 't' <> long "tag" <> metavar "TAG" <> help "The target tag")
|
||||
)
|
||||
|
||||
|
||||
toolParser :: String -> Either String Tool
|
||||
toolParser s' | t == T.pack "ghc" = Right GHC
|
||||
| t == T.pack "cabal" = Right Cabal
|
||||
| otherwise = Left ("Unknown tool: " <> s')
|
||||
where t = T.toLower (T.pack s')
|
||||
|
||||
|
||||
criteriaParser :: String -> Either String ListCriteria
|
||||
criteriaParser s' | t == T.pack "installed" = Right ListInstalled
|
||||
| t == T.pack "set" = Right ListSet
|
||||
| otherwise = Left ("Unknown criteria: " <> s')
|
||||
where t = T.toLower (T.pack s')
|
||||
|
||||
|
||||
toSettings :: Options -> Settings
|
||||
toSettings Options {..} =
|
||||
let cache = optCache
|
||||
urlSource = maybe GHCupURL OwnSource optUrlSource
|
||||
noVerify = optNoVerify
|
||||
in Settings { .. }
|
||||
|
||||
|
||||
upgradeOptsP :: Parser UpgradeOpts
|
||||
upgradeOptsP =
|
||||
flag'
|
||||
UpgradeInplace
|
||||
(short 'i' <> long "inplace" <> help
|
||||
"Upgrade ghcup in-place (wherever it's at)"
|
||||
)
|
||||
<|> ( UpgradeAt
|
||||
<$> (option
|
||||
(eitherReader
|
||||
(\x ->
|
||||
bimap show id . parseAbs . E.encodeUtf8 . T.pack $ x :: Either
|
||||
String
|
||||
(Path Abs)
|
||||
)
|
||||
)
|
||||
(short 't' <> long "target" <> metavar "TARGET_DIR" <> help
|
||||
"Absolute filepath to write ghcup into"
|
||||
)
|
||||
)
|
||||
)
|
||||
<|> (pure UpgradeGHCupDir)
|
||||
|
||||
|
||||
plan_json :: String
|
||||
plan_json = $( do
|
||||
(fp, c) <- runIO (handleIO (\_ -> pure ("", "")) $ do
|
||||
fp <- findPlanJson (ProjectRelativeToDir ".")
|
||||
c <- B.readFile fp
|
||||
(Just res) <- pure $ decodeStrict' @Value c
|
||||
pure (fp, T.unpack $ decUTF8Safe' $ encodePretty res))
|
||||
unless (null fp) $ qAddDependentFile fp
|
||||
pure . LitE . StringL $ c)
|
||||
|
||||
|
||||
main :: IO ()
|
||||
main = do
|
||||
-- https://gitlab.haskell.org/ghc/ghc/issues/8118
|
||||
setLocaleEncoding utf8
|
||||
|
||||
customExecParser (prefs showHelpOnError) (info (opts <**> helper) idm)
|
||||
void enableAnsiSupport
|
||||
|
||||
let versionHelp = infoOption
|
||||
( "The GHCup Haskell installer, version " <> (head . lines $ describe_result)
|
||||
)
|
||||
(long "version" <> help "Show version" <> hidden)
|
||||
let planJson = infoOption
|
||||
plan_json
|
||||
(long "plan-json" <> help "Show the build-time configuration" <> internal)
|
||||
let numericVersionHelp = infoOption
|
||||
numericVer
|
||||
( long "numeric-version"
|
||||
<> help "Show the numeric version (for use in scripts)"
|
||||
<> hidden
|
||||
)
|
||||
let listCommands = infoOption
|
||||
"install set rm install-cabal list upgrade compile debug-info tool-requirements changelog"
|
||||
( long "list-commands"
|
||||
<> help "List available commands for shell completion"
|
||||
<> internal
|
||||
)
|
||||
|
||||
let main_footer = [s|Discussion:
|
||||
ghcup installs the Glasgow Haskell Compiler from the official
|
||||
release channels, enabling you to easily switch between different
|
||||
versions. It maintains a self-contained ~/.ghcup directory.
|
||||
|
||||
ENV variables:
|
||||
* TMPDIR: where ghcup does the work (unpacking, building, ...)
|
||||
* GHCUP_INSTALL_BASE_PREFIX: the base of ghcup (default: $HOME)
|
||||
* GHCUP_USE_XDG_DIRS: set to anything to use XDG style directories
|
||||
|
||||
Report bugs at <https://gitlab.haskell.org/haskell/ghcup-hs/issues>|]
|
||||
|
||||
customExecParser
|
||||
(prefs showHelpOnError)
|
||||
(info (opts <**> helper <**> versionHelp <**> numericVersionHelp <**> planJson <**> listCommands)
|
||||
(footerDoc (Just $ text main_footer))
|
||||
)
|
||||
>>= \opt@Options {..} -> do
|
||||
let settings = toSettings opt
|
||||
dirs@Dirs{..} <- getAllDirs
|
||||
|
||||
-- create ~/.ghcup dir
|
||||
ensureDirectories dirs
|
||||
|
||||
(settings, keybindings) <- toSettings opt
|
||||
|
||||
-- logger interpreter
|
||||
logfile <- initGHCupFileLogging ([rel|ghcup.log|] :: Path Rel)
|
||||
let runLogger = myLoggerT LoggerConfig
|
||||
{ lcPrintDebug = optVerbose
|
||||
, colorOutter = B.hPut stderr
|
||||
, rawOutter = appendFile logfile
|
||||
logfile <- runReaderT initGHCupFileLogging dirs
|
||||
no_color <- isJust <$> lookupEnv "NO_COLOR"
|
||||
let loggerConfig = LoggerConfig
|
||||
{ lcPrintDebug = verbose settings
|
||||
, consoleOutter = T.hPutStr stderr
|
||||
, fileOutter =
|
||||
case optCommand of
|
||||
Nuke -> \_ -> pure ()
|
||||
_ -> T.appendFile logfile
|
||||
, fancyColors = not no_color
|
||||
}
|
||||
|
||||
-- wrapper to run effects with settings
|
||||
let runInstTool =
|
||||
runLogger
|
||||
. flip runReaderT settings
|
||||
. runResourceT
|
||||
. runE
|
||||
@'[ AlreadyInstalled
|
||||
, UnknownArchive
|
||||
, DistroNotFound
|
||||
, FileDoesNotExistError
|
||||
, CopyError
|
||||
, JSONError
|
||||
, NoCompatibleArch
|
||||
, NoDownload
|
||||
, NotInstalled
|
||||
, NoCompatiblePlatform
|
||||
, BuildFailed
|
||||
, TagNotFound
|
||||
, DigestError
|
||||
, DownloadFailed
|
||||
]
|
||||
|
||||
let runSetGHC =
|
||||
runLogger
|
||||
. flip runReaderT settings
|
||||
. runE
|
||||
@'[ FileDoesNotExistError
|
||||
, NotInstalled
|
||||
, TagNotFound
|
||||
, JSONError
|
||||
, TagNotFound
|
||||
, DownloadFailed
|
||||
]
|
||||
|
||||
let runListGHC =
|
||||
runLogger
|
||||
. flip runReaderT settings
|
||||
. runE @'[FileDoesNotExistError , JSONError , DownloadFailed]
|
||||
|
||||
let runRmGHC =
|
||||
runLogger . flip runReaderT settings . runE @'[NotInstalled]
|
||||
|
||||
let runDebugInfo =
|
||||
runLogger
|
||||
. flip runReaderT settings
|
||||
. runE
|
||||
@'[NoCompatiblePlatform , NoCompatibleArch , DistroNotFound]
|
||||
|
||||
let runCompileGHC =
|
||||
runLogger
|
||||
. flip runReaderT settings
|
||||
. runResourceT
|
||||
. runE
|
||||
@'[ AlreadyInstalled
|
||||
, BuildFailed
|
||||
, DigestError
|
||||
, DownloadFailed
|
||||
, GHCupSetError
|
||||
, NoDownload
|
||||
, UnknownArchive
|
||||
--
|
||||
, JSONError
|
||||
]
|
||||
|
||||
let runCompileCabal =
|
||||
runLogger
|
||||
. flip runReaderT settings
|
||||
. runResourceT
|
||||
. runE
|
||||
@'[ JSONError
|
||||
, UnknownArchive
|
||||
, NoDownload
|
||||
, DigestError
|
||||
, DownloadFailed
|
||||
, BuildFailed
|
||||
]
|
||||
|
||||
let runUpgrade =
|
||||
runLogger
|
||||
. flip runReaderT settings
|
||||
. runResourceT
|
||||
. runE
|
||||
@'[ DigestError
|
||||
, DistroNotFound
|
||||
, NoCompatiblePlatform
|
||||
, NoCompatibleArch
|
||||
, NoDownload
|
||||
, FileDoesNotExistError
|
||||
, JSONError
|
||||
, DownloadFailed
|
||||
, CopyError
|
||||
]
|
||||
let leanAppstate = LeanAppState settings dirs keybindings loggerConfig
|
||||
let runLogger = flip runReaderT leanAppstate
|
||||
let siletRunLogger = flip runReaderT (leanAppstate { loggerConfig = loggerConfig { consoleOutter = \_ -> pure () } } :: LeanAppState)
|
||||
|
||||
|
||||
case optCommand of
|
||||
Install (InstallGHC InstallOptions {..}) ->
|
||||
void
|
||||
$ (runInstTool $ do
|
||||
dls <- liftE getDownloads
|
||||
v <- liftE $ fromVersion dls instVer GHC
|
||||
liftE $ installGHCBin dls v Nothing
|
||||
-------------------------
|
||||
-- Setting up appstate --
|
||||
-------------------------
|
||||
|
||||
|
||||
appState = do
|
||||
pfreq <- (
|
||||
runLogger . runE @'[NoCompatiblePlatform, NoCompatibleArch, DistroNotFound] . liftE $ platformRequest
|
||||
) >>= \case
|
||||
VRight r -> pure r
|
||||
VLeft e -> do
|
||||
runLogger
|
||||
(logError $ T.pack $ prettyShow e)
|
||||
exitWith (ExitFailure 2)
|
||||
|
||||
ghcupInfo <-
|
||||
( flip runReaderT leanAppstate
|
||||
. runE @'[DigestError, GPGError, JSONError , DownloadFailed, FileDoesNotExistError]
|
||||
$ liftE getDownloadsF
|
||||
)
|
||||
>>= \case
|
||||
VRight _ -> runLogger
|
||||
$ $(logInfo) ([s|GHC installation successful|])
|
||||
VLeft (V (AlreadyInstalled _ v)) ->
|
||||
runLogger $ $(logWarn)
|
||||
[i|GHC ver #{prettyVer v} already installed|]
|
||||
VLeft (V (BuildFailed tmpdir e)) ->
|
||||
runLogger
|
||||
($(logError) [i|Build failed with #{e}
|
||||
Check the logs at ~/ghcup/logs and the build directory #{tmpdir} for more clues.|]
|
||||
)
|
||||
>> exitFailure
|
||||
VLeft e -> do
|
||||
runLogger $ do
|
||||
$(logError) [i|#{e}|]
|
||||
$(logError) [i|Also check the logs in ~/.ghcup/logs|]
|
||||
exitFailure
|
||||
Install (InstallCabal InstallOptions {..}) ->
|
||||
void
|
||||
$ (runInstTool $ do
|
||||
dls <- liftE getDownloads
|
||||
v <- liftE $ fromVersion dls instVer Cabal
|
||||
liftE $ installCabalBin dls v Nothing
|
||||
)
|
||||
>>= \case
|
||||
VRight _ -> runLogger
|
||||
$ $(logInfo) ([s|Cabal installation successful|])
|
||||
VLeft (V (AlreadyInstalled _ v)) ->
|
||||
runLogger $ $(logWarn)
|
||||
[i|Cabal ver #{prettyVer v} already installed|]
|
||||
VLeft e -> do
|
||||
runLogger $ do
|
||||
$(logError) [i|#{e}|]
|
||||
$(logError) [i|Also check the logs in ~/.ghcup/logs|]
|
||||
exitFailure
|
||||
>>= \case
|
||||
VRight r -> pure r
|
||||
VLeft e -> do
|
||||
runLogger
|
||||
(logError $ T.pack $ prettyShow e)
|
||||
exitWith (ExitFailure 2)
|
||||
let s' = AppState settings dirs keybindings ghcupInfo pfreq loggerConfig
|
||||
|
||||
SetGHC (SetGHCOptions {..}) ->
|
||||
void
|
||||
$ (runSetGHC $ do
|
||||
dls <- liftE getDownloads
|
||||
v <- liftE $ fromVersion dls ghcVer GHC
|
||||
liftE $ setGHC v SetGHCOnly
|
||||
)
|
||||
>>= \case
|
||||
VRight _ ->
|
||||
runLogger $ $(logInfo) ([s|GHC successfully set|])
|
||||
VLeft e ->
|
||||
runLogger ($(logError) [i|#{e}|]) >> exitFailure
|
||||
race_ (liftIO $ runReaderT cleanupTrash s')
|
||||
(threadDelay 5000000 >> runLogger (logWarn $ "Killing cleanup thread (exceeded 5s timeout)... please remove leftover files in " <> T.pack recycleDir <> " manually"))
|
||||
|
||||
List (ListOptions {..}) ->
|
||||
void
|
||||
$ (runListGHC $ do
|
||||
dls <- liftE getDownloads
|
||||
liftIO $ listVersions dls lTool lCriteria
|
||||
)
|
||||
>>= \case
|
||||
VRight r -> liftIO $ printListResult r
|
||||
VLeft e ->
|
||||
runLogger ($(logError) [i|#{e}|]) >> exitFailure
|
||||
case optCommand of
|
||||
Nuke -> pure ()
|
||||
Whereis _ _ -> pure ()
|
||||
DInfo -> pure ()
|
||||
ToolRequirements -> pure ()
|
||||
ChangeLog _ -> pure ()
|
||||
UnSet _ -> pure ()
|
||||
#if defined(BRICK)
|
||||
Interactive -> pure ()
|
||||
#endif
|
||||
_ -> lookupEnv "GHCUP_SKIP_UPDATE_CHECK" >>= \case
|
||||
Nothing -> runReaderT checkForUpdates s'
|
||||
Just _ -> pure ()
|
||||
|
||||
Rm (RmOptions {..}) ->
|
||||
void
|
||||
$ (runRmGHC $ do
|
||||
liftE $ rmGHCVer ghcVer
|
||||
)
|
||||
>>= \case
|
||||
VRight _ -> pure ()
|
||||
VLeft e ->
|
||||
runLogger ($(logError) [i|#{e}|]) >> exitFailure
|
||||
-- TODO: always run for windows
|
||||
siletRunLogger (flip runReaderT s' $ runE ensureGlobalTools) >>= \case
|
||||
VRight _ -> pure ()
|
||||
VLeft e -> do
|
||||
runLogger
|
||||
(logError $ T.pack $ prettyShow e)
|
||||
exitWith (ExitFailure 30)
|
||||
pure s'
|
||||
|
||||
DInfo -> do
|
||||
void
|
||||
$ (runDebugInfo $ do
|
||||
liftE $ getDebugInfo
|
||||
)
|
||||
>>= \case
|
||||
VRight dinfo -> putStrLn $ show dinfo
|
||||
VLeft e ->
|
||||
runLogger ($(logError) [i|#{e}|]) >> exitFailure
|
||||
|
||||
Compile (CompileGHC CompileOptions {..}) ->
|
||||
void
|
||||
$ (runCompileGHC $ do
|
||||
dls <- liftE getDownloads
|
||||
liftE
|
||||
$ compileGHC dls targetVer bootstrapVer jobs buildConfig
|
||||
)
|
||||
>>= \case
|
||||
VRight _ ->
|
||||
runLogger $ $(logInfo)
|
||||
([s|GHC successfully compiled and installed|])
|
||||
VLeft (V (AlreadyInstalled _ v)) ->
|
||||
runLogger $ $(logWarn)
|
||||
[i|GHC ver #{prettyVer v} already installed|]
|
||||
VLeft (V (BuildFailed tmpdir e)) ->
|
||||
runLogger
|
||||
($(logError) [i|Build failed with #{e}
|
||||
Check the logs at ~/ghcup/logs and the build directory #{tmpdir} for more clues.|]
|
||||
)
|
||||
>> exitFailure
|
||||
VLeft e ->
|
||||
runLogger ($(logError) [i|#{e}|]) >> exitFailure
|
||||
#if defined(IS_WINDOWS)
|
||||
-- FIXME: windows needs 'ensureGlobalTools', which requires
|
||||
-- full appstate
|
||||
runLeanAppState = runAppState
|
||||
#else
|
||||
runLeanAppState = flip runReaderT leanAppstate
|
||||
#endif
|
||||
runAppState action' = do
|
||||
s' <- liftIO appState
|
||||
runReaderT action' s'
|
||||
|
||||
|
||||
Compile (CompileCabal CompileOptions {..}) ->
|
||||
void
|
||||
$ (runCompileCabal $ do
|
||||
dls <- liftE getDownloads
|
||||
liftE $ compileCabal dls
|
||||
targetVer
|
||||
bootstrapVer
|
||||
jobs
|
||||
)
|
||||
>>= \case
|
||||
VRight _ ->
|
||||
runLogger $ $(logInfo)
|
||||
([s|Cabal successfully compiled and installed|])
|
||||
VLeft (V (BuildFailed tmpdir e)) ->
|
||||
runLogger
|
||||
($(logError) [i|Build failed with #{e}
|
||||
Check the logs at ~/ghcup/logs and the build directory #{tmpdir} for more clues.|]
|
||||
)
|
||||
>> exitFailure
|
||||
VLeft e ->
|
||||
runLogger ($(logError) [i|#{e}|]) >> exitFailure
|
||||
-----------------
|
||||
-- Run command --
|
||||
-----------------
|
||||
|
||||
Upgrade (uOpts) -> do
|
||||
target <- case uOpts of
|
||||
UpgradeInplace -> do
|
||||
efp <- liftIO $ getExecutablePath
|
||||
p <- parseAbs . E.encodeUtf8 . T.pack $ efp
|
||||
pure $ Just p
|
||||
(UpgradeAt p) -> pure $ Just p
|
||||
UpgradeGHCupDir -> do
|
||||
bdir <- liftIO $ ghcupBinDir
|
||||
pure (Just (bdir </> ([rel|ghcup|] :: Path Rel)))
|
||||
res <- case optCommand of
|
||||
#if defined(BRICK)
|
||||
Interactive -> do
|
||||
s' <- appState
|
||||
liftIO $ brickMain s' >> pure ExitSuccess
|
||||
#endif
|
||||
Install installCommand -> install installCommand settings appState runLogger
|
||||
InstallCabalLegacy iopts -> install (Left (InstallCabal iopts)) settings appState runLogger
|
||||
Set setCommand -> set setCommand runAppState runLeanAppState runLogger
|
||||
UnSet unsetCommand -> unset unsetCommand runLeanAppState runLogger
|
||||
List lo -> list lo no_color runAppState
|
||||
Rm rmCommand -> rm rmCommand runAppState runLogger
|
||||
DInfo -> dinfo runAppState runLogger
|
||||
Compile compileCommand -> compile compileCommand settings runAppState runLogger
|
||||
Config configCommand -> config configCommand settings keybindings runLogger
|
||||
Whereis whereisOptions
|
||||
whereisCommand -> whereis whereisCommand whereisOptions runAppState leanAppstate runLogger
|
||||
Upgrade uOpts force' -> upgrade uOpts force' runAppState runLogger
|
||||
ToolRequirements -> toolRequirements runAppState runLogger
|
||||
ChangeLog changelogOpts -> changelog changelogOpts runAppState runLogger
|
||||
Nuke -> nuke appState runLogger
|
||||
Prefetch pfCom -> prefetch pfCom runAppState runLogger
|
||||
GC gcOpts -> gc gcOpts runAppState runLogger
|
||||
|
||||
void
|
||||
$ (runUpgrade $ do
|
||||
dls <- liftE getDownloads
|
||||
liftE $ upgradeGHCup dls target
|
||||
)
|
||||
>>= \case
|
||||
VRight v' -> do
|
||||
let pretty_v = prettyVer v'
|
||||
runLogger
|
||||
$ $(logInfo)
|
||||
[i|Successfully upgraded GHCup to version #{pretty_v}|]
|
||||
VLeft e ->
|
||||
runLogger ($(logError) [i|#{e}|]) >> exitFailure
|
||||
case res of
|
||||
ExitSuccess -> pure ()
|
||||
ef@(ExitFailure _) -> exitWith ef
|
||||
|
||||
NumericVersion -> T.hPutStr stdout (prettyPVP ghcUpVer)
|
||||
pure ()
|
||||
|
||||
|
||||
fromVersion :: Monad m
|
||||
=> GHCupDownloads
|
||||
-> Maybe ToolVersion
|
||||
-> Tool
|
||||
-> Excepts '[TagNotFound] m Version
|
||||
fromVersion av Nothing tool =
|
||||
getRecommended av tool ?? TagNotFound Recommended tool
|
||||
fromVersion _ (Just (ToolVersion v)) _ = pure v
|
||||
fromVersion av (Just (ToolTag Latest)) tool =
|
||||
getLatest av tool ?? TagNotFound Latest tool
|
||||
fromVersion av (Just (ToolTag Recommended)) tool =
|
||||
getRecommended av tool ?? TagNotFound Recommended tool
|
||||
|
||||
|
||||
printListResult :: [ListResult] -> IO ()
|
||||
printListResult lr = do
|
||||
let
|
||||
formatted =
|
||||
gridString
|
||||
[ column expand left def def
|
||||
, column expand left def def
|
||||
, column expand left def def
|
||||
, column expand left def def
|
||||
, column expand left def def
|
||||
]
|
||||
$ fmap
|
||||
(\ListResult {..} ->
|
||||
[ if
|
||||
| lSet -> (color Green "✔✔")
|
||||
| lInstalled -> (color Green "✓")
|
||||
| otherwise -> (color Red "✗")
|
||||
, fmap toLower . show $ lTool
|
||||
, T.unpack . prettyVer $ lVer
|
||||
, intercalate "," $ ((fmap . fmap) toLower . fmap show $ lTag)
|
||||
, if fromSrc then (color Blue "compiled") else mempty
|
||||
]
|
||||
)
|
||||
lr
|
||||
putStrLn $ formatted
|
||||
|
||||
29
cabal.ghc8107.project
Normal file
@@ -0,0 +1,29 @@
|
||||
packages: ./ghcup.cabal
|
||||
|
||||
optional-packages: ./vendored/*/*.cabal
|
||||
|
||||
optimization: 2
|
||||
|
||||
package ghcup
|
||||
tests: True
|
||||
flags: +tui
|
||||
|
||||
constraints: http-io-streams -brotli,
|
||||
any.Cabal ==3.6.2.0,
|
||||
any.aeson >= 2.0.1.0
|
||||
|
||||
package libarchive
|
||||
flags: -system-libarchive
|
||||
|
||||
package aeson-pretty
|
||||
flags: +lib-only
|
||||
|
||||
package cabal-plan
|
||||
flags: -exe
|
||||
|
||||
package aeson
|
||||
flags: +ordered-keymap
|
||||
|
||||
allow-newer: base, ghc-prim, template-haskell, language-c
|
||||
|
||||
with-compiler: ghc-8.10.7
|
||||
229
cabal.ghc8107.project.freeze
Normal file
@@ -0,0 +1,229 @@
|
||||
active-repositories: hackage.haskell.org:merge
|
||||
constraints: any.Cabal ==3.6.2.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.QuickCheck ==2.14.2,
|
||||
QuickCheck -old-random +templatehaskell,
|
||||
any.StateVar ==1.2.2,
|
||||
any.abstract-deque ==0.3,
|
||||
abstract-deque -usecas,
|
||||
any.aeson ==2.0.1.0,
|
||||
aeson -bytestring-builder -cffi +ordered-keymap,
|
||||
any.aeson-pretty ==0.8.9,
|
||||
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.4,
|
||||
async -bench,
|
||||
any.atomic-primops ==0.8.4,
|
||||
atomic-primops -debug,
|
||||
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.2,
|
||||
any.brick ==0.64.2,
|
||||
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.1,
|
||||
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.1,
|
||||
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.fusion-plugin-types ==0.1.0,
|
||||
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.4.1,
|
||||
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.heaps ==0.4,
|
||||
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.1,
|
||||
libarchive -cross -low-memory -system-libarchive,
|
||||
any.libyaml-streamly ==0.2.0,
|
||||
libyaml-streamly -no-unicode -system-libyaml,
|
||||
any.lockfree-queue ==0.2.3.1,
|
||||
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.monad-control ==1.0.3.1,
|
||||
any.mtl ==2.2.2,
|
||||
any.network ==3.1.2.5,
|
||||
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.1,
|
||||
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.retry ==0.8.1.2,
|
||||
retry -lib-werror,
|
||||
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.semialign ==1.2,
|
||||
semialign +semigroupoids,
|
||||
any.semigroupoids ==5.3.6,
|
||||
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.streamly ==0.8.0,
|
||||
streamly -debug -dev -fusion-plugin -has-llvm -inspection -no-fusion +opt -streamk -use-c-malloc,
|
||||
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.5,
|
||||
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.witherable ==0.4.2,
|
||||
any.word-wrap ==0.5,
|
||||
any.word8 ==0.1.3,
|
||||
any.xor ==0.0.1.0,
|
||||
any.yaml-streamly ==0.12.0,
|
||||
yaml-streamly +no-examples +no-exe,
|
||||
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-24T10:21:56Z
|
||||
29
cabal.ghc901.project
Normal file
@@ -0,0 +1,29 @@
|
||||
packages: ./ghcup.cabal
|
||||
|
||||
optional-packages: ./vendored/*/*.cabal
|
||||
|
||||
optimization: 2
|
||||
|
||||
package ghcup
|
||||
tests: True
|
||||
flags: +tui
|
||||
|
||||
constraints: http-io-streams -brotli,
|
||||
any.Cabal ==3.6.2.0,
|
||||
any.aeson >= 2.0.1.0
|
||||
|
||||
package libarchive
|
||||
flags: -system-libarchive
|
||||
|
||||
package aeson-pretty
|
||||
flags: +lib-only
|
||||
|
||||
package cabal-plan
|
||||
flags: -exe
|
||||
|
||||
package aeson
|
||||
flags: +ordered-keymap
|
||||
|
||||
allow-newer: base, ghc-prim, template-haskell, language-c
|
||||
|
||||
with-compiler: ghc-9.0.1
|
||||
229
cabal.ghc901.project.freeze
Normal file
@@ -0,0 +1,229 @@
|
||||
active-repositories: hackage.haskell.org:merge
|
||||
constraints: any.Cabal ==3.6.2.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.QuickCheck ==2.14.2,
|
||||
QuickCheck -old-random +templatehaskell,
|
||||
any.StateVar ==1.2.2,
|
||||
any.abstract-deque ==0.3,
|
||||
abstract-deque -usecas,
|
||||
any.aeson ==2.0.1.0,
|
||||
aeson -bytestring-builder -cffi +ordered-keymap,
|
||||
any.aeson-pretty ==0.8.9,
|
||||
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.4,
|
||||
async -bench,
|
||||
any.atomic-primops ==0.8.4,
|
||||
atomic-primops -debug,
|
||||
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.2,
|
||||
any.brick ==0.64.2,
|
||||
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.1,
|
||||
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.1,
|
||||
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.fusion-plugin-types ==0.1.0,
|
||||
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.4.1,
|
||||
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.heaps ==0.4,
|
||||
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.1,
|
||||
libarchive -cross -low-memory -system-libarchive,
|
||||
any.libyaml-streamly ==0.2.0,
|
||||
libyaml-streamly -no-unicode -system-libyaml,
|
||||
any.lockfree-queue ==0.2.3.1,
|
||||
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.monad-control ==1.0.3.1,
|
||||
any.mtl ==2.2.2,
|
||||
any.network ==3.1.2.5,
|
||||
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.1,
|
||||
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.retry ==0.8.1.2,
|
||||
retry -lib-werror,
|
||||
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.semialign ==1.2,
|
||||
semialign +semigroupoids,
|
||||
any.semigroupoids ==5.3.6,
|
||||
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.streamly ==0.8.0,
|
||||
streamly -debug -dev -fusion-plugin -has-llvm -inspection -no-fusion +opt -streamk -use-c-malloc,
|
||||
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.5,
|
||||
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.witherable ==0.4.2,
|
||||
any.word-wrap ==0.5,
|
||||
any.word8 ==0.1.3,
|
||||
any.xor ==0.0.1.0,
|
||||
any.yaml-streamly ==0.12.0,
|
||||
yaml-streamly +no-examples +no-exe,
|
||||
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-24T10:21:56Z
|
||||
@@ -1,15 +1,32 @@
|
||||
packages: ./ghcup.cabal
|
||||
|
||||
with-compiler: ghc-8.6.5
|
||||
optional-packages: ./vendored/*/*.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
|
||||
tests: True
|
||||
flags: +tui
|
||||
|
||||
package tar-bytestring
|
||||
ghc-options: -O2
|
||||
constraints: http-io-streams -brotli,
|
||||
any.Cabal ==3.6.2.0,
|
||||
any.aeson >= 2.0.1.0
|
||||
|
||||
source-repository-package
|
||||
type: git
|
||||
location: https://github.com/input-output-hk/optparse-applicative
|
||||
tag: 7497a29cb998721a9068d5725d49461f2bba0e7a
|
||||
|
||||
package libarchive
|
||||
flags: -system-libarchive
|
||||
|
||||
package aeson-pretty
|
||||
flags: +lib-only
|
||||
|
||||
package cabal-plan
|
||||
flags: -exe
|
||||
|
||||
package aeson
|
||||
flags: +ordered-keymap
|
||||
|
||||
allow-newer: base, ghc-prim, template-haskell, language-c
|
||||
|
||||
@@ -1,229 +1,2 @@
|
||||
constraints: any.Cabal ==2.4.0.1,
|
||||
any.HsOpenSSL ==0.11.4.17,
|
||||
HsOpenSSL -fast-bignum -homebrew-openssl -macports-openssl -old-locale,
|
||||
any.IfElse ==0.85,
|
||||
any.QuickCheck ==2.13.2,
|
||||
QuickCheck +templatehaskell,
|
||||
any.StateVar ==1.2,
|
||||
any.abstract-deque ==0.3,
|
||||
abstract-deque -usecas,
|
||||
any.aeson ==1.4.6.0,
|
||||
aeson -bytestring-builder -cffi -developer -fast,
|
||||
any.aeson-pretty ==0.8.8,
|
||||
aeson-pretty -lib-only,
|
||||
any.ansi-terminal ==0.10.3,
|
||||
ansi-terminal -example,
|
||||
any.ansi-wl-pprint ==0.6.9,
|
||||
ansi-wl-pprint -example,
|
||||
any.array ==0.5.3.0,
|
||||
any.ascii-string ==1.0.1.4,
|
||||
any.assoc ==1.0.1,
|
||||
any.async ==2.2.2,
|
||||
async -bench,
|
||||
any.atomic-primops ==0.8.3,
|
||||
atomic-primops -debug,
|
||||
any.attoparsec ==0.13.2.3,
|
||||
attoparsec -developer,
|
||||
any.auto-update ==0.1.6,
|
||||
any.base ==4.12.0.0,
|
||||
any.base-compat ==0.11.1,
|
||||
any.base-orphans ==0.8.2,
|
||||
any.base-prelude ==1.3,
|
||||
any.base16-bytestring ==0.1.1.6,
|
||||
any.base64-bytestring ==1.0.0.3,
|
||||
any.bifunctors ==5.5.7,
|
||||
bifunctors +semigroups +tagged,
|
||||
any.binary ==0.8.6.0,
|
||||
any.blaze-builder ==0.4.1.0,
|
||||
any.brotli ==0.0.0.0,
|
||||
any.brotli-streams ==0.0.0.0,
|
||||
any.bytestring ==0.10.8.2,
|
||||
any.bytestring-builder ==0.10.8.2.0,
|
||||
bytestring-builder +bytestring_has_builder,
|
||||
any.bzlib ==0.5.0.5,
|
||||
any.cabal-doctest ==1.0.8,
|
||||
any.case-insensitive ==1.2.1.0,
|
||||
any.cereal ==0.5.8.1,
|
||||
cereal -bytestring-builder,
|
||||
any.clock ==0.8,
|
||||
clock -llvm,
|
||||
any.cmdargs ==0.10.20,
|
||||
cmdargs +quotation -testprog,
|
||||
any.colour ==2.3.5,
|
||||
any.comonad ==5.0.6,
|
||||
comonad +containers +distributive +test-doctests,
|
||||
any.conduit ==1.3.1.2,
|
||||
any.conduit-extra ==1.3.4,
|
||||
any.containers ==0.6.0.1,
|
||||
any.contravariant ==1.5.2,
|
||||
contravariant +semigroups +statevar +tagged,
|
||||
any.data-default-class ==0.1.2.0,
|
||||
any.data-default-instances-base ==0.1.0.1,
|
||||
any.deepseq ==1.4.4.0,
|
||||
any.deferred-folds ==0.9.10.1,
|
||||
any.directory ==1.3.3.0 || ==1.3.6.0,
|
||||
any.distributive ==0.6.1,
|
||||
distributive +semigroups +tagged,
|
||||
any.dlist ==0.8.0.7,
|
||||
any.easy-file ==0.2.2,
|
||||
any.errors ==2.3.0,
|
||||
any.exceptions ==0.10.4,
|
||||
exceptions +transformers-0-4,
|
||||
any.extra ==1.7,
|
||||
any.fast-logger ==3.0.1,
|
||||
any.filepath ==1.4.2.1,
|
||||
any.focus ==1.0.1.3,
|
||||
any.foldl ==1.4.6,
|
||||
any.free ==5.1.3,
|
||||
any.fusion-plugin-types ==0.1.0,
|
||||
any.generics-sop ==0.5.0.0,
|
||||
any.ghc-boot-th ==8.6.5,
|
||||
any.ghc-prim ==0.5.3,
|
||||
any.happy ==1.19.12,
|
||||
happy +small_base,
|
||||
any.hashable ==1.3.0.0,
|
||||
hashable -examples +integer-gmp +sse2 -sse41,
|
||||
any.haskell-src-exts ==1.23.0,
|
||||
any.haskell-src-meta ==0.8.5,
|
||||
any.haskus-utils-data ==1.2,
|
||||
any.haskus-utils-types ==1.5,
|
||||
any.haskus-utils-variant ==3.0,
|
||||
any.heaps ==0.3.6.1,
|
||||
any.hopenssl ==2.2.4,
|
||||
hopenssl -link-libz,
|
||||
any.hpath ==0.11.0,
|
||||
any.hpath-directory ==0.13.2,
|
||||
any.hpath-filepath ==0.10.4,
|
||||
any.hpath-io ==0.13.1,
|
||||
any.hpath-posix ==0.13.1,
|
||||
any.hsc2hs ==0.68.6,
|
||||
hsc2hs -in-ghc-tree,
|
||||
any.http-io-streams ==0.1.2.0,
|
||||
http-io-streams +brotli,
|
||||
any.indexed-profunctors ==0.1,
|
||||
any.integer-gmp ==1.0.2.0,
|
||||
any.integer-logarithms ==1.0.3,
|
||||
integer-logarithms -check-bounds +integer-gmp,
|
||||
any.io-streams ==1.5.1.0,
|
||||
io-streams -nointeractivetests,
|
||||
any.language-bash ==0.9.0,
|
||||
any.lifted-base ==0.2.3.12,
|
||||
any.list-t ==1.0.4,
|
||||
any.lockfree-queue ==0.2.3.1,
|
||||
any.lzma ==0.0.0.3,
|
||||
any.math-functions ==0.3.3.0,
|
||||
math-functions +system-erf +system-expm1,
|
||||
any.megaparsec ==8.0.0,
|
||||
megaparsec -dev,
|
||||
any.mmorph ==1.1.3,
|
||||
any.monad-control ==1.0.2.3,
|
||||
any.monad-logger ==0.3.32,
|
||||
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.14.0.0,
|
||||
any.network ==3.1.1.1,
|
||||
any.network-uri ==2.6.3.0,
|
||||
any.old-locale ==1.0.0.7,
|
||||
any.old-time ==1.1.0.3,
|
||||
any.openssl-streams ==1.2.2.0,
|
||||
any.optics ==0.2,
|
||||
any.optics-core ==0.2,
|
||||
any.optics-extra ==0.2,
|
||||
any.optics-th ==0.2,
|
||||
any.optics-vl ==0.2,
|
||||
any.optparse-applicative ==0.15.1.0,
|
||||
any.parsec ==3.1.13.0,
|
||||
any.parser-combinators ==1.2.1,
|
||||
parser-combinators -dev,
|
||||
any.pretty ==1.1.3.6,
|
||||
any.pretty-terminal ==0.1.0.0,
|
||||
any.prettyprinter ==1.6.1,
|
||||
prettyprinter -buildreadme,
|
||||
any.primitive ==0.7.0.1,
|
||||
any.primitive-extras ==0.8,
|
||||
any.primitive-unlifted ==0.1.3.0,
|
||||
any.process ==1.6.5.0 || ==1.6.8.0,
|
||||
any.profunctors ==5.5.2,
|
||||
any.random ==1.1,
|
||||
any.recursion-schemes ==5.1.3,
|
||||
recursion-schemes +template-haskell,
|
||||
any.resourcet ==1.2.3,
|
||||
any.rts ==1.0,
|
||||
any.safe ==0.3.18,
|
||||
any.safe-exceptions ==0.1.7.0,
|
||||
any.scientific ==0.3.6.2,
|
||||
scientific -bytestring-builder -integer-simple,
|
||||
any.semigroupoids ==5.3.4,
|
||||
semigroupoids +comonad +containers +contravariant +distributive +doctests +tagged +unordered-containers,
|
||||
any.semigroups ==0.19.1,
|
||||
semigroups +binary +bytestring -bytestring-builder +containers +deepseq +hashable +tagged +template-haskell +text +transformers +unordered-containers,
|
||||
any.sop-core ==0.5.0.0,
|
||||
any.split ==0.2.3.4,
|
||||
any.splitmix ==0.0.4,
|
||||
splitmix -optimised-mixer +random,
|
||||
any.stm ==2.5.0.0,
|
||||
any.stm-chans ==3.0.0.4,
|
||||
any.streaming-commons ==0.2.1.2,
|
||||
streaming-commons -use-bytestring-builder,
|
||||
any.streamly ==0.7.1,
|
||||
streamly -debug -dev -examples -examples-sdl -fusion-plugin -has-llvm -inspection -no-charts -no-fusion -streamk,
|
||||
any.streamly-bytestring ==0.1.2,
|
||||
any.streamly-posix ==0.1.0.0,
|
||||
any.strict-base ==0.4.0.0,
|
||||
any.string-interpolate ==0.2.0.0,
|
||||
any.syb ==0.7.1,
|
||||
any.table-layout ==0.8.0.5,
|
||||
any.tagged ==0.8.6,
|
||||
tagged +deepseq +transformers,
|
||||
any.tar-bytestring ==0.6.3.0,
|
||||
any.template-haskell ==2.14.0.0,
|
||||
any.terminal-progress-bar ==0.4.1,
|
||||
any.terminal-size ==0.3.2.1,
|
||||
any.text ==1.2.3.1,
|
||||
any.text-conversions ==0.3.0,
|
||||
any.text-icu ==0.7.0.1,
|
||||
any.text-short ==0.1.3,
|
||||
text-short -asserts,
|
||||
any.th-abstraction ==0.3.2.0,
|
||||
any.th-expand-syns ==0.4.5.0,
|
||||
any.th-lift ==0.8.1,
|
||||
any.th-lift-instances ==0.1.14,
|
||||
any.th-orphans ==0.13.9,
|
||||
any.th-reify-many ==0.1.9,
|
||||
any.these ==1.0.1,
|
||||
these +aeson +assoc +quickcheck +semigroupoids,
|
||||
any.time ==1.8.0.2 || ==1.9.3,
|
||||
any.time-compat ==1.9.2.2,
|
||||
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.5,
|
||||
transformers-compat -five +five-three -four +generic-deriving +mtl -three -two,
|
||||
any.typed-process ==0.2.6.0,
|
||||
any.unix ==2.7.2.2,
|
||||
any.unix-bytestring ==0.3.7.3,
|
||||
any.unix-compat ==0.5.2,
|
||||
unix-compat -old-time,
|
||||
any.unix-time ==0.4.7,
|
||||
any.unliftio-core ==0.2.0.1,
|
||||
any.unordered-containers ==0.2.10.0,
|
||||
unordered-containers -debug,
|
||||
any.uri-bytestring ==0.3.2.2,
|
||||
uri-bytestring -lib-werror,
|
||||
any.utf8-string ==1.0.1.1,
|
||||
any.uuid-types ==1.0.3,
|
||||
any.vector ==0.12.1.2,
|
||||
vector +boundschecks -internalchecks -unsafechecks -wall,
|
||||
any.vector-algorithms ==0.8.0.3,
|
||||
vector-algorithms +bench +boundschecks -internalchecks -llvm +properties -unsafechecks,
|
||||
any.vector-builder ==0.3.8,
|
||||
any.vector-th-unbox ==0.2.1.7,
|
||||
any.versions ==3.5.3,
|
||||
any.word8 ==0.1.3,
|
||||
any.zlib ==0.6.2.1,
|
||||
zlib -non-blocking-ffi -pkg-config,
|
||||
any.zlib-bindings ==0.1.1.5
|
||||
-- windows picks weird version
|
||||
constraints: any.hsc2hs ==0.68.7
|
||||
|
||||
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
|
||||
71
data/config.yaml
Normal file
@@ -0,0 +1,71 @@
|
||||
# Cache downloads in ~/.ghcup/cache
|
||||
cache: False
|
||||
# Skip tarball checksum verification
|
||||
no-verify: False
|
||||
# enable verbosity
|
||||
verbose: False
|
||||
# When to keep build directories
|
||||
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
|
||||
# for possible values.
|
||||
key-bindings:
|
||||
up:
|
||||
KUp: []
|
||||
down:
|
||||
KDown: []
|
||||
quit:
|
||||
KChar: 'q'
|
||||
install:
|
||||
KChar: 'i'
|
||||
uninstall:
|
||||
KChar: 'u'
|
||||
set:
|
||||
KChar: 's'
|
||||
changelog:
|
||||
KChar: 'c'
|
||||
show-all:
|
||||
KChar: 'a'
|
||||
show-all-tools:
|
||||
KChar: 't'
|
||||
|
||||
# The caching for the metadata files containing download info, depending on last access time
|
||||
# of the file. These usually are in '~/.ghcup/cache/ghcup-<ver>.yaml'.
|
||||
meta-cache: 300 # in seconds
|
||||
|
||||
# Where to get GHC/cabal/hls download info/versions from. For more detailed explanation
|
||||
# check the 'URLSource' type in the code.
|
||||
url-source:
|
||||
## Use the internal download uri, this is the default
|
||||
GHCupURL: []
|
||||
|
||||
## Example 1: Read download info from this location instead
|
||||
## Accepts file/http/https scheme
|
||||
# OwnSource: "file:///home/jule/git/ghcup-hs/ghcup-0.0.3.yaml"
|
||||
|
||||
## Example 2: Add custom tarballs to the default downloads, overwriting duplicate versions
|
||||
# AddSource:
|
||||
# Left:
|
||||
# toolRequirements: {} # this is ignored
|
||||
# ghcupDownloads:
|
||||
# GHC:
|
||||
# 9.10.2:
|
||||
# viTags: []
|
||||
# viArch:
|
||||
# A_64:
|
||||
# Linux_UnknownLinux:
|
||||
# unknown_versioning:
|
||||
# dlUri: https://downloads.haskell.org/~ghc/7.10.3/ghc-7.10.3-x86_64-deb8-linux.tar.bz2
|
||||
# dlSubdir: ghc-7.10.3
|
||||
# dlHash: 01cfbad8dff1e8b34a5fdca8caeaf843b56e36af919e29cd68870d2588563db5
|
||||
|
||||
## Example 3: Add a custom download file to the default downloads, overwriting duplicate versions
|
||||
# AddSource:
|
||||
# Right: "file:///home/jule/git/ghcup-hs/ghcup-custom.yaml"
|
||||
1
docs/BUGS.md
Normal file
@@ -0,0 +1 @@
|
||||
# Known BUGS
|
||||
10
docs/Discord-Logo-Black.svg
Normal file
@@ -0,0 +1,10 @@
|
||||
<svg width="71" height="55" viewBox="0 0 71 55" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0)">
|
||||
<path d="M60.1045 4.8978C55.5792 2.8214 50.7265 1.2916 45.6527 0.41542C45.5603 0.39851 45.468 0.440769 45.4204 0.525289C44.7963 1.6353 44.105 3.0834 43.6209 4.2216C38.1637 3.4046 32.7345 3.4046 27.3892 4.2216C26.905 3.0581 26.1886 1.6353 25.5617 0.525289C25.5141 0.443589 25.4218 0.40133 25.3294 0.41542C20.2584 1.2888 15.4057 2.8186 10.8776 4.8978C10.8384 4.9147 10.8048 4.9429 10.7825 4.9795C1.57795 18.7309 -0.943561 32.1443 0.293408 45.3914C0.299005 45.4562 0.335386 45.5182 0.385761 45.5576C6.45866 50.0174 12.3413 52.7249 18.1147 54.5195C18.2071 54.5477 18.305 54.5139 18.3638 54.4378C19.7295 52.5728 20.9469 50.6063 21.9907 48.5383C22.0523 48.4172 21.9935 48.2735 21.8676 48.2256C19.9366 47.4931 18.0979 46.6 16.3292 45.5858C16.1893 45.5041 16.1781 45.304 16.3068 45.2082C16.679 44.9293 17.0513 44.6391 17.4067 44.3461C17.471 44.2926 17.5606 44.2813 17.6362 44.3151C29.2558 49.6202 41.8354 49.6202 53.3179 44.3151C53.3935 44.2785 53.4831 44.2898 53.5502 44.3433C53.9057 44.6363 54.2779 44.9293 54.6529 45.2082C54.7816 45.304 54.7732 45.5041 54.6333 45.5858C52.8646 46.6197 51.0259 47.4931 49.0921 48.2228C48.9662 48.2707 48.9102 48.4172 48.9718 48.5383C50.038 50.6034 51.2554 52.5699 52.5959 54.435C52.6519 54.5139 52.7526 54.5477 52.845 54.5195C58.6464 52.7249 64.529 50.0174 70.6019 45.5576C70.6551 45.5182 70.6887 45.459 70.6943 45.3942C72.1747 30.0791 68.2147 16.7757 60.1968 4.9823C60.1772 4.9429 60.1437 4.9147 60.1045 4.8978ZM23.7259 37.3253C20.2276 37.3253 17.3451 34.1136 17.3451 30.1693C17.3451 26.225 20.1717 23.0133 23.7259 23.0133C27.308 23.0133 30.1626 26.2532 30.1066 30.1693C30.1066 34.1136 27.28 37.3253 23.7259 37.3253ZM47.3178 37.3253C43.8196 37.3253 40.9371 34.1136 40.9371 30.1693C40.9371 26.225 43.7636 23.0133 47.3178 23.0133C50.9 23.0133 53.7545 26.2532 53.6986 30.1693C53.6986 34.1136 50.9 37.3253 47.3178 37.3253Z" fill="#23272A"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0">
|
||||
<rect width="71" height="55" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.0 KiB |
7
docs/Matrix_logo.svg
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg version="1.1" viewBox="0 0 75 32" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
||||
<title>Matrix (protocol) logo</title>
|
||||
<g fill="#040404">
|
||||
<path d="m0.936 0.732v30.52h2.194v0.732h-3.035v-31.98h3.034v0.732zm8.45 9.675v1.544h0.044a4.461 4.461 0 0 1 1.487-1.368c0.58-0.323 1.245-0.485 1.993-0.485 0.72 0 1.377 0.14 1.972 0.42 0.595 0.279 1.047 0.771 1.355 1.477 0.338-0.5 0.796-0.941 1.377-1.323 0.58-0.383 1.266-0.574 2.06-0.574 0.602 0 1.16 0.074 1.674 0.22 0.514 0.148 0.954 0.383 1.322 0.707 0.366 0.323 0.653 0.746 0.859 1.268 0.205 0.522 0.308 1.15 0.308 1.887v7.633h-3.127v-6.464c0-0.383-0.015-0.743-0.044-1.082a2.305 2.305 0 0 0-0.242-0.882 1.473 1.473 0 0 0-0.584-0.596c-0.257-0.146-0.606-0.22-1.047-0.22-0.44 0-0.796 0.085-1.068 0.253-0.272 0.17-0.485 0.39-0.639 0.662a2.654 2.654 0 0 0-0.308 0.927 7.074 7.074 0 0 0-0.078 1.048v6.354h-3.128v-6.398c0-0.338-7e-3 -0.673-0.021-1.004a2.825 2.825 0 0 0-0.188-0.916 1.411 1.411 0 0 0-0.55-0.673c-0.258-0.168-0.636-0.253-1.135-0.253a2.33 2.33 0 0 0-0.584 0.1 1.94 1.94 0 0 0-0.705 0.374c-0.228 0.184-0.422 0.449-0.584 0.794-0.161 0.346-0.242 0.798-0.242 1.357v6.619h-3.129v-11.41zm16.46 1.677a3.751 3.751 0 0 1 1.233-1.17 5.37 5.37 0 0 1 1.685-0.629 9.579 9.579 0 0 1 1.884-0.187c0.573 0 1.153 0.04 1.74 0.121 0.588 0.081 1.124 0.24 1.609 0.475 0.484 0.235 0.88 0.562 1.19 0.981 0.308 0.42 0.462 0.975 0.462 1.666v5.934c0 0.516 0.03 1.008 0.088 1.478 0.058 0.471 0.161 0.824 0.308 1.06h-3.171a4.435 4.435 0 0 1-0.22-1.104c-0.5 0.515-1.087 0.876-1.762 1.081a7.084 7.084 0 0 1-2.071 0.31c-0.544 0-1.05-0.067-1.52-0.2a3.472 3.472 0 0 1-1.234-0.617 2.87 2.87 0 0 1-0.826-1.059c-0.199-0.426-0.298-0.934-0.298-1.522 0-0.647 0.114-1.18 0.342-1.6 0.227-0.419 0.52-0.753 0.881-1.004 0.36-0.25 0.771-0.437 1.234-0.562 0.462-0.125 0.929-0.224 1.399-0.298 0.47-0.073 0.932-0.132 1.387-0.176 0.456-0.044 0.86-0.11 1.212-0.199 0.353-0.088 0.631-0.217 0.837-0.386s0.301-0.415 0.287-0.74c0-0.337-0.055-0.606-0.166-0.804a1.217 1.217 0 0 0-0.44-0.464 1.737 1.737 0 0 0-0.639-0.22 5.292 5.292 0 0 0-0.782-0.055c-0.617 0-1.101 0.132-1.454 0.397-0.352 0.264-0.558 0.706-0.617 1.323h-3.128c0.044-0.735 0.227-1.345 0.55-1.83zm6.179 4.423a5.095 5.095 0 0 1-0.639 0.165 9.68 9.68 0 0 1-0.716 0.11c-0.25 0.03-0.5 0.067-0.749 0.11a5.616 5.616 0 0 0-0.694 0.177 2.057 2.057 0 0 0-0.594 0.298c-0.17 0.125-0.305 0.284-0.408 0.474-0.103 0.192-0.154 0.434-0.154 0.728 0 0.28 0.051 0.515 0.154 0.706 0.103 0.192 0.242 0.342 0.419 0.453 0.176 0.11 0.381 0.187 0.617 0.231 0.234 0.044 0.477 0.066 0.726 0.066 0.617 0 1.094-0.102 1.432-0.309 0.338-0.205 0.587-0.452 0.75-0.739 0.16-0.286 0.26-0.576 0.297-0.87 0.036-0.295 0.055-0.53 0.055-0.707v-1.17a1.4 1.4 0 0 1-0.496 0.277zm11.86-6.1v2.096h-2.291v5.647c0 0.53 0.088 0.883 0.264 1.059 0.176 0.177 0.529 0.265 1.057 0.265 0.177 0 0.345-7e-3 0.507-0.022 0.161-0.015 0.316-0.037 0.463-0.066v2.426a7.49 7.49 0 0 1-0.882 0.089 21.67 21.67 0 0 1-0.947 0.022c-0.484 0-0.944-0.034-1.377-0.1a3.233 3.233 0 0 1-1.145-0.386 2.04 2.04 0 0 1-0.782-0.816c-0.191-0.353-0.287-0.816-0.287-1.39v-6.728h-1.894v-2.096h1.894v-3.42h3.129v3.42h2.29zm4.471 0v2.118h0.044a3.907 3.907 0 0 1 1.454-1.754 4.213 4.213 0 0 1 1.036-0.497 3.734 3.734 0 0 1 1.145-0.176c0.206 0 0.433 0.037 0.683 0.11v2.912a5.862 5.862 0 0 0-0.528-0.077 5.566 5.566 0 0 0-0.595-0.033c-0.573 0-1.058 0.096-1.454 0.287a2.52 2.52 0 0 0-0.958 0.783 3.143 3.143 0 0 0-0.518 1.158 6.32 6.32 0 0 0-0.154 1.434v5.14h-3.128v-11.4zm5.684-1.765v-2.582h3.128v2.582h-3.127zm3.128 1.765v11.4h-3.127v-11.4h3.128zm1.63 0h3.569l2.005 2.978 1.982-2.978h3.459l-3.745 5.339 4.208 6.067h-3.57l-2.378-3.596-2.38 3.596h-3.502l4.097-6.001zm15.3 20.84v-30.52h-2.194v-0.732h3.035v31.98h-3.035v-0.732z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.8 KiB |
36
docs/Octicons-bug.svg
Normal file
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
height="800.3468"
|
||||
width="733.88495"
|
||||
version="1.1"
|
||||
id="svg4"
|
||||
sodipodi:docname="Octicons-bug.svg"
|
||||
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs8" />
|
||||
<sodipodi:namedview
|
||||
id="namedview6"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
showgrid="false"
|
||||
inkscape:zoom="0.85253906"
|
||||
inkscape:cx="367.1386"
|
||||
inkscape:cy="432.23826"
|
||||
inkscape:window-width="3828"
|
||||
inkscape:window-height="2081"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="46"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg4" />
|
||||
<path
|
||||
d="m 243.6206,76.877783 c -52.874,56.780997 -38.281,147.468997 -38.281,147.468997 0,0 53.968,64 160,64 106.031,0 160.031,-64 160.031,-64 0,0 14.375,-89.469 -37.375,-146.311997 32.375,-18.031 51.438,-44.094 43.562,-61.812 -8.938,-19.9689999 -48.375,-21.7499999 -88.25,-3.969 -14.812,6.594 -27.438,14.969 -37.25,23.875 -12.438,-2.25 -25.625,-3.781 -40.72,-3.781 -14.061,0 -26.561,1.344 -38.344,3.25 -9.656,-8.75 -22.062,-16.875 -36.531,-23.344 -39.875,-17.7189999 -79.375,-15.9379999 -88.25,3.969 -7.748,17.343 10.284,42.686 41.408,60.655 z m 401.125,413.218997 c -8.25,-1.75 -16.125,-2.75 -23.75,-3.5 0,-2.125 0.375,-4.125 0.375,-6.312 0,-33.594 -4.75,-65.654 -12.438,-96.125 16.438,1.406 37.375,-2.375 58.562,-11.779 39.875,-17.781 65,-48.375 56.125,-68.219 -8.875,-19.969 -48.375,-21.75 -88.25,-3.969 -18.625,8.312 -33.812,19.469 -44,30.906 -7.75,-18.25 -16.5,-35.781 -26.812,-51.719 -30.188,25.156 -87.312,62.719 -167.062,71.062 v 321.781 c 0,0 -0.25,32 -32.031,32 -31.75,0 -32,-32 -32,-32 v -321.657 c -79.811,-8.344 -136.968,-45.969 -167.093,-71.062 -9.875,15.312 -18.375,32 -25.938,49.344 -10.281,-10.625 -24.625,-20.844 -41.969,-28.594 -39.875,-17.719 -79.375,-15.938 -88.25,3.969 -8.9060001,19.906 16.25,50.438 56.125,68.219 19.844,8.846 39.531,12.812 55.469,12.096 -7.656,30.404 -12.469,62.344 -12.469,95.812 0,2.188 0.375,4.25 0.438,6.5 -6.719,0.75 -13.688,1.75 -20.781,3.25 -51.969,10.75 -91.7810001,37.625 -88.84400014,59.812 2.93800004,22.312 47.50000014,31.5 99.59400014,20.688 6.781,-1.375 13.438,-3.125 19.781,-5.062 9.156,40.809 23.812,78.684 44.094,111.309 -12.031,6.062 -24.531,15 -36.031,26.625 -31.876,31.875 -44.812,70.625 -28.876,86.563 15.938,15.937 54.656,3 86.531,-28.812 9.344,-9.375 16.844,-19.25 22.656,-29 43.532,42.624 98.063,68.124 157.563,68.124 60.343,0 115.781,-26.25 159.531,-69.938 5.875,10.312 13.75,20.812 23.625,30.688 31.812,31.875 70.625,44.812 86.562,28.875 15.937,-15.937 3,-54.625 -28.875,-86.5 -12.312,-12.375 -25.688,-21.75 -38.438,-27.938 20.125,-32.5 34.625,-70.375 43.688,-111.062 7.188,2.25 14.688,4.375 22.562,6.062 52.061,10.812 96.625,1.562 99.625,-20.688 2.813,-22.124 -36.999,-48.999 -88.999,-59.749 z"
|
||||
id="path2" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.1 KiB |
39
docs/TODO.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# TODOs and Remarks
|
||||
|
||||
## Now
|
||||
|
||||
* ghcup init?
|
||||
* merge two download files
|
||||
* fetch/unpack functionality
|
||||
* installing multiple versions of the same
|
||||
* post-install
|
||||
|
||||
* proper test suite
|
||||
|
||||
* !! update of 0.1.5 must go in ghcup-0.0.1.json !!
|
||||
|
||||
* try to run exe before upgrade (backup to ~/.ghcup/bin/ghcup.old)
|
||||
* stdout flushing?
|
||||
* resume support (for make-install only)
|
||||
|
||||
## Maybe
|
||||
|
||||
* version ranges in json
|
||||
* sign the JSON? (Or check gpg keys?)
|
||||
* testing (especially distro detection -> unit tests)
|
||||
|
||||
## Later
|
||||
|
||||
* add support for RC/alpha/HEAD versions
|
||||
|
||||
## Cleanups
|
||||
|
||||
* avoid alternative for IO
|
||||
* use plucky or oops instead of Excepts
|
||||
|
||||
## Questions
|
||||
|
||||
* move out GHCup.Version module, bc it's not library-ish?
|
||||
* mirror support
|
||||
* interactive handling when distro doesn't exist and we know the tarball is incompatible?
|
||||
* ghcup-with wrapper to execute a command with a given ghc in PATH?
|
||||
222
docs/about.md
Normal file
@@ -0,0 +1,222 @@
|
||||
# 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
|
||||
|
||||
## How to help
|
||||
|
||||
* if you want to contribute code or documentation, check out the [issue tracker](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues) and the [Development guide](./dev.md)
|
||||
* if you want to propose features or write user feedback, feel free to [open a ticket](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/new?issue)
|
||||
* if you want to donate to the project, visit our [opencollective](https://opencollective.com/ghcup#category-CONTRIBUTE) page
|
||||
|
||||
## 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.
|
||||
330
docs/css/extra.css
Normal file
@@ -0,0 +1,330 @@
|
||||
:root {
|
||||
--theme-purple: #5E5184;
|
||||
--link-pink: #9E358F;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
.index-ghcup-hero {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.index-ghcup-hero img {
|
||||
width: 10%;
|
||||
min-width: 110px;
|
||||
max-width: 120px;
|
||||
border: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.index-ghcup-hero h1 {
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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: none;
|
||||
background-color: var(--theme-purple) !important;
|
||||
}
|
||||
|
||||
body .bg-primary {
|
||||
background-image: none;
|
||||
background-color: var(--theme-purple);
|
||||
border: 0px;
|
||||
}
|
||||
|
||||
body .btn-primary {
|
||||
background-image: none;
|
||||
background-color: var(--theme-purple);
|
||||
border: 1px solid var(--theme-purple);
|
||||
}
|
||||
|
||||
.navbar.fixed-top {
|
||||
background-image: none;
|
||||
background-color: var(--theme-purple);
|
||||
border-bottom: 5px solid rgba(69, 59, 97, 0.5);
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background-color: var(--theme-purple);
|
||||
border: 1px solid var(--theme-purple);
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--link-pink);
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #996FC2;
|
||||
}
|
||||
|
||||
.col-md-9 img.main-logo {
|
||||
border: 0px;
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
.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;
|
||||
box-sizing: border-box;
|
||||
padding: 0.75rem;
|
||||
background-color: rgb(250, 250, 250);
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 2rem;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
border-radius: 3px;
|
||||
border: 1px solid rgb(204, 204, 204);
|
||||
box-shadow:
|
||||
4px 8px 10px -6px rgb(204, 204, 204),
|
||||
4px 8px 10px -6px rgb(153, 111, 194);
|
||||
}
|
||||
|
||||
@media only screen and (max-width:1000px) {
|
||||
.qi-container {
|
||||
box-shadow:
|
||||
4px 10px 10px -6px rgb(204, 204, 204),
|
||||
4px 10px 10px -9px rgb(153, 111, 194);
|
||||
}
|
||||
}
|
||||
|
||||
.index-cta-donate .donate-button a {
|
||||
position: absolute;
|
||||
top:0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.index-cta-donate .donate-button {
|
||||
margin: 10px auto;
|
||||
position: relative;
|
||||
display: block;
|
||||
background: none;
|
||||
padding: none;
|
||||
border: none;
|
||||
background: url("https://opencollective.com/webpack/donate/button@2x.png?color=blue");
|
||||
width: 35%;
|
||||
min-width: 240px;
|
||||
max-width: 280px;
|
||||
height: 40px;
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
|
||||
.footer {
|
||||
color: grey;
|
||||
font-size: 0.7em;
|
||||
margin-top: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.footer div.show-all-platforms {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#help, #collective {
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#help img {
|
||||
border: none;
|
||||
margin: 0px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.ghcup-help {
|
||||
margin: 10px auto;
|
||||
padding: 10px 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
#collective img {
|
||||
border: none;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
#collective {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
115
docs/dev.md
Normal file
@@ -0,0 +1,115 @@
|
||||
# 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
|
||||
|
||||
Head over to: [https://github.com/haskell/ghcup-metadata#adding-a-new-ghc-version](https://github.com/haskell/ghcup-metadata#adding-a-new-ghc-version)
|
||||
|
||||
### 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](https://gitlab.haskell.org/haskell/ghcup-hs/-/commit/c19dd5ee8b2edbaf0336af143f1c75b6f4843e26)
|
||||
|
||||
Every subcommand now lives in its own module under [GHCup.OptParse.MyCommand](https://gitlab.haskell.org/haskell/ghcup-hs/-/tree/master/app/ghcup/GHCup/OptParse).
|
||||
|
||||
## 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.
|
||||
3. This refactor split up the huge `Main.hs` and put every subcommand in its own module: [#212](https://gitlab.haskell.org/haskell/ghcup-hs/-/merge_requests/212)
|
||||
|
||||
# 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. Commit and git push with tag. Wait for tests to succeed and release artifacts to build.
|
||||
|
||||
5. Download release artifacts and upload them `downloads.haskell.org/~ghcup` along with checksum files (`sha256sum --tag * > SHA256SUMS && gpg --detach-sign -u <your-email> SHA256SUMS`)
|
||||
|
||||
6. Add ghcup release artifacts to ALL yaml files, see [ghcup-metadata repo](https://github.com/haskell/ghcup-metadata)
|
||||
|
||||
7. Upload the final `ghcup-<ver>.yaml` (and a detached GPG sig of it) to `webhost.haskell.org/ghcup/data/` (for yaml versions <= 0.0.6) as well as [https://github.com/haskell/ghcup-metadata](https://github.com/haskell/ghcup-metadata) (for all versions).
|
||||
|
||||
8. Upload `bootstrap-haskell` and `bootstrap-haskell.ps1` to `webhost.haskell.org/ghcup/sh/`
|
||||
|
||||
9. Update the top-level ghcup symlinks at `downloads.haskell.org/~ghcup`
|
||||
|
||||
10. 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 |
326
docs/guide.md
Normal file
@@ -0,0 +1,326 @@
|
||||
# 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.
|
||||
|
||||
## 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).
|
||||
|
||||
## Caching
|
||||
|
||||
GHCup has a few caching mechanisms to avoid redownloads. All cached files end up in `~/.ghcup/cache` by default.
|
||||
|
||||
### Downloads cache
|
||||
|
||||
Downloaded tarballs (such as GHC, cabal, etc.) are not cached by default unless you pass `ghcup --cache` or set caching
|
||||
in your [config](#configuration) via `ghcup config set cache true`.
|
||||
|
||||
### Metadata cache
|
||||
|
||||
The metadata files (also see [github.com/haskell/ghcup-metadata](https://github.com/haskell/ghcup-metadata))
|
||||
have a 5 minutes cache per default depending on the last access time of the file. That means if you run
|
||||
`ghcup list` 10 times in a row, only the first time will trigger a download attempt.
|
||||
|
||||
### Clearing the cache
|
||||
|
||||
If you experience problems, consider clearing the cache via `ghcup gc --cache`.
|
||||
|
||||
## 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/](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
|
||||
```
|
||||
|
||||
## 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>`.
|
||||
|
||||
## 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 |
99
docs/index.md
Normal file
@@ -0,0 +1,99 @@
|
||||
---
|
||||
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>
|
||||
|
||||
|
||||
<section class="index-ghcup-hero">
|
||||
<img alt="haskell logo" src="./haskell_logo.png" />
|
||||
<h1>GHCup</h1>
|
||||
</section>
|
||||
|
||||
<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 main-buttons">
|
||||
<a href="install/" class="btn btn-primary" role="button">Getting Started</a>
|
||||
<a href="guide/" class="btn btn-primary" role="button">User Guide</a>
|
||||
</div>
|
||||
|
||||
<section class="qi-container">
|
||||
|
||||
<div class="ghcup-os-container" id="ghcup-instructions-unix">
|
||||
<h3>To install on 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 class="footer">
|
||||
<a href="https://gitlab.haskell.org/haskell/ghcup-hs/-/blob/master/scripts/bootstrap/bootstrap-haskell" target="_blank">What does this do?</a> <b> · </b> <a href="https://www.haskell.org/ghcup/install/#manual-install">I don't like curl | sh</a> <div class="show-all-platforms"><b> · </b> <a class="show-all-platforms-button" href="#">Show all platforms</a></div></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ghcup-os-container" id="ghcup-instructions-win">
|
||||
<h3>To install on 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 class="footer">
|
||||
<a href="https://gitlab.haskell.org/haskell/ghcup-hs/-/blob/master/scripts/bootstrap/bootstrap-haskell.ps1" target="_blank">What does this do?</a> <b> · </b> <a href="https://www.haskell.org/ghcup/install/#manual-install">I don't like curl | sh</a> <div class="show-all-platforms"><b> · </b> <a class="show-all-platforms-button" href="#">Show all platforms</a></div></p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<p id="help" class="ghcup-help">
|
||||
Need help? Ask on
|
||||
<span>
|
||||
<a href="https://kiwiirc.com/nextclient/irc.libera.chat/?nick=Guest%7C?#haskell,#haskell-ghcup">
|
||||
<img src="irc.svg" alt="" />
|
||||
IRC
|
||||
</a>
|
||||
</span>,
|
||||
<span>
|
||||
<a href="https://discord.gg/pKYf3zDQU7">
|
||||
<img src="Discord-Logo-Black.svg" alt="" />
|
||||
Discord
|
||||
</a>
|
||||
</span>,
|
||||
<span>
|
||||
<a href="https://app.element.io/#/room/#haskell-tooling:matrix.org">
|
||||
<img src="Matrix_logo.svg" alt=""/>
|
||||
</a>
|
||||
</span>
|
||||
or
|
||||
<span>
|
||||
<a href="https://gitlab.haskell.org/haskell/ghcup-hs/issues">
|
||||
report a bug
|
||||
<img src="Octicons-bug.svg" alt="" />
|
||||
</a>
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<script type="text/javascript" src="javascripts/ghcup.js"></script>
|
||||
|
||||
|
||||
----
|
||||
|
||||
|
||||
{: .center style="width:700px"}
|
||||
|
||||
<section class="index-cta-donate">
|
||||
<button class="donate-button">
|
||||
<a href="https://opencollective.com/ghcup#category-CONTRIBUTE" class="donate-badge" />
|
||||
</a>
|
||||
</button>
|
||||
</section>
|
||||
122
docs/install.md
Normal file
@@ -0,0 +1,122 @@
|
||||
# Getting started
|
||||
|
||||
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).
|
||||
|
||||
## 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
|
||||
```
|
||||
|
||||
If you want to know what these scripts do, check out the [source code at the repository](https://gitlab.haskell.org/haskell/ghcup-hs/-/tree/master/scripts/bootstrap). Advanced users may want to perform a [manual installation](#manual-install) and GPG verify the binaries.
|
||||
|
||||
## First steps
|
||||
|
||||
1. To get started with creating a Haskell project, follow the [Getting Started with Haskell and Cabal](https://cabal.readthedocs.io/en/latest/getting-started.html) guide
|
||||
2. To properly learn Haskell, run through the [CIS 194 Haskell course](https://www.cis.upenn.edu/~cis194/spring13/) including exercises
|
||||
3. To learn more about Haskell Toolchain management, check out the [ghcup user guide](./guide.md)
|
||||
|
||||
## Uninstallation
|
||||
|
||||
On linux, just run `ghcup nuke`, then make sure any ghcup added lines in your `~/.bashrc` (or similar) are removed.
|
||||
|
||||
On windows, double-click on the `Uninstall Haskell.ps1` PowerShell script on your Desktop.
|
||||
|
||||
## 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/140)
|
||||
* [https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/197](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).
|
||||
|
||||
## Get help
|
||||
|
||||
* [Libera IRC chat on #haskell-ghcup or #haskell](https://kiwiirc.com/nextclient/irc.libera.chat/?nick=Guest%7C?#haskell,#haskell-ghcup)
|
||||
* [GHCup issue tracker](https://gitlab.haskell.org/haskell/ghcup-hs/issues)
|
||||
* [Matrix](https://app.element.io/#/room/#haskell-tooling:matrix.org)
|
||||
* [Discord](https://discord.gg/pKYf3zDQU7)
|
||||
|
||||
38
docs/irc.svg
Normal file
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
height="18.043058"
|
||||
viewBox="0 0 18 18.043058"
|
||||
width="18"
|
||||
version="1.1"
|
||||
id="svg4"
|
||||
sodipodi:docname="irc.svg"
|
||||
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs8" />
|
||||
<sodipodi:namedview
|
||||
id="namedview6"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
showgrid="false"
|
||||
inkscape:zoom="36.375"
|
||||
inkscape:cx="3.3814433"
|
||||
inkscape:cy="9.0309278"
|
||||
inkscape:window-width="3828"
|
||||
inkscape:window-height="2081"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="46"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg4" />
|
||||
<path
|
||||
class="heroicon-ui"
|
||||
d="m 8.03,5.0375961 h 3.94 l 1.06,-4.23999995 a 1,1 0 1 1 1.94,0.47999995 l -0.94,3.76 H 17 a 1,1 0 0 1 0,2 h -3.47 l -1,3.9999999 H 15 a 1,1 0 1 1 0,2 h -2.97 l -1.06,4.25 a 1.0004624,1.0004624 0 1 1 -1.94,-0.49 l 0.94,-3.76 H 6.03 l -1.06,4.25 a 1.0004624,1.0004624 0 1 1 -1.94,-0.49 l 0.94,-3.76 H 1 a 1,1 0 0 1 0,-2 h 3.47 l 1,-3.9999999 H 3 a 1,1 0 0 1 0,-2 H 5.97 L 7.03,0.79759615 A 1,1 0 1 1 8.97,1.2775961 Z m -0.5,2 -1,3.9999999 h 3.94 l 1,-3.9999999 z"
|
||||
id="path2" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
119
docs/javascripts/extra.js
Normal file
@@ -0,0 +1,119 @@
|
||||
var platforms = ["win", "unix"];
|
||||
var platform_override = null;
|
||||
|
||||
function detect_platform() {
|
||||
"use strict";
|
||||
|
||||
if (platform_override !== null) {
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
var os = "unknown";
|
||||
|
||||
if (navigator.platform == "Linux x86_64") {os = "unix";}
|
||||
if (navigator.platform == "Linux i686") {os = "unix";}
|
||||
if (navigator.platform == "Linux i686 on x86_64") {os = "unix";}
|
||||
if (navigator.platform == "Linux aarch64") {os = "unix";}
|
||||
if (navigator.platform == "Linux armv6l") {os = "unix";}
|
||||
if (navigator.platform == "Linux armv7l") {os = "unix";}
|
||||
if (navigator.platform == "Linux armv8l") {os = "unix";}
|
||||
if (navigator.platform == "Linux ppc64") {os = "unix";}
|
||||
if (navigator.platform == "Linux mips") {os = "unix";}
|
||||
if (navigator.platform == "Linux mips64") {os = "unix";}
|
||||
if (navigator.platform == "Mac") {os = "unix";}
|
||||
if (navigator.platform == "Win32") {os = "win";}
|
||||
if (navigator.platform == "Win64" ||
|
||||
navigator.userAgent.indexOf("WOW64") != -1 ||
|
||||
navigator.userAgent.indexOf("Win64") != -1) {os = "win";}
|
||||
if (navigator.platform == "FreeBSD x86_64") {os = "unix";}
|
||||
if (navigator.platform == "FreeBSD amd64") {os = "unix";}
|
||||
// if (navigator.platform == "NetBSD x86_64") {os = "unix";}
|
||||
// if (navigator.platform == "NetBSD amd64") {os = "unix";}
|
||||
|
||||
// I wish I knew by now, but I don't. Try harder.
|
||||
if (os == "unknown") {
|
||||
if (navigator.appVersion.indexOf("Win")!=-1) {os = "win";}
|
||||
if (navigator.appVersion.indexOf("Mac")!=-1) {os = "unix";}
|
||||
if (navigator.appVersion.indexOf("FreeBSD")!=-1) {os = "unix";}
|
||||
}
|
||||
|
||||
// Firefox Quantum likes to hide platform and appVersion but oscpu works
|
||||
if (navigator.oscpu) {
|
||||
if (navigator.oscpu.indexOf("Win32")!=-1) {os = "win";}
|
||||
if (navigator.oscpu.indexOf("Win64")!=-1) {os = "win";}
|
||||
if (navigator.oscpu.indexOf("Mac")!=-1) {os = "unix";}
|
||||
if (navigator.oscpu.indexOf("Linux")!=-1) {os = "unix";}
|
||||
if (navigator.oscpu.indexOf("FreeBSD")!=-1) {os = "unix";}
|
||||
// if (navigator.oscpu.indexOf("NetBSD")!=-1) {os = "unix";}
|
||||
}
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
function adjust_for_platform() {
|
||||
"use strict";
|
||||
|
||||
var platform = detect_platform();
|
||||
|
||||
if (platforms.includes(platform)) {
|
||||
platforms.forEach(function (platform_elem) {
|
||||
var platform_div = document.getElementById("ghcup-instructions-" + platform_elem);
|
||||
platform_div.style.display = "none";
|
||||
if (platform == platform_elem) {
|
||||
platform_div.style.display = "block";
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function show_all_platforms() {
|
||||
platforms.forEach(function (platform_elem) {
|
||||
var platform_div = document.getElementById("ghcup-instructions-" + platform_elem);
|
||||
platform_div.style.display = "block";
|
||||
});
|
||||
|
||||
var buttons = document.getElementsByClassName("show-all-platforms");
|
||||
console.log(buttons);
|
||||
Array.from(buttons).forEach(function (button) {
|
||||
button.style.display = "none";
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function set_up_default_platform_buttons() {
|
||||
var defaults_buttons = document.getElementsByClassName('show-all-platforms-button');
|
||||
for (var i = 0; i < defaults_buttons.length; i++) {
|
||||
defaults_buttons[i].onclick = show_all_platforms;
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
(function () {
|
||||
adjust_for_platform();
|
||||
set_up_default_platform_buttons();
|
||||
}());
|
||||
|
||||
641
docs/modules_small.svg
Normal file
@@ -0,0 +1,641 @@
|
||||
<?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="720pt" height="648pt"
|
||||
viewBox="0.00 0.00 719.60 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.45 0.45) rotate(0) translate(4 1421.5)">
|
||||
<title>G</title>
|
||||
<polygon fill="white" stroke="transparent" points="-4,4 -4,-1421.5 1579,-1421.5 1579,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,-12.99 8,-1346.06 1567,-1346.06 1567,-12.99 8,-12.99"/>
|
||||
<text text-anchor="middle" x="787.5" y="-1330.86" 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="1102,-529.33 1102,-823.22 1362,-823.22 1362,-529.33 1102,-529.33"/>
|
||||
<text text-anchor="middle" x="1232" y="-808.02" 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="16,-940.13 16,-1295.72 1559,-1295.72 1559,-940.13 16,-940.13"/>
|
||||
<text text-anchor="middle" x="787.5" y="-1280.52" font-family="Times-Roman" font-size="14.00">OptParse</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="1196,-277.65 1196,-516.34 1377,-516.34 1377,-277.65 1196,-277.65"/>
|
||||
<text text-anchor="middle" x="1286.5" y="-501.14" font-family="Times-Roman" font-size="14.00">Types</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="586,-25.98 586,-701.44 1082,-701.44 1082,-25.98 586,-25.98"/>
|
||||
<text text-anchor="middle" x="834" y="-686.24" font-family="Times-Roman" font-size="14.00">Utils</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="744,-394.56 744,-651.11 862,-651.11 862,-394.56 744,-394.56"/>
|
||||
<text text-anchor="middle" x="803" y="-635.91" font-family="Times-Roman" font-size="14.00">File</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="995,-38.97 995,-160.75 1065,-160.75 1065,-38.97 995,-38.97"/>
|
||||
<text text-anchor="middle" x="1030" y="-145.55" font-family="Times-Roman" font-size="14.00">String</text>
|
||||
</g>
|
||||
<g id="clust8" class="cluster">
|
||||
<title>cluster_7</title>
|
||||
<polygon fill="#000000" fill-opacity="0.058824" stroke="#000000" stroke-opacity="0.058824" points="594,-529.33 594,-651.11 664,-651.11 664,-529.33 594,-529.33"/>
|
||||
<text text-anchor="middle" x="629" y="-635.91" 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="1165" cy="-743.99" rx="55.49" ry="18"/>
|
||||
<text text-anchor="middle" x="1165" y="-740.29" font-family="Times-Roman" font-size="14.00">Download</text>
|
||||
</g>
|
||||
<!-- u12 -->
|
||||
<g id="node24" class="node">
|
||||
<title>u12</title>
|
||||
<ellipse fill="#ffbbff" stroke="black" stroke-width="2" cx="825" cy="-571.99" rx="27" ry="18"/>
|
||||
<text text-anchor="middle" x="825" y="-568.29" font-family="Times-Roman" font-size="14.00">File</text>
|
||||
</g>
|
||||
<!-- u1->u12 -->
|
||||
<g id="edge13" class="edge">
|
||||
<title>u1->u12</title>
|
||||
<path fill="none" stroke="black" d="M1125,-731.45C1042,-707.49 858.55,-654.33 856,-651.99 841.25,-638.47 833.42,-617.06 829.33,-599.94"/>
|
||||
<polygon fill="black" stroke="black" points="832.71,-599.01 827.23,-589.94 825.86,-600.45 832.71,-599.01"/>
|
||||
</g>
|
||||
<!-- u11 -->
|
||||
<g id="node32" class="node">
|
||||
<title>u11</title>
|
||||
<ellipse fill="#ffbbff" stroke="black" stroke-width="0" cx="1045" cy="-571.99" rx="28.7" ry="18"/>
|
||||
<text text-anchor="middle" x="1045" y="-568.29" font-family="Times-Roman" font-size="14.00">Dirs</text>
|
||||
</g>
|
||||
<!-- u1->u11 -->
|
||||
<g id="edge12" class="edge">
|
||||
<title>u1->u11</title>
|
||||
<path fill="none" stroke="black" d="M1152.43,-726.38C1138.8,-708.25 1116.51,-678.31 1098,-651.99 1085.29,-633.92 1071.4,-613.17 1061.02,-597.47"/>
|
||||
<polygon fill="black" stroke="black" points="1063.78,-595.29 1055.36,-588.87 1057.94,-599.14 1063.78,-595.29"/>
|
||||
</g>
|
||||
<!-- u13 -->
|
||||
<g id="node35" class="node">
|
||||
<title>u13</title>
|
||||
<ellipse fill="#ffffbb" stroke="black" stroke-width="0" cx="1414" cy="-571.99" rx="44.39" ry="18"/>
|
||||
<text text-anchor="middle" x="1414" y="-568.29" font-family="Times-Roman" font-size="14.00">Version</text>
|
||||
</g>
|
||||
<!-- u1->u13 -->
|
||||
<g id="edge11" class="edge">
|
||||
<title>u1->u13</title>
|
||||
<path fill="none" stroke="black" d="M1206.8,-732.08C1250.56,-718.96 1319.26,-693.39 1366,-651.99 1382.37,-637.49 1394.91,-616.04 1403.06,-599.16"/>
|
||||
<polygon fill="black" stroke="black" points="1406.35,-600.37 1407.35,-589.82 1399.99,-597.45 1406.35,-600.37"/>
|
||||
</g>
|
||||
<!-- u17 -->
|
||||
<g id="node2" class="node">
|
||||
<title>u17</title>
|
||||
<ellipse fill="#bbbbff" stroke="black" stroke-width="0" cx="1267" cy="-571.99" rx="30.59" ry="18"/>
|
||||
<text text-anchor="middle" x="1267" y="-568.29" font-family="Times-Roman" font-size="14.00">Utils</text>
|
||||
</g>
|
||||
<!-- u5 -->
|
||||
<g id="node23" class="node">
|
||||
<title>u5</title>
|
||||
<ellipse fill="#bbffff" stroke="black" stroke-width="0" cx="1238" cy="-436.99" rx="33.6" ry="18"/>
|
||||
<text text-anchor="middle" x="1238" y="-433.29" font-family="Times-Roman" font-size="14.00">JSON</text>
|
||||
</g>
|
||||
<!-- u17->u5 -->
|
||||
<g id="edge14" class="edge">
|
||||
<title>u17->u5</title>
|
||||
<path fill="none" stroke="black" d="M1263.27,-553.87C1258.35,-531.33 1249.65,-491.44 1243.86,-464.85"/>
|
||||
<polygon fill="black" stroke="black" points="1247.27,-464.06 1241.72,-455.04 1240.43,-465.56 1247.27,-464.06"/>
|
||||
</g>
|
||||
<!-- u19 -->
|
||||
<g id="node3" class="node">
|
||||
<title>u19</title>
|
||||
<ellipse fill="#bbbbff" stroke="black" stroke-width="0" cx="1296" cy="-743.99" rx="57.69" ry="18"/>
|
||||
<text text-anchor="middle" x="1296" y="-740.29" font-family="Times-Roman" font-size="14.00">IOStreams</text>
|
||||
</g>
|
||||
<!-- u19->u17 -->
|
||||
<g id="edge15" class="edge">
|
||||
<title>u19->u17</title>
|
||||
<path fill="none" stroke="black" d="M1293.06,-725.75C1288.01,-696.15 1277.65,-635.42 1271.63,-600.1"/>
|
||||
<polygon fill="black" stroke="black" points="1275.04,-599.29 1269.9,-590.02 1268.14,-600.46 1275.04,-599.29"/>
|
||||
</g>
|
||||
<!-- u21 -->
|
||||
<g id="node4" class="node">
|
||||
<title>u21</title>
|
||||
<ellipse fill="#ffffbb" stroke="black" stroke-width="2" cx="742" cy="-1215.99" rx="51.99" ry="18"/>
|
||||
<text text-anchor="middle" x="742" y="-1212.29" font-family="Times-Roman" font-size="14.00">OptParse</text>
|
||||
</g>
|
||||
<!-- u23 -->
|
||||
<g id="node6" class="node">
|
||||
<title>u23</title>
|
||||
<ellipse fill="#ffbbbb" stroke="black" stroke-width="0" cx="846" cy="-1098.99" rx="38.19" ry="18"/>
|
||||
<text text-anchor="middle" x="846" y="-1095.29" font-family="Times-Roman" font-size="14.00">Install</text>
|
||||
</g>
|
||||
<!-- u21->u23 -->
|
||||
<g id="edge16" class="edge">
|
||||
<title>u21->u23</title>
|
||||
<path fill="none" stroke="black" d="M756.9,-1198.51C774.61,-1178.93 804.29,-1146.11 824.49,-1123.77"/>
|
||||
<polygon fill="black" stroke="black" points="827.35,-1125.83 831.46,-1116.07 822.16,-1121.13 827.35,-1125.83"/>
|
||||
</g>
|
||||
<!-- u24 -->
|
||||
<g id="node7" class="node">
|
||||
<title>u24</title>
|
||||
<ellipse fill="#ffbbbb" stroke="black" stroke-width="0" cx="929" cy="-1098.99" rx="27" ry="18"/>
|
||||
<text text-anchor="middle" x="929" y="-1095.29" font-family="Times-Roman" font-size="14.00">Set</text>
|
||||
</g>
|
||||
<!-- u21->u24 -->
|
||||
<g id="edge17" class="edge">
|
||||
<title>u21->u24</title>
|
||||
<path fill="none" stroke="black" d="M766.45,-1199.96C801.13,-1178.63 864.45,-1139.69 900.98,-1117.22"/>
|
||||
<polygon fill="black" stroke="black" points="902.97,-1120.1 909.66,-1111.88 899.31,-1114.14 902.97,-1120.1"/>
|
||||
</g>
|
||||
<!-- u25 -->
|
||||
<g id="node8" class="node">
|
||||
<title>u25</title>
|
||||
<ellipse fill="#ffbbbb" stroke="black" stroke-width="0" cx="1197" cy="-1098.99" rx="38.19" ry="18"/>
|
||||
<text text-anchor="middle" x="1197" y="-1095.29" font-family="Times-Roman" font-size="14.00">UnSet</text>
|
||||
</g>
|
||||
<!-- u21->u25 -->
|
||||
<g id="edge18" class="edge">
|
||||
<title>u21->u25</title>
|
||||
<path fill="none" stroke="black" d="M785.46,-1206.08C860.33,-1190.39 1018.18,-1155.79 1149,-1116.99 1152.09,-1116.07 1155.28,-1115.07 1158.47,-1114.03"/>
|
||||
<polygon fill="black" stroke="black" points="1159.62,-1117.34 1167.97,-1110.82 1157.37,-1110.7 1159.62,-1117.34"/>
|
||||
</g>
|
||||
<!-- u26 -->
|
||||
<g id="node9" class="node">
|
||||
<title>u26</title>
|
||||
<ellipse fill="#ffbbbb" stroke="black" stroke-width="0" cx="1001" cy="-1098.99" rx="27" ry="18"/>
|
||||
<text text-anchor="middle" x="1001" y="-1095.29" font-family="Times-Roman" font-size="14.00">Rm</text>
|
||||
</g>
|
||||
<!-- u21->u26 -->
|
||||
<g id="edge19" class="edge">
|
||||
<title>u21->u26</title>
|
||||
<path fill="none" stroke="black" d="M773.51,-1201.46C816.81,-1182.8 897.08,-1147.94 965,-1116.99 966.79,-1116.17 968.63,-1115.33 970.49,-1114.47"/>
|
||||
<polygon fill="black" stroke="black" points="972.15,-1117.56 979.72,-1110.15 969.18,-1111.21 972.15,-1117.56"/>
|
||||
</g>
|
||||
<!-- u27 -->
|
||||
<g id="node10" class="node">
|
||||
<title>u27</title>
|
||||
<ellipse fill="#ffbbbb" stroke="black" stroke-width="0" cx="1093" cy="-1098.99" rx="47.39" ry="18"/>
|
||||
<text text-anchor="middle" x="1093" y="-1095.29" font-family="Times-Roman" font-size="14.00">Compile</text>
|
||||
</g>
|
||||
<!-- u21->u27 -->
|
||||
<g id="edge20" class="edge">
|
||||
<title>u21->u27</title>
|
||||
<path fill="none" stroke="black" d="M778.57,-1203.01C843.42,-1181.76 978.33,-1137.56 1048.47,-1114.58"/>
|
||||
<polygon fill="black" stroke="black" points="1049.92,-1117.79 1058.34,-1111.35 1047.74,-1111.13 1049.92,-1117.79"/>
|
||||
</g>
|
||||
<!-- u28 -->
|
||||
<g id="node11" class="node">
|
||||
<title>u28</title>
|
||||
<ellipse fill="#ffbbbb" stroke="black" stroke-width="0" cx="64" cy="-1098.99" rx="40.09" ry="18"/>
|
||||
<text text-anchor="middle" x="64" y="-1095.29" font-family="Times-Roman" font-size="14.00">Config</text>
|
||||
</g>
|
||||
<!-- u21->u28 -->
|
||||
<g id="edge21" class="edge">
|
||||
<title>u21->u28</title>
|
||||
<path fill="none" stroke="black" d="M692.47,-1210.33C585.48,-1199.59 325.33,-1169.91 113,-1116.99 109.85,-1116.21 106.62,-1115.31 103.4,-1114.34"/>
|
||||
<polygon fill="black" stroke="black" points="104.39,-1110.98 93.8,-1111.28 102.27,-1117.65 104.39,-1110.98"/>
|
||||
</g>
|
||||
<!-- u29 -->
|
||||
<g id="node12" class="node">
|
||||
<title>u29</title>
|
||||
<ellipse fill="#ffbbbb" stroke="black" stroke-width="0" cx="415" cy="-1098.99" rx="46.59" ry="18"/>
|
||||
<text text-anchor="middle" x="415" y="-1095.29" font-family="Times-Roman" font-size="14.00">Whereis</text>
|
||||
</g>
|
||||
<!-- u21->u29 -->
|
||||
<g id="edge22" class="edge">
|
||||
<title>u21->u29</title>
|
||||
<path fill="none" stroke="black" d="M706.69,-1202.57C646.37,-1181.36 523.67,-1138.21 458.29,-1115.21"/>
|
||||
<polygon fill="black" stroke="black" points="459.28,-1111.85 448.69,-1111.84 456.96,-1118.46 459.28,-1111.85"/>
|
||||
</g>
|
||||
<!-- u30 -->
|
||||
<g id="node13" class="node">
|
||||
<title>u30</title>
|
||||
<ellipse fill="#ffbbbb" stroke="black" stroke-width="0" cx="507" cy="-1098.99" rx="27" ry="18"/>
|
||||
<text text-anchor="middle" x="507" y="-1095.29" font-family="Times-Roman" font-size="14.00">List</text>
|
||||
</g>
|
||||
<!-- u21->u30 -->
|
||||
<g id="edge23" class="edge">
|
||||
<title>u21->u30</title>
|
||||
<path fill="none" stroke="black" d="M713.18,-1200.89C668.44,-1178.99 582.69,-1137.03 537.15,-1114.75"/>
|
||||
<polygon fill="black" stroke="black" points="538.6,-1111.55 528.07,-1110.3 535.52,-1117.84 538.6,-1111.55"/>
|
||||
</g>
|
||||
<!-- u31 -->
|
||||
<g id="node14" class="node">
|
||||
<title>u31</title>
|
||||
<ellipse fill="#ffbbbb" stroke="black" stroke-width="0" cx="1303" cy="-1098.99" rx="50.09" ry="18"/>
|
||||
<text text-anchor="middle" x="1303" y="-1095.29" font-family="Times-Roman" font-size="14.00">Upgrade</text>
|
||||
</g>
|
||||
<!-- u21->u31 -->
|
||||
<g id="edge24" class="edge">
|
||||
<title>u21->u31</title>
|
||||
<path fill="none" stroke="black" d="M787.97,-1207.41C876.68,-1192.47 1077.4,-1157.17 1244,-1116.99 1248.02,-1116.02 1252.18,-1114.95 1256.34,-1113.84"/>
|
||||
<polygon fill="black" stroke="black" points="1257.28,-1117.21 1265.99,-1111.19 1255.42,-1110.46 1257.28,-1117.21"/>
|
||||
</g>
|
||||
<!-- u32 -->
|
||||
<g id="node15" class="node">
|
||||
<title>u32</title>
|
||||
<ellipse fill="#ffbbbb" stroke="black" stroke-width="0" cx="614" cy="-1098.99" rx="61.99" ry="18"/>
|
||||
<text text-anchor="middle" x="614" y="-1095.29" font-family="Times-Roman" font-size="14.00">ChangeLog</text>
|
||||
</g>
|
||||
<!-- u21->u32 -->
|
||||
<g id="edge25" class="edge">
|
||||
<title>u21->u32</title>
|
||||
<path fill="none" stroke="black" d="M724.2,-1199C702.26,-1179.29 664.8,-1145.63 639.73,-1123.11"/>
|
||||
<polygon fill="black" stroke="black" points="641.84,-1120.29 632.06,-1116.21 637.16,-1125.5 641.84,-1120.29"/>
|
||||
</g>
|
||||
<!-- u33 -->
|
||||
<g id="node16" class="node">
|
||||
<title>u33</title>
|
||||
<ellipse fill="#ffbbbb" stroke="black" stroke-width="0" cx="742" cy="-1098.99" rx="48.19" ry="18"/>
|
||||
<text text-anchor="middle" x="742" y="-1095.29" font-family="Times-Roman" font-size="14.00">Prefetch</text>
|
||||
</g>
|
||||
<!-- u21->u33 -->
|
||||
<g id="edge26" class="edge">
|
||||
<title>u21->u33</title>
|
||||
<path fill="none" stroke="black" d="M742,-1197.52C742,-1178.93 742,-1149.23 742,-1127.49"/>
|
||||
<polygon fill="black" stroke="black" points="745.5,-1127.24 742,-1117.24 738.5,-1127.24 745.5,-1127.24"/>
|
||||
</g>
|
||||
<!-- u34 -->
|
||||
<g id="node17" class="node">
|
||||
<title>u34</title>
|
||||
<ellipse fill="#ffbbbb" stroke="black" stroke-width="0" cx="235" cy="-1098.99" rx="27" ry="18"/>
|
||||
<text text-anchor="middle" x="235" y="-1095.29" font-family="Times-Roman" font-size="14.00">GC</text>
|
||||
</g>
|
||||
<!-- u21->u34 -->
|
||||
<g id="edge27" class="edge">
|
||||
<title>u21->u34</title>
|
||||
<path fill="none" stroke="black" d="M694.23,-1208.86C608.04,-1196.96 421.48,-1167.38 271,-1116.99 269.08,-1116.35 267.13,-1115.63 265.19,-1114.86"/>
|
||||
<polygon fill="black" stroke="black" points="266.16,-1111.47 255.6,-1110.73 263.4,-1117.9 266.16,-1111.47"/>
|
||||
</g>
|
||||
<!-- u35 -->
|
||||
<g id="node18" class="node">
|
||||
<title>u35</title>
|
||||
<ellipse fill="#ffbbbb" stroke="black" stroke-width="0" cx="315" cy="-1098.99" rx="35.19" ry="18"/>
|
||||
<text text-anchor="middle" x="315" y="-1095.29" font-family="Times-Roman" font-size="14.00">DInfo</text>
|
||||
</g>
|
||||
<!-- u21->u35 -->
|
||||
<g id="edge28" class="edge">
|
||||
<title>u21->u35</title>
|
||||
<path fill="none" stroke="black" d="M699.03,-1205.74C627.68,-1189.99 480.59,-1155.89 359,-1116.99 356.46,-1116.18 353.84,-1115.29 351.23,-1114.37"/>
|
||||
<polygon fill="black" stroke="black" points="352.41,-1111.08 341.81,-1110.93 350,-1117.65 352.41,-1111.08"/>
|
||||
</g>
|
||||
<!-- u36 -->
|
||||
<g id="node19" class="node">
|
||||
<title>u36</title>
|
||||
<ellipse fill="#ffbbbb" stroke="black" stroke-width="0" cx="1461" cy="-1098.99" rx="90.18" ry="18"/>
|
||||
<text text-anchor="middle" x="1461" y="-1095.29" font-family="Times-Roman" font-size="14.00">ToolRequirements</text>
|
||||
</g>
|
||||
<!-- u21->u36 -->
|
||||
<g id="edge29" class="edge">
|
||||
<title>u21->u36</title>
|
||||
<path fill="none" stroke="black" d="M788.7,-1207.83C892.07,-1191.92 1148.03,-1152.27 1362,-1116.99 1369.56,-1115.74 1377.44,-1114.42 1385.32,-1113.09"/>
|
||||
<polygon fill="black" stroke="black" points="1385.98,-1116.53 1395.25,-1111.41 1384.81,-1109.63 1385.98,-1116.53"/>
|
||||
</g>
|
||||
<!-- u37 -->
|
||||
<g id="node20" class="node">
|
||||
<title>u37</title>
|
||||
<ellipse fill="#ffbbbb" stroke="black" stroke-width="0" cx="156" cy="-1098.99" rx="33.6" ry="18"/>
|
||||
<text text-anchor="middle" x="156" y="-1095.29" font-family="Times-Roman" font-size="14.00">Nuke</text>
|
||||
</g>
|
||||
<!-- u21->u37 -->
|
||||
<g id="edge30" class="edge">
|
||||
<title>u21->u37</title>
|
||||
<path fill="none" stroke="black" d="M693.33,-1209.49C597.41,-1197.93 377.73,-1167.91 199,-1116.99 196.41,-1116.25 193.76,-1115.42 191.12,-1114.52"/>
|
||||
<polygon fill="black" stroke="black" points="192.23,-1111.2 181.64,-1111.08 189.84,-1117.78 192.23,-1111.2"/>
|
||||
</g>
|
||||
<!-- u22 -->
|
||||
<g id="node5" class="node">
|
||||
<title>u22</title>
|
||||
<ellipse fill="#ffbbbb" stroke="black" stroke-width="0" cx="742" cy="-981.99" rx="51.19" ry="18"/>
|
||||
<text text-anchor="middle" x="742" y="-978.29" font-family="Times-Roman" font-size="14.00">Common</text>
|
||||
</g>
|
||||
<!-- u0 -->
|
||||
<g id="node33" class="node">
|
||||
<title>u0</title>
|
||||
<ellipse fill="#bbffbb" stroke="black" stroke-width="2" cx="705" cy="-864.99" rx="42.49" ry="18"/>
|
||||
<text text-anchor="middle" x="705" y="-861.29" font-family="Times-Roman" font-size="14.00">GHCup</text>
|
||||
</g>
|
||||
<!-- u22->u0 -->
|
||||
<g id="edge31" class="edge">
|
||||
<title>u22->u0</title>
|
||||
<path fill="none" stroke="black" d="M736.54,-964.02C730.5,-945.25 720.69,-914.76 713.61,-892.76"/>
|
||||
<polygon fill="black" stroke="black" points="716.88,-891.48 710.48,-883.03 710.21,-893.62 716.88,-891.48"/>
|
||||
</g>
|
||||
<!-- u23->u22 -->
|
||||
<g id="edge32" class="edge">
|
||||
<title>u23->u22</title>
|
||||
<path fill="none" stroke="black" d="M831.54,-1082C813.97,-1062.57 784.14,-1029.59 763.78,-1007.08"/>
|
||||
<polygon fill="black" stroke="black" points="766.31,-1004.66 757.01,-999.59 761.12,-1009.35 766.31,-1004.66"/>
|
||||
</g>
|
||||
<!-- u24->u22 -->
|
||||
<g id="edge33" class="edge">
|
||||
<title>u24->u22</title>
|
||||
<path fill="none" stroke="black" d="M909.69,-1086.12C877.99,-1066.62 814.52,-1027.58 775.4,-1003.53"/>
|
||||
<polygon fill="black" stroke="black" points="776.84,-1000.31 766.49,-998.05 773.18,-1006.27 776.84,-1000.31"/>
|
||||
</g>
|
||||
<!-- u25->u0 -->
|
||||
<g id="edge34" class="edge">
|
||||
<title>u25->u0</title>
|
||||
<path fill="none" stroke="black" d="M1170.9,-1085.68C1088.88,-1047.01 836.24,-927.88 741.44,-883.17"/>
|
||||
<polygon fill="black" stroke="black" points="742.78,-879.94 732.24,-878.84 739.8,-886.27 742.78,-879.94"/>
|
||||
</g>
|
||||
<!-- u26->u22 -->
|
||||
<g id="edge35" class="edge">
|
||||
<title>u26->u22</title>
|
||||
<path fill="none" stroke="black" d="M979.72,-1087.83C974.89,-1085.55 969.78,-1083.17 965,-1080.99 901.54,-1052.07 827.31,-1019.75 782.51,-1000.4"/>
|
||||
<polygon fill="black" stroke="black" points="783.71,-997.11 773.14,-996.36 780.94,-1003.53 783.71,-997.11"/>
|
||||
</g>
|
||||
<!-- u27->u22 -->
|
||||
<g id="edge36" class="edge">
|
||||
<title>u27->u22</title>
|
||||
<path fill="none" stroke="black" d="M1058.38,-1086.65C994.71,-1065.79 859,-1021.32 787.79,-997.99"/>
|
||||
<polygon fill="black" stroke="black" points="788.78,-994.63 778.19,-994.85 786.6,-1001.29 788.78,-994.63"/>
|
||||
</g>
|
||||
<!-- u15 -->
|
||||
<g id="node28" class="node">
|
||||
<title>u15</title>
|
||||
<ellipse fill="#ffffbb" stroke="black" stroke-width="2" cx="705" cy="-571.99" rx="30.59" ry="18"/>
|
||||
<text text-anchor="middle" x="705" y="-568.29" font-family="Times-Roman" font-size="14.00">Utils</text>
|
||||
</g>
|
||||
<!-- u28->u15 -->
|
||||
<g id="edge37" class="edge">
|
||||
<title>u28->u15</title>
|
||||
<path fill="none" stroke="black" d="M67.99,-1080.83C82.87,-1020.89 141.11,-819.44 271,-725.99 416.7,-621.17 526.05,-761.83 668,-651.99 684.52,-639.21 693.98,-617.26 699.19,-599.74"/>
|
||||
<polygon fill="black" stroke="black" points="702.58,-600.61 701.79,-590.04 695.82,-598.8 702.58,-600.61"/>
|
||||
</g>
|
||||
<!-- u29->u22 -->
|
||||
<g id="edge38" class="edge">
|
||||
<title>u29->u22</title>
|
||||
<path fill="none" stroke="black" d="M448.46,-1086.22C507.6,-1065.42 630.64,-1022.15 697.09,-998.78"/>
|
||||
<polygon fill="black" stroke="black" points="698.59,-1001.97 706.86,-995.35 696.27,-995.36 698.59,-1001.97"/>
|
||||
</g>
|
||||
<!-- u30->u22 -->
|
||||
<g id="edge39" class="edge">
|
||||
<title>u30->u22</title>
|
||||
<path fill="none" stroke="black" d="M528.27,-1087.58C568.07,-1068.1 654.29,-1025.91 704.21,-1001.48"/>
|
||||
<polygon fill="black" stroke="black" points="705.94,-1004.53 713.38,-996.99 702.86,-998.25 705.94,-1004.53"/>
|
||||
</g>
|
||||
<!-- u31->u0 -->
|
||||
<g id="edge40" class="edge">
|
||||
<title>u31->u0</title>
|
||||
<path fill="none" stroke="black" d="M1271.29,-1084.99C1209.35,-1059.66 1067.86,-1002.15 948,-955.99 877.11,-928.69 794.01,-898.24 745.65,-880.68"/>
|
||||
<polygon fill="black" stroke="black" points="746.76,-877.36 736.17,-877.24 744.37,-883.94 746.76,-877.36"/>
|
||||
</g>
|
||||
<!-- u32->u22 -->
|
||||
<g id="edge41" class="edge">
|
||||
<title>u32->u22</title>
|
||||
<path fill="none" stroke="black" d="M632.07,-1081.76C654.08,-1061.98 691.42,-1028.44 716.39,-1006"/>
|
||||
<polygon fill="black" stroke="black" points="718.92,-1008.43 724.02,-999.14 714.25,-1003.22 718.92,-1008.43"/>
|
||||
</g>
|
||||
<!-- u33->u22 -->
|
||||
<g id="edge42" class="edge">
|
||||
<title>u33->u22</title>
|
||||
<path fill="none" stroke="black" d="M742,-1080.52C742,-1061.93 742,-1032.23 742,-1010.49"/>
|
||||
<polygon fill="black" stroke="black" points="745.5,-1010.24 742,-1000.24 738.5,-1010.24 745.5,-1010.24"/>
|
||||
</g>
|
||||
<!-- u34->u0 -->
|
||||
<g id="edge43" class="edge">
|
||||
<title>u34->u0</title>
|
||||
<path fill="none" stroke="black" d="M253.73,-1086.02C294.34,-1060.34 393.93,-998.82 482,-955.99 543.91,-925.88 618.59,-897.22 663.9,-880.63"/>
|
||||
<polygon fill="black" stroke="black" points="665.18,-883.89 673.38,-877.18 662.79,-877.31 665.18,-883.89"/>
|
||||
</g>
|
||||
<!-- u35->u0 -->
|
||||
<g id="edge44" class="edge">
|
||||
<title>u35->u0</title>
|
||||
<path fill="none" stroke="black" d="M337.09,-1084.85C402.43,-1045.98 595.06,-931.39 672.36,-885.41"/>
|
||||
<polygon fill="black" stroke="black" points="674.39,-888.27 681.2,-880.15 670.81,-882.25 674.39,-888.27"/>
|
||||
</g>
|
||||
<!-- u14 -->
|
||||
<g id="node36" class="node">
|
||||
<title>u14</title>
|
||||
<ellipse fill="#ffffbb" stroke="black" stroke-width="0" cx="934" cy="-743.99" rx="48.19" ry="18"/>
|
||||
<text text-anchor="middle" x="934" y="-740.29" font-family="Times-Roman" font-size="14.00">Platform</text>
|
||||
</g>
|
||||
<!-- u36->u14 -->
|
||||
<g id="edge45" class="edge">
|
||||
<title>u36->u14</title>
|
||||
<path fill="none" stroke="black" d="M1436.29,-1081.44C1349.76,-1023.48 1060.5,-829.72 964.94,-765.71"/>
|
||||
<polygon fill="black" stroke="black" points="966.82,-762.76 956.56,-760.1 962.93,-768.58 966.82,-762.76"/>
|
||||
</g>
|
||||
<!-- u18 -->
|
||||
<g id="node37" class="node">
|
||||
<title>u18</title>
|
||||
<ellipse fill="#ffffbb" stroke="black" stroke-width="0" cx="1461" cy="-743.99" rx="73.39" ry="18"/>
|
||||
<text text-anchor="middle" x="1461" y="-740.29" font-family="Times-Roman" font-size="14.00">Requirements</text>
|
||||
</g>
|
||||
<!-- u36->u18 -->
|
||||
<g id="edge46" class="edge">
|
||||
<title>u36->u18</title>
|
||||
<path fill="none" stroke="black" d="M1461,-1080.96C1461,-1024.36 1461,-842.13 1461,-772.44"/>
|
||||
<polygon fill="black" stroke="black" points="1464.5,-772.26 1461,-762.26 1457.5,-772.26 1464.5,-772.26"/>
|
||||
</g>
|
||||
<!-- u37->u0 -->
|
||||
<g id="edge47" class="edge">
|
||||
<title>u37->u0</title>
|
||||
<path fill="none" stroke="black" d="M175.44,-1084.01C214.9,-1056.2 307.95,-993.37 394,-955.99 483.86,-916.95 595.52,-889.35 657.64,-875.71"/>
|
||||
<polygon fill="black" stroke="black" points="658.52,-879.1 667.55,-873.56 657.03,-872.26 658.52,-879.1"/>
|
||||
</g>
|
||||
<!-- u3 -->
|
||||
<g id="node21" class="node">
|
||||
<title>u3</title>
|
||||
<ellipse fill="#ffffbb" stroke="black" stroke-width="2" cx="1257" cy="-319.99" rx="36.29" ry="18"/>
|
||||
<text text-anchor="middle" x="1257" y="-316.29" font-family="Times-Roman" font-size="14.00">Types</text>
|
||||
</g>
|
||||
<!-- u4 -->
|
||||
<g id="node22" class="node">
|
||||
<title>u4</title>
|
||||
<ellipse fill="#bbffff" stroke="black" stroke-width="0" cx="1329" cy="-436.99" rx="39.79" ry="18"/>
|
||||
<text text-anchor="middle" x="1329" y="-433.29" font-family="Times-Roman" font-size="14.00">Optics</text>
|
||||
</g>
|
||||
<!-- u4->u3 -->
|
||||
<g id="edge48" class="edge">
|
||||
<title>u4->u3</title>
|
||||
<path fill="none" stroke="black" d="M1318.68,-419.51C1306.65,-400.3 1286.64,-368.33 1272.68,-346.04"/>
|
||||
<polygon fill="black" stroke="black" points="1275.57,-344.05 1267.3,-337.44 1269.64,-347.77 1275.57,-344.05"/>
|
||||
</g>
|
||||
<!-- u6 -->
|
||||
<g id="node29" class="node">
|
||||
<title>u6</title>
|
||||
<ellipse fill="#ffbbff" stroke="black" stroke-width="0" cx="934" cy="-571.99" rx="64.19" ry="18"/>
|
||||
<text text-anchor="middle" x="934" y="-568.29" font-family="Times-Roman" font-size="14.00">MegaParsec</text>
|
||||
</g>
|
||||
<!-- u5->u6 -->
|
||||
<g id="edge49" class="edge">
|
||||
<title>u5->u6</title>
|
||||
<path fill="none" stroke="black" d="M1225.64,-453.75C1216.72,-464.19 1203.86,-477.47 1190,-485.99 1117.08,-530.81 1088.16,-518.79 1007,-545.99 999.06,-548.65 990.64,-551.5 982.45,-554.3"/>
|
||||
<polygon fill="black" stroke="black" points="981.32,-550.99 972.99,-557.53 983.58,-557.61 981.32,-550.99"/>
|
||||
</g>
|
||||
<!-- u7 -->
|
||||
<g id="node30" class="node">
|
||||
<title>u7</title>
|
||||
<ellipse fill="#ffbbff" stroke="black" stroke-width="0" cx="1030" cy="-319.99" rx="44.39" ry="18"/>
|
||||
<text text-anchor="middle" x="1030" y="-316.29" font-family="Times-Roman" font-size="14.00">Prelude</text>
|
||||
</g>
|
||||
<!-- u5->u7 -->
|
||||
<g id="edge50" class="edge">
|
||||
<title>u5->u7</title>
|
||||
<path fill="none" stroke="black" d="M1218.11,-422.39C1212.34,-418.59 1205.98,-414.53 1200,-410.99 1154.95,-384.33 1101.33,-356.57 1066.52,-339.06"/>
|
||||
<polygon fill="black" stroke="black" points="1067.74,-335.75 1057.23,-334.4 1064.6,-342.01 1067.74,-335.75"/>
|
||||
</g>
|
||||
<!-- u9 -->
|
||||
<g id="node25" class="node">
|
||||
<title>u9</title>
|
||||
<ellipse fill="#77ff77" stroke="black" stroke-width="0" cx="803" cy="-436.99" rx="51.19" ry="18"/>
|
||||
<text text-anchor="middle" x="803" y="-433.29" font-family="Times-Roman" font-size="14.00">Common</text>
|
||||
</g>
|
||||
<!-- u12->u9 -->
|
||||
<g id="edge59" class="edge">
|
||||
<title>u12->u9</title>
|
||||
<path fill="none" stroke="black" d="M822.17,-553.87C818.46,-531.43 811.9,-491.79 807.5,-465.2"/>
|
||||
<polygon fill="black" stroke="black" points="810.91,-464.33 805.82,-455.04 804,-465.48 810.91,-464.33"/>
|
||||
</g>
|
||||
<!-- u9->u7 -->
|
||||
<g id="edge60" class="edge">
|
||||
<title>u9->u7</title>
|
||||
<path fill="none" stroke="black" d="M831.29,-421.66C872.57,-400.75 949.27,-361.89 994.36,-339.05"/>
|
||||
<polygon fill="black" stroke="black" points="996.13,-342.07 1003.47,-334.43 992.97,-335.83 996.13,-342.07"/>
|
||||
</g>
|
||||
<!-- u10 -->
|
||||
<g id="node26" class="node">
|
||||
<title>u10</title>
|
||||
<ellipse fill="#ffff77" stroke="black" stroke-width="0" cx="1030" cy="-80.99" rx="27" ry="18"/>
|
||||
<text text-anchor="middle" x="1030" y="-77.29" font-family="Times-Roman" font-size="14.00">QQ</text>
|
||||
</g>
|
||||
<!-- u16 -->
|
||||
<g id="node27" class="node">
|
||||
<title>u16</title>
|
||||
<ellipse fill="#7777ff" stroke="black" stroke-width="0" cx="629" cy="-571.99" rx="27" ry="18"/>
|
||||
<text text-anchor="middle" x="629" y="-568.29" font-family="Times-Roman" font-size="14.00">QQ</text>
|
||||
</g>
|
||||
<!-- u15->u1 -->
|
||||
<g id="edge51" class="edge">
|
||||
<title>u15->u1</title>
|
||||
<path fill="none" stroke="black" d="M707.81,-589.96C711.74,-608.15 720.7,-636.49 740,-651.99 869.4,-755.91 944.8,-686.54 1106,-725.99 1109.21,-726.78 1112.51,-727.62 1115.82,-728.5"/>
|
||||
<polygon fill="black" stroke="black" points="1115.2,-731.95 1125.77,-731.2 1117.04,-725.2 1115.2,-731.95"/>
|
||||
</g>
|
||||
<!-- u6->u3 -->
|
||||
<g id="edge52" class="edge">
|
||||
<title>u6->u3</title>
|
||||
<path fill="none" stroke="black" d="M972.89,-557.62C1042.12,-533.81 1179.56,-486.5 1180,-485.99 1202.36,-460.38 1181.75,-442.3 1195,-410.99 1205.36,-386.51 1222.94,-361.88 1236.75,-344.58"/>
|
||||
<polygon fill="black" stroke="black" points="1239.56,-346.68 1243.17,-336.72 1234.13,-342.25 1239.56,-346.68"/>
|
||||
</g>
|
||||
<!-- u8 -->
|
||||
<g id="node31" class="node">
|
||||
<title>u8</title>
|
||||
<ellipse fill="#ffbbff" stroke="black" stroke-width="0" cx="1030" cy="-202.99" rx="42.49" ry="18"/>
|
||||
<text text-anchor="middle" x="1030" y="-199.29" font-family="Times-Roman" font-size="14.00">Logger</text>
|
||||
</g>
|
||||
<!-- u7->u8 -->
|
||||
<g id="edge54" class="edge">
|
||||
<title>u7->u8</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M1030,-301.52C1030,-282.93 1030,-253.23 1030,-231.49"/>
|
||||
<polygon fill="black" stroke="black" points="1033.5,-231.24 1030,-221.24 1026.5,-231.24 1033.5,-231.24"/>
|
||||
</g>
|
||||
<!-- u2 -->
|
||||
<g id="node34" class="node">
|
||||
<title>u2</title>
|
||||
<ellipse fill="#ffffbb" stroke="black" stroke-width="0" cx="1128" cy="-436.99" rx="37.89" ry="18"/>
|
||||
<text text-anchor="middle" x="1128" y="-433.29" font-family="Times-Roman" font-size="14.00">Errors</text>
|
||||
</g>
|
||||
<!-- u7->u2 -->
|
||||
<g id="edge53" class="edge">
|
||||
<title>u7->u2</title>
|
||||
<path fill="none" stroke="black" d="M1043.83,-337.21C1060.5,-356.78 1088.66,-389.83 1107.78,-412.26"/>
|
||||
<polygon fill="black" stroke="black" points="1105.22,-414.66 1114.37,-420 1110.55,-410.12 1105.22,-414.66"/>
|
||||
</g>
|
||||
<!-- u8->u4 -->
|
||||
<g id="edge55" class="edge">
|
||||
<title>u8->u4</title>
|
||||
<path fill="none" stroke="black" d="M1072.08,-205.27C1132.49,-209.51 1242.99,-226.65 1302,-293.99 1329.81,-325.73 1332.74,-377.05 1331.47,-408.52"/>
|
||||
<polygon fill="black" stroke="black" points="1327.96,-408.58 1330.88,-418.77 1334.95,-408.98 1327.96,-408.58"/>
|
||||
</g>
|
||||
<!-- u8->u9 -->
|
||||
<g id="edge56" class="edge">
|
||||
<title>u8->u9</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M1014.36,-219.98C975.12,-260.08 872.38,-365.08 826.14,-412.34"/>
|
||||
<polygon fill="black" stroke="black" points="823.45,-410.08 818.96,-419.68 828.46,-414.98 823.45,-410.08"/>
|
||||
</g>
|
||||
<!-- u8->u10 -->
|
||||
<g id="edge57" class="edge">
|
||||
<title>u8->u10</title>
|
||||
<path fill="none" stroke="black" d="M1030,-184.8C1030,-165.1 1030,-132.57 1030,-109.38"/>
|
||||
<polygon fill="black" stroke="black" points="1033.5,-109.15 1030,-99.15 1026.5,-109.15 1033.5,-109.15"/>
|
||||
</g>
|
||||
<!-- u11->u5 -->
|
||||
<g id="edge58" class="edge">
|
||||
<title>u11->u5</title>
|
||||
<path fill="none" stroke="black" d="M1062.1,-557.23C1067.11,-553.42 1072.68,-549.4 1078,-545.99 1125.54,-515.51 1144.66,-519.65 1190,-485.99 1199.71,-478.78 1209.34,-469.64 1217.41,-461.28"/>
|
||||
<polygon fill="black" stroke="black" points="1220.04,-463.58 1224.33,-453.89 1214.94,-458.8 1220.04,-463.58"/>
|
||||
</g>
|
||||
<!-- u0->u16 -->
|
||||
<g id="edge4" class="edge">
|
||||
<title>u0->u16</title>
|
||||
<path fill="none" stroke="black" d="M700.59,-847.09C687.91,-798.57 651.35,-658.57 635.96,-599.64"/>
|
||||
<polygon fill="black" stroke="black" points="639.34,-598.73 633.43,-589.94 632.57,-600.5 639.34,-598.73"/>
|
||||
</g>
|
||||
<!-- u0->u15 -->
|
||||
<g id="edge3" class="edge">
|
||||
<title>u0->u15</title>
|
||||
<path fill="none" stroke="black" d="M705,-846.66C705,-797.93 705,-659.45 705,-600.31"/>
|
||||
<polygon fill="black" stroke="black" points="708.5,-600.23 705,-590.23 701.5,-600.23 708.5,-600.23"/>
|
||||
</g>
|
||||
<!-- u0->u14 -->
|
||||
<g id="edge2" class="edge">
|
||||
<title>u0->u14</title>
|
||||
<path fill="none" stroke="black" d="M730.82,-850.57C771.64,-829.36 851.2,-788.02 897.73,-763.84"/>
|
||||
<polygon fill="black" stroke="black" points="899.59,-766.81 906.85,-759.1 896.37,-760.6 899.59,-766.81"/>
|
||||
</g>
|
||||
<!-- u2->u3 -->
|
||||
<g id="edge5" class="edge">
|
||||
<title>u2->u3</title>
|
||||
<path fill="none" stroke="black" d="M1145.13,-420.72C1167.39,-400.87 1206.44,-366.06 1232.01,-343.27"/>
|
||||
<polygon fill="black" stroke="black" points="1234.66,-345.59 1239.8,-336.32 1230.01,-340.37 1234.66,-345.59"/>
|
||||
</g>
|
||||
<!-- u13->u3 -->
|
||||
<g id="edge6" class="edge">
|
||||
<title>u13->u3</title>
|
||||
<path fill="none" stroke="black" d="M1413.93,-553.61C1413.03,-522.51 1407.48,-456.35 1378,-410.99 1356.72,-378.25 1319.17,-353.11 1291.53,-337.83"/>
|
||||
<polygon fill="black" stroke="black" points="1293.04,-334.67 1282.57,-333.03 1289.73,-340.84 1293.04,-334.67"/>
|
||||
</g>
|
||||
<!-- u14->u5 -->
|
||||
<g id="edge7" class="edge">
|
||||
<title>u14->u5</title>
|
||||
<path fill="none" stroke="black" d="M970.19,-731.9C1005.99,-718.88 1059.19,-693.62 1086,-651.99 1111.67,-612.13 1073.1,-586.34 1098,-545.99 1123.63,-504.44 1152.09,-516.75 1190,-485.99 1199.39,-478.37 1208.96,-469.15 1217.06,-460.83"/>
|
||||
<polygon fill="black" stroke="black" points="1219.67,-463.17 1224.04,-453.52 1214.6,-458.34 1219.67,-463.17"/>
|
||||
</g>
|
||||
<!-- u14->u12 -->
|
||||
<g id="edge8" class="edge">
|
||||
<title>u14->u12</title>
|
||||
<path fill="none" stroke="black" d="M917.2,-726.88C899.99,-709.65 873.37,-680.88 856,-651.99 846.1,-635.52 838.24,-615.33 832.91,-599.48"/>
|
||||
<polygon fill="black" stroke="black" points="836.18,-598.22 829.78,-589.77 829.52,-600.36 836.18,-598.22"/>
|
||||
</g>
|
||||
<!-- u18->u5 -->
|
||||
<g id="edge10" class="edge">
|
||||
<title>u18->u5</title>
|
||||
<path fill="none" stroke="black" d="M1467.83,-725.94C1481.37,-689.08 1507.02,-600.87 1467,-545.99 1415.57,-475.47 1352.95,-533.91 1280,-485.99 1270.56,-479.79 1261.98,-470.91 1255.06,-462.47"/>
|
||||
<polygon fill="black" stroke="black" points="1257.62,-460.06 1248.74,-454.29 1252.09,-464.34 1257.62,-460.06"/>
|
||||
</g>
|
||||
<!-- u18->u13 -->
|
||||
<g id="edge9" class="edge">
|
||||
<title>u18->u13</title>
|
||||
<path fill="none" stroke="black" d="M1456.23,-725.75C1448.05,-696.15 1431.26,-635.42 1421.5,-600.1"/>
|
||||
<polygon fill="black" stroke="black" points="1424.75,-598.72 1418.71,-590.02 1418,-600.59 1424.75,-598.72"/>
|
||||
</g>
|
||||
<!-- u20 -->
|
||||
<g id="node38" class="node">
|
||||
<title>u20</title>
|
||||
<ellipse fill="#bbffbb" stroke="black" stroke-width="0" cx="742" cy="-1387.99" rx="32.49" ry="18"/>
|
||||
<text text-anchor="middle" x="742" y="-1384.29" font-family="Times-Roman" font-size="14.00">Main</text>
|
||||
</g>
|
||||
<!-- u20->u21 -->
|
||||
<g id="edge1" class="edge">
|
||||
<title>u20->u21</title>
|
||||
<path fill="none" stroke="black" d="M742,-1369.75C742,-1340.15 742,-1279.42 742,-1244.1"/>
|
||||
<polygon fill="black" stroke="black" points="745.5,-1244.02 742,-1234.02 738.5,-1244.02 745.5,-1244.02"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 32 KiB |
641
docs/modules_wide.svg
Normal file
@@ -0,0 +1,641 @@
|
||||
<?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="1076pt" height="648pt"
|
||||
viewBox="0.00 0.00 1076.37 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.68 0.68) rotate(0) translate(4 949)">
|
||||
<title>G</title>
|
||||
<polygon fill="white" stroke="transparent" points="-4,4 -4,-949 1579,-949 1579,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.66 8,-897.37 1567,-897.37 1567,-8.66 8,-8.66"/>
|
||||
<text text-anchor="middle" x="787.5" y="-882.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="1102,-352.89 1102,-548.81 1362,-548.81 1362,-352.89 1102,-352.89"/>
|
||||
<text text-anchor="middle" x="1232" y="-533.61" 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="16,-626.75 16,-863.81 1559,-863.81 1559,-626.75 16,-626.75"/>
|
||||
<text text-anchor="middle" x="787.5" y="-848.61" font-family="Times-Roman" font-size="14.00">OptParse</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="1196,-185.1 1196,-344.23 1377,-344.23 1377,-185.1 1196,-185.1"/>
|
||||
<text text-anchor="middle" x="1286.5" y="-329.03" font-family="Times-Roman" font-size="14.00">Types</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="586,-17.32 586,-467.63 1082,-467.63 1082,-17.32 586,-17.32"/>
|
||||
<text text-anchor="middle" x="834" y="-452.43" font-family="Times-Roman" font-size="14.00">Utils</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="744,-263.04 744,-434.07 862,-434.07 862,-263.04 744,-263.04"/>
|
||||
<text text-anchor="middle" x="803" y="-418.87" font-family="Times-Roman" font-size="14.00">File</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="995,-25.98 995,-107.16 1065,-107.16 1065,-25.98 995,-25.98"/>
|
||||
<text text-anchor="middle" x="1030" y="-91.96" font-family="Times-Roman" font-size="14.00">String</text>
|
||||
</g>
|
||||
<g id="clust8" class="cluster">
|
||||
<title>cluster_7</title>
|
||||
<polygon fill="#000000" fill-opacity="0.058824" stroke="#000000" stroke-opacity="0.058824" points="594,-352.89 594,-434.07 664,-434.07 664,-352.89 594,-352.89"/>
|
||||
<text text-anchor="middle" x="629" y="-418.87" 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="1165" cy="-495.66" rx="55.49" ry="18"/>
|
||||
<text text-anchor="middle" x="1165" y="-491.96" font-family="Times-Roman" font-size="14.00">Download</text>
|
||||
</g>
|
||||
<!-- u12 -->
|
||||
<g id="node24" class="node">
|
||||
<title>u12</title>
|
||||
<ellipse fill="#ffbbff" stroke="black" stroke-width="2" cx="825" cy="-380.66" rx="27" ry="18"/>
|
||||
<text text-anchor="middle" x="825" y="-376.96" font-family="Times-Roman" font-size="14.00">File</text>
|
||||
</g>
|
||||
<!-- u1->u12 -->
|
||||
<g id="edge13" class="edge">
|
||||
<title>u1->u12</title>
|
||||
<path fill="none" stroke="black" d="M1127.19,-482.48C1120.21,-480.6 1112.93,-478.88 1106,-477.66 1078.58,-472.83 878.46,-477.12 856,-460.66 839.51,-448.58 831.79,-426.38 828.17,-408.59"/>
|
||||
<polygon fill="black" stroke="black" points="831.62,-407.99 826.49,-398.73 824.72,-409.17 831.62,-407.99"/>
|
||||
</g>
|
||||
<!-- u11 -->
|
||||
<g id="node32" class="node">
|
||||
<title>u11</title>
|
||||
<ellipse fill="#ffbbff" stroke="black" stroke-width="0" cx="1045" cy="-380.66" rx="28.7" ry="18"/>
|
||||
<text text-anchor="middle" x="1045" y="-376.96" font-family="Times-Roman" font-size="14.00">Dirs</text>
|
||||
</g>
|
||||
<!-- u1->u11 -->
|
||||
<g id="edge12" class="edge">
|
||||
<title>u1->u11</title>
|
||||
<path fill="none" stroke="black" d="M1130.87,-481.48C1119.63,-476.1 1107.57,-469.13 1098,-460.66 1081.15,-445.74 1067.22,-424.32 1057.88,-407.55"/>
|
||||
<polygon fill="black" stroke="black" points="1060.73,-405.46 1052.92,-398.3 1054.56,-408.76 1060.73,-405.46"/>
|
||||
</g>
|
||||
<!-- u13 -->
|
||||
<g id="node35" class="node">
|
||||
<title>u13</title>
|
||||
<ellipse fill="#ffffbb" stroke="black" stroke-width="0" cx="1414" cy="-380.66" rx="44.39" ry="18"/>
|
||||
<text text-anchor="middle" x="1414" y="-376.96" font-family="Times-Roman" font-size="14.00">Version</text>
|
||||
</g>
|
||||
<!-- u1->u13 -->
|
||||
<g id="edge11" class="edge">
|
||||
<title>u1->u13</title>
|
||||
<path fill="none" stroke="black" d="M1205.09,-483.12C1212.97,-481.1 1221.21,-479.17 1229,-477.66 1259.12,-471.82 1340.24,-477.32 1366,-460.66 1384.87,-448.45 1397.46,-425.95 1405,-408.08"/>
|
||||
<polygon fill="black" stroke="black" points="1408.27,-409.31 1408.67,-398.72 1401.76,-406.75 1408.27,-409.31"/>
|
||||
</g>
|
||||
<!-- u17 -->
|
||||
<g id="node2" class="node">
|
||||
<title>u17</title>
|
||||
<ellipse fill="#bbbbff" stroke="black" stroke-width="0" cx="1267" cy="-380.66" rx="30.59" ry="18"/>
|
||||
<text text-anchor="middle" x="1267" y="-376.96" font-family="Times-Roman" font-size="14.00">Utils</text>
|
||||
</g>
|
||||
<!-- u5 -->
|
||||
<g id="node23" class="node">
|
||||
<title>u5</title>
|
||||
<ellipse fill="#bbffff" stroke="black" stroke-width="0" cx="1238" cy="-291.66" rx="33.6" ry="18"/>
|
||||
<text text-anchor="middle" x="1238" y="-287.96" font-family="Times-Roman" font-size="14.00">JSON</text>
|
||||
</g>
|
||||
<!-- u17->u5 -->
|
||||
<g id="edge14" class="edge">
|
||||
<title>u17->u5</title>
|
||||
<path fill="none" stroke="black" d="M1261.41,-362.89C1257.3,-350.57 1251.64,-333.58 1246.91,-319.4"/>
|
||||
<polygon fill="black" stroke="black" points="1250.16,-318.06 1243.67,-309.68 1243.52,-320.27 1250.16,-318.06"/>
|
||||
</g>
|
||||
<!-- u19 -->
|
||||
<g id="node3" class="node">
|
||||
<title>u19</title>
|
||||
<ellipse fill="#bbbbff" stroke="black" stroke-width="0" cx="1296" cy="-495.66" rx="57.69" ry="18"/>
|
||||
<text text-anchor="middle" x="1296" y="-491.96" font-family="Times-Roman" font-size="14.00">IOStreams</text>
|
||||
</g>
|
||||
<!-- u19->u17 -->
|
||||
<g id="edge15" class="edge">
|
||||
<title>u19->u17</title>
|
||||
<path fill="none" stroke="black" d="M1291.6,-477.5C1286.88,-459.14 1279.35,-429.78 1273.86,-408.39"/>
|
||||
<polygon fill="black" stroke="black" points="1277.23,-407.43 1271.35,-398.61 1270.45,-409.17 1277.23,-407.43"/>
|
||||
</g>
|
||||
<!-- u21 -->
|
||||
<g id="node4" class="node">
|
||||
<title>u21</title>
|
||||
<ellipse fill="#ffffbb" stroke="black" stroke-width="2" cx="742" cy="-810.66" rx="51.99" ry="18"/>
|
||||
<text text-anchor="middle" x="742" y="-806.96" font-family="Times-Roman" font-size="14.00">OptParse</text>
|
||||
</g>
|
||||
<!-- u23 -->
|
||||
<g id="node6" class="node">
|
||||
<title>u23</title>
|
||||
<ellipse fill="#ffbbbb" stroke="black" stroke-width="0" cx="846" cy="-732.66" rx="38.19" ry="18"/>
|
||||
<text text-anchor="middle" x="846" y="-728.96" font-family="Times-Roman" font-size="14.00">Install</text>
|
||||
</g>
|
||||
<!-- u21->u23 -->
|
||||
<g id="edge16" class="edge">
|
||||
<title>u21->u23</title>
|
||||
<path fill="none" stroke="black" d="M763.3,-794.1C778.98,-782.63 800.48,-766.92 817.63,-754.39"/>
|
||||
<polygon fill="black" stroke="black" points="820.13,-756.9 826.14,-748.17 816,-751.25 820.13,-756.9"/>
|
||||
</g>
|
||||
<!-- u24 -->
|
||||
<g id="node7" class="node">
|
||||
<title>u24</title>
|
||||
<ellipse fill="#ffbbbb" stroke="black" stroke-width="0" cx="929" cy="-732.66" rx="27" ry="18"/>
|
||||
<text text-anchor="middle" x="929" y="-728.96" font-family="Times-Roman" font-size="14.00">Set</text>
|
||||
</g>
|
||||
<!-- u21->u24 -->
|
||||
<g id="edge17" class="edge">
|
||||
<title>u21->u24</title>
|
||||
<path fill="none" stroke="black" d="M776.15,-797.08C806.94,-785.56 853.32,-767.76 893,-750.66 894.81,-749.88 896.66,-749.06 898.53,-748.23"/>
|
||||
<polygon fill="black" stroke="black" points="900.16,-751.33 907.79,-743.97 897.24,-744.97 900.16,-751.33"/>
|
||||
</g>
|
||||
<!-- u25 -->
|
||||
<g id="node8" class="node">
|
||||
<title>u25</title>
|
||||
<ellipse fill="#ffbbbb" stroke="black" stroke-width="0" cx="1197" cy="-732.66" rx="38.19" ry="18"/>
|
||||
<text text-anchor="middle" x="1197" y="-728.96" font-family="Times-Roman" font-size="14.00">UnSet</text>
|
||||
</g>
|
||||
<!-- u21->u25 -->
|
||||
<g id="edge18" class="edge">
|
||||
<title>u21->u25</title>
|
||||
<path fill="none" stroke="black" d="M792.1,-805.59C869.52,-798.59 1022.5,-781.91 1149,-750.66 1152.18,-749.88 1155.44,-748.96 1158.69,-747.97"/>
|
||||
<polygon fill="black" stroke="black" points="1159.91,-751.26 1168.34,-744.84 1157.75,-744.6 1159.91,-751.26"/>
|
||||
</g>
|
||||
<!-- u26 -->
|
||||
<g id="node9" class="node">
|
||||
<title>u26</title>
|
||||
<ellipse fill="#ffbbbb" stroke="black" stroke-width="0" cx="1001" cy="-732.66" rx="27" ry="18"/>
|
||||
<text text-anchor="middle" x="1001" y="-728.96" font-family="Times-Roman" font-size="14.00">Rm</text>
|
||||
</g>
|
||||
<!-- u21->u26 -->
|
||||
<g id="edge19" class="edge">
|
||||
<title>u21->u26</title>
|
||||
<path fill="none" stroke="black" d="M785.47,-800.63C830.94,-790.62 904.05,-772.9 965,-750.66 966.85,-749.98 968.74,-749.25 970.62,-748.47"/>
|
||||
<polygon fill="black" stroke="black" points="972.2,-751.6 979.95,-744.38 969.39,-745.19 972.2,-751.6"/>
|
||||
</g>
|
||||
<!-- u27 -->
|
||||
<g id="node10" class="node">
|
||||
<title>u27</title>
|
||||
<ellipse fill="#ffbbbb" stroke="black" stroke-width="0" cx="1093" cy="-732.66" rx="47.39" ry="18"/>
|
||||
<text text-anchor="middle" x="1093" y="-728.96" font-family="Times-Roman" font-size="14.00">Compile</text>
|
||||
</g>
|
||||
<!-- u21->u27 -->
|
||||
<g id="edge20" class="edge">
|
||||
<title>u21->u27</title>
|
||||
<path fill="none" stroke="black" d="M787.79,-801.93C846.05,-791.76 949.62,-772.61 1037,-750.66 1040.61,-749.75 1044.34,-748.76 1048.07,-747.72"/>
|
||||
<polygon fill="black" stroke="black" points="1049.25,-751.02 1057.9,-744.89 1047.32,-744.29 1049.25,-751.02"/>
|
||||
</g>
|
||||
<!-- u28 -->
|
||||
<g id="node11" class="node">
|
||||
<title>u28</title>
|
||||
<ellipse fill="#ffbbbb" stroke="black" stroke-width="0" cx="64" cy="-732.66" rx="40.09" ry="18"/>
|
||||
<text text-anchor="middle" x="64" y="-728.96" font-family="Times-Roman" font-size="14.00">Config</text>
|
||||
</g>
|
||||
<!-- u21->u28 -->
|
||||
<g id="edge21" class="edge">
|
||||
<title>u21->u28</title>
|
||||
<path fill="none" stroke="black" d="M689.99,-808.99C581.5,-806.67 323.62,-796.37 113,-750.66 109.64,-749.93 106.2,-749.04 102.77,-748.06"/>
|
||||
<polygon fill="black" stroke="black" points="103.8,-744.71 93.21,-745.08 101.72,-751.4 103.8,-744.71"/>
|
||||
</g>
|
||||
<!-- u29 -->
|
||||
<g id="node12" class="node">
|
||||
<title>u29</title>
|
||||
<ellipse fill="#ffbbbb" stroke="black" stroke-width="0" cx="415" cy="-732.66" rx="46.59" ry="18"/>
|
||||
<text text-anchor="middle" x="415" y="-728.96" font-family="Times-Roman" font-size="14.00">Whereis</text>
|
||||
</g>
|
||||
<!-- u21->u29 -->
|
||||
<g id="edge22" class="edge">
|
||||
<title>u21->u29</title>
|
||||
<path fill="none" stroke="black" d="M697.62,-801.14C643.73,-790.53 550.22,-771.27 471,-750.66 467.24,-749.68 463.35,-748.61 459.45,-747.51"/>
|
||||
<polygon fill="black" stroke="black" points="460.41,-744.14 449.83,-744.71 458.45,-750.86 460.41,-744.14"/>
|
||||
</g>
|
||||
<!-- u30 -->
|
||||
<g id="node13" class="node">
|
||||
<title>u30</title>
|
||||
<ellipse fill="#ffbbbb" stroke="black" stroke-width="0" cx="507" cy="-732.66" rx="27" ry="18"/>
|
||||
<text text-anchor="middle" x="507" y="-728.96" font-family="Times-Roman" font-size="14.00">List</text>
|
||||
</g>
|
||||
<!-- u21->u30 -->
|
||||
<g id="edge23" class="edge">
|
||||
<title>u21->u30</title>
|
||||
<path fill="none" stroke="black" d="M700.99,-799.47C660.33,-788.91 596.53,-771.1 543,-750.66 541.16,-749.96 539.28,-749.2 537.4,-748.41"/>
|
||||
<polygon fill="black" stroke="black" points="538.65,-745.13 528.09,-744.28 535.81,-751.53 538.65,-745.13"/>
|
||||
</g>
|
||||
<!-- u31 -->
|
||||
<g id="node14" class="node">
|
||||
<title>u31</title>
|
||||
<ellipse fill="#ffbbbb" stroke="black" stroke-width="0" cx="1303" cy="-732.66" rx="50.09" ry="18"/>
|
||||
<text text-anchor="middle" x="1303" y="-728.96" font-family="Times-Roman" font-size="14.00">Upgrade</text>
|
||||
</g>
|
||||
<!-- u21->u31 -->
|
||||
<g id="edge24" class="edge">
|
||||
<title>u21->u31</title>
|
||||
<path fill="none" stroke="black" d="M792.66,-806.46C883.72,-800.09 1080.77,-783.54 1244,-750.66 1248.17,-749.82 1252.48,-748.83 1256.78,-747.75"/>
|
||||
<polygon fill="black" stroke="black" points="1257.95,-751.06 1266.72,-745.12 1256.16,-744.29 1257.95,-751.06"/>
|
||||
</g>
|
||||
<!-- u32 -->
|
||||
<g id="node15" class="node">
|
||||
<title>u32</title>
|
||||
<ellipse fill="#ffbbbb" stroke="black" stroke-width="0" cx="614" cy="-732.66" rx="61.99" ry="18"/>
|
||||
<text text-anchor="middle" x="614" y="-728.96" font-family="Times-Roman" font-size="14.00">ChangeLog</text>
|
||||
</g>
|
||||
<!-- u21->u32 -->
|
||||
<g id="edge25" class="edge">
|
||||
<title>u21->u32</title>
|
||||
<path fill="none" stroke="black" d="M717.02,-794.83C697.66,-783.34 670.61,-767.27 649.09,-754.49"/>
|
||||
<polygon fill="black" stroke="black" points="650.63,-751.34 640.24,-749.24 647.05,-757.36 650.63,-751.34"/>
|
||||
</g>
|
||||
<!-- u33 -->
|
||||
<g id="node16" class="node">
|
||||
<title>u33</title>
|
||||
<ellipse fill="#ffbbbb" stroke="black" stroke-width="0" cx="742" cy="-732.66" rx="48.19" ry="18"/>
|
||||
<text text-anchor="middle" x="742" y="-728.96" font-family="Times-Roman" font-size="14.00">Prefetch</text>
|
||||
</g>
|
||||
<!-- u21->u33 -->
|
||||
<g id="edge26" class="edge">
|
||||
<title>u21->u33</title>
|
||||
<path fill="none" stroke="black" d="M742,-792.41C742,-783.18 742,-771.59 742,-761.15"/>
|
||||
<polygon fill="black" stroke="black" points="745.5,-760.84 742,-750.84 738.5,-760.84 745.5,-760.84"/>
|
||||
</g>
|
||||
<!-- u34 -->
|
||||
<g id="node17" class="node">
|
||||
<title>u34</title>
|
||||
<ellipse fill="#ffbbbb" stroke="black" stroke-width="0" cx="235" cy="-732.66" rx="27" ry="18"/>
|
||||
<text text-anchor="middle" x="235" y="-728.96" font-family="Times-Roman" font-size="14.00">GC</text>
|
||||
</g>
|
||||
<!-- u21->u34 -->
|
||||
<g id="edge27" class="edge">
|
||||
<title>u21->u34</title>
|
||||
<path fill="none" stroke="black" d="M690.05,-808.49C602.09,-805.33 418.98,-793.68 271,-750.66 269.06,-750.1 267.09,-749.44 265.13,-748.72"/>
|
||||
<polygon fill="black" stroke="black" points="266.08,-745.32 255.5,-744.7 263.39,-751.78 266.08,-745.32"/>
|
||||
</g>
|
||||
<!-- u35 -->
|
||||
<g id="node18" class="node">
|
||||
<title>u35</title>
|
||||
<ellipse fill="#ffbbbb" stroke="black" stroke-width="0" cx="315" cy="-732.66" rx="35.19" ry="18"/>
|
||||
<text text-anchor="middle" x="315" y="-728.96" font-family="Times-Roman" font-size="14.00">DInfo</text>
|
||||
</g>
|
||||
<!-- u21->u35 -->
|
||||
<g id="edge28" class="edge">
|
||||
<title>u21->u35</title>
|
||||
<path fill="none" stroke="black" d="M692.02,-805.43C618.22,-798.41 476.17,-781.93 359,-750.66 356.35,-749.95 353.63,-749.14 350.92,-748.26"/>
|
||||
<polygon fill="black" stroke="black" points="351.81,-744.86 341.22,-744.85 349.49,-751.47 351.81,-744.86"/>
|
||||
</g>
|
||||
<!-- u36 -->
|
||||
<g id="node19" class="node">
|
||||
<title>u36</title>
|
||||
<ellipse fill="#ffbbbb" stroke="black" stroke-width="0" cx="1461" cy="-732.66" rx="90.18" ry="18"/>
|
||||
<text text-anchor="middle" x="1461" y="-728.96" font-family="Times-Roman" font-size="14.00">ToolRequirements</text>
|
||||
</g>
|
||||
<!-- u21->u36 -->
|
||||
<g id="edge29" class="edge">
|
||||
<title>u21->u36</title>
|
||||
<path fill="none" stroke="black" d="M792.37,-806.16C898.17,-798.52 1151.13,-778.76 1362,-750.66 1370.05,-749.59 1378.45,-748.34 1386.8,-747.02"/>
|
||||
<polygon fill="black" stroke="black" points="1387.62,-750.44 1396.94,-745.38 1386.51,-743.53 1387.62,-750.44"/>
|
||||
</g>
|
||||
<!-- u37 -->
|
||||
<g id="node20" class="node">
|
||||
<title>u37</title>
|
||||
<ellipse fill="#ffbbbb" stroke="black" stroke-width="0" cx="156" cy="-732.66" rx="33.6" ry="18"/>
|
||||
<text text-anchor="middle" x="156" y="-728.96" font-family="Times-Roman" font-size="14.00">Nuke</text>
|
||||
</g>
|
||||
<!-- u21->u37 -->
|
||||
<g id="edge30" class="edge">
|
||||
<title>u21->u37</title>
|
||||
<path fill="none" stroke="black" d="M690.3,-808.63C592.81,-805.69 375.74,-794.35 199,-750.66 196.22,-749.97 193.39,-749.15 190.56,-748.24"/>
|
||||
<polygon fill="black" stroke="black" points="191.69,-744.93 181.1,-744.88 189.35,-751.52 191.69,-744.93"/>
|
||||
</g>
|
||||
<!-- u22 -->
|
||||
<g id="node5" class="node">
|
||||
<title>u22</title>
|
||||
<ellipse fill="#ffbbbb" stroke="black" stroke-width="0" cx="742" cy="-654.66" rx="51.19" ry="18"/>
|
||||
<text text-anchor="middle" x="742" y="-650.96" font-family="Times-Roman" font-size="14.00">Common</text>
|
||||
</g>
|
||||
<!-- u0 -->
|
||||
<g id="node33" class="node">
|
||||
<title>u0</title>
|
||||
<ellipse fill="#bbffbb" stroke="black" stroke-width="2" cx="705" cy="-576.66" rx="42.49" ry="18"/>
|
||||
<text text-anchor="middle" x="705" y="-572.96" font-family="Times-Roman" font-size="14.00">GHCup</text>
|
||||
</g>
|
||||
<!-- u22->u0 -->
|
||||
<g id="edge31" class="edge">
|
||||
<title>u22->u0</title>
|
||||
<path fill="none" stroke="black" d="M733.79,-636.79C729.05,-627.05 722.98,-614.59 717.64,-603.63"/>
|
||||
<polygon fill="black" stroke="black" points="720.71,-601.94 713.19,-594.48 714.42,-605 720.71,-601.94"/>
|
||||
</g>
|
||||
<!-- u23->u22 -->
|
||||
<g id="edge32" class="edge">
|
||||
<title>u23->u22</title>
|
||||
<path fill="none" stroke="black" d="M825.95,-717.01C810.53,-705.74 788.99,-690 771.59,-677.28"/>
|
||||
<polygon fill="black" stroke="black" points="773.56,-674.39 763.42,-671.31 769.43,-680.04 773.56,-674.39"/>
|
||||
</g>
|
||||
<!-- u24->u22 -->
|
||||
<g id="edge33" class="edge">
|
||||
<title>u24->u22</title>
|
||||
<path fill="none" stroke="black" d="M907.79,-721.35C902.96,-719.08 897.82,-716.74 893,-714.66 857.2,-699.23 815.93,-683.23 785.6,-671.79"/>
|
||||
<polygon fill="black" stroke="black" points="786.75,-668.48 776.15,-668.24 784.29,-675.03 786.75,-668.48"/>
|
||||
</g>
|
||||
<!-- u25->u0 -->
|
||||
<g id="edge34" class="edge">
|
||||
<title>u25->u0</title>
|
||||
<path fill="none" stroke="black" d="M1167.62,-721.04C1161.48,-718.88 1155.04,-716.66 1149,-714.66 1003.04,-666.32 828.31,-614.02 748.55,-590.45"/>
|
||||
<polygon fill="black" stroke="black" points="749.43,-587.06 738.85,-587.59 747.45,-593.77 749.43,-587.06"/>
|
||||
</g>
|
||||
<!-- u26->u22 -->
|
||||
<g id="edge35" class="edge">
|
||||
<title>u26->u22</title>
|
||||
<path fill="none" stroke="black" d="M979.97,-720.89C975.13,-718.64 969.95,-716.43 965,-714.66 892.52,-688.77 871.13,-693.36 797,-672.66 794.25,-671.89 791.42,-671.08 788.58,-670.25"/>
|
||||
<polygon fill="black" stroke="black" points="789.48,-666.87 778.9,-667.37 787.48,-673.58 789.48,-666.87"/>
|
||||
</g>
|
||||
<!-- u27->u22 -->
|
||||
<g id="edge36" class="edge">
|
||||
<title>u27->u22</title>
|
||||
<path fill="none" stroke="black" d="M1058.23,-720.39C1051.24,-718.33 1043.92,-716.31 1037,-714.66 931.66,-689.55 902.27,-698.03 797,-672.66 794.04,-671.95 791,-671.16 787.94,-670.33"/>
|
||||
<polygon fill="black" stroke="black" points="788.79,-666.93 778.21,-667.56 786.87,-673.66 788.79,-666.93"/>
|
||||
</g>
|
||||
<!-- u15 -->
|
||||
<g id="node28" class="node">
|
||||
<title>u15</title>
|
||||
<ellipse fill="#ffffbb" stroke="black" stroke-width="2" cx="705" cy="-380.66" rx="30.59" ry="18"/>
|
||||
<text text-anchor="middle" x="705" y="-376.96" font-family="Times-Roman" font-size="14.00">Utils</text>
|
||||
</g>
|
||||
<!-- u28->u15 -->
|
||||
<g id="edge37" class="edge">
|
||||
<title>u28->u15</title>
|
||||
<path fill="none" stroke="black" d="M71.46,-714.85C93.67,-667.18 164.47,-531.09 271,-477.66 310.47,-457.87 631.26,-485.14 668,-460.66 685.49,-449.01 694.89,-426.77 699.83,-408.86"/>
|
||||
<polygon fill="black" stroke="black" points="703.29,-409.46 702.25,-398.92 696.49,-407.8 703.29,-409.46"/>
|
||||
</g>
|
||||
<!-- u29->u22 -->
|
||||
<g id="edge38" class="edge">
|
||||
<title>u29->u22</title>
|
||||
<path fill="none" stroke="black" d="M449.8,-720.49C456.78,-718.42 464.1,-716.37 471,-714.66 565.92,-691.09 592.14,-696.47 687,-672.66 689.96,-671.92 692.99,-671.11 696.04,-670.26"/>
|
||||
<polygon fill="black" stroke="black" points="697.13,-673.6 705.77,-667.46 695.19,-666.87 697.13,-673.6"/>
|
||||
</g>
|
||||
<!-- u30->u22 -->
|
||||
<g id="edge39" class="edge">
|
||||
<title>u30->u22</title>
|
||||
<path fill="none" stroke="black" d="M528.08,-721.03C532.92,-718.78 538.09,-716.52 543,-714.66 605.33,-691.02 623.15,-691.84 687,-672.66 689.74,-671.84 692.55,-670.99 695.38,-670.12"/>
|
||||
<polygon fill="black" stroke="black" points="696.5,-673.44 705.04,-667.17 694.46,-666.75 696.5,-673.44"/>
|
||||
</g>
|
||||
<!-- u31->u0 -->
|
||||
<g id="edge40" class="edge">
|
||||
<title>u31->u0</title>
|
||||
<path fill="none" stroke="black" d="M1267.21,-719.95C1204.45,-699.67 1070.24,-657.41 955,-628.66 885.44,-611.3 803.91,-595.51 753.35,-586.24"/>
|
||||
<polygon fill="black" stroke="black" points="753.82,-582.77 743.35,-584.42 752.56,-589.65 753.82,-582.77"/>
|
||||
</g>
|
||||
<!-- u32->u22 -->
|
||||
<g id="edge41" class="edge">
|
||||
<title>u32->u22</title>
|
||||
<path fill="none" stroke="black" d="M639.9,-716.28C659.59,-704.59 686.84,-688.41 708.23,-675.71"/>
|
||||
<polygon fill="black" stroke="black" points="710.2,-678.61 717.01,-670.5 706.62,-672.6 710.2,-678.61"/>
|
||||
</g>
|
||||
<!-- u33->u22 -->
|
||||
<g id="edge42" class="edge">
|
||||
<title>u33->u22</title>
|
||||
<path fill="none" stroke="black" d="M742,-714.41C742,-705.18 742,-693.59 742,-683.15"/>
|
||||
<polygon fill="black" stroke="black" points="745.5,-682.84 742,-672.84 738.5,-682.84 745.5,-682.84"/>
|
||||
</g>
|
||||
<!-- u34->u0 -->
|
||||
<g id="edge43" class="edge">
|
||||
<title>u34->u0</title>
|
||||
<path fill="none" stroke="black" d="M256.18,-721.27C261.01,-719.01 266.15,-716.68 271,-714.66 321.21,-693.69 336.18,-694.54 386,-672.66 424.95,-655.55 430.98,-643.09 471,-628.66 532.58,-606.45 606.93,-592.27 655.04,-584.64"/>
|
||||
<polygon fill="black" stroke="black" points="655.85,-588.06 665.19,-583.07 654.78,-581.14 655.85,-588.06"/>
|
||||
</g>
|
||||
<!-- u35->u0 -->
|
||||
<g id="edge44" class="edge">
|
||||
<title>u35->u0</title>
|
||||
<path fill="none" stroke="black" d="M342.11,-720.95C409.78,-694.23 586.34,-624.51 665.55,-593.24"/>
|
||||
<polygon fill="black" stroke="black" points="667.14,-596.37 675.16,-589.44 664.57,-589.86 667.14,-596.37"/>
|
||||
</g>
|
||||
<!-- u14 -->
|
||||
<g id="node36" class="node">
|
||||
<title>u14</title>
|
||||
<ellipse fill="#ffffbb" stroke="black" stroke-width="0" cx="934" cy="-495.66" rx="48.19" ry="18"/>
|
||||
<text text-anchor="middle" x="934" y="-491.96" font-family="Times-Roman" font-size="14.00">Platform</text>
|
||||
</g>
|
||||
<!-- u36->u14 -->
|
||||
<g id="edge45" class="edge">
|
||||
<title>u36->u14</title>
|
||||
<path fill="none" stroke="black" d="M1426.01,-716.06C1331.57,-673.94 1071.92,-558.16 972.98,-514.04"/>
|
||||
<polygon fill="black" stroke="black" points="974.21,-510.76 963.65,-509.88 971.36,-517.15 974.21,-510.76"/>
|
||||
</g>
|
||||
<!-- u18 -->
|
||||
<g id="node37" class="node">
|
||||
<title>u18</title>
|
||||
<ellipse fill="#ffffbb" stroke="black" stroke-width="0" cx="1461" cy="-495.66" rx="73.39" ry="18"/>
|
||||
<text text-anchor="middle" x="1461" y="-491.96" font-family="Times-Roman" font-size="14.00">Requirements</text>
|
||||
</g>
|
||||
<!-- u36->u18 -->
|
||||
<g id="edge46" class="edge">
|
||||
<title>u36->u18</title>
|
||||
<path fill="none" stroke="black" d="M1461,-714.38C1461,-673.98 1461,-573.06 1461,-524.13"/>
|
||||
<polygon fill="black" stroke="black" points="1464.5,-523.97 1461,-513.97 1457.5,-523.97 1464.5,-523.97"/>
|
||||
</g>
|
||||
<!-- u37->u0 -->
|
||||
<g id="edge47" class="edge">
|
||||
<title>u37->u0</title>
|
||||
<path fill="none" stroke="black" d="M178.73,-719.04C219.16,-697.17 306.76,-652.29 386,-628.66 478.02,-601.22 589.65,-587.67 653.49,-581.71"/>
|
||||
<polygon fill="black" stroke="black" points="654.05,-585.17 663.7,-580.78 653.42,-578.2 654.05,-585.17"/>
|
||||
</g>
|
||||
<!-- u3 -->
|
||||
<g id="node21" class="node">
|
||||
<title>u3</title>
|
||||
<ellipse fill="#ffffbb" stroke="black" stroke-width="2" cx="1257" cy="-213.66" rx="36.29" ry="18"/>
|
||||
<text text-anchor="middle" x="1257" y="-209.96" font-family="Times-Roman" font-size="14.00">Types</text>
|
||||
</g>
|
||||
<!-- u4 -->
|
||||
<g id="node22" class="node">
|
||||
<title>u4</title>
|
||||
<ellipse fill="#bbffff" stroke="black" stroke-width="0" cx="1329" cy="-291.66" rx="39.79" ry="18"/>
|
||||
<text text-anchor="middle" x="1329" y="-287.96" font-family="Times-Roman" font-size="14.00">Optics</text>
|
||||
</g>
|
||||
<!-- u4->u3 -->
|
||||
<g id="edge48" class="edge">
|
||||
<title>u4->u3</title>
|
||||
<path fill="none" stroke="black" d="M1314.08,-274.91C1303.94,-264.21 1290.37,-249.88 1278.99,-237.88"/>
|
||||
<polygon fill="black" stroke="black" points="1281.32,-235.24 1271.9,-230.39 1276.24,-240.05 1281.32,-235.24"/>
|
||||
</g>
|
||||
<!-- u6 -->
|
||||
<g id="node29" class="node">
|
||||
<title>u6</title>
|
||||
<ellipse fill="#ffbbff" stroke="black" stroke-width="0" cx="934" cy="-380.66" rx="64.19" ry="18"/>
|
||||
<text text-anchor="middle" x="934" y="-376.96" font-family="Times-Roman" font-size="14.00">MegaParsec</text>
|
||||
</g>
|
||||
<!-- u5->u6 -->
|
||||
<g id="edge49" class="edge">
|
||||
<title>u5->u6</title>
|
||||
<path fill="none" stroke="black" d="M1226.6,-309.05C1217.94,-320.06 1204.99,-333.77 1190,-340.66 1152.94,-357.69 1046.95,-346.43 1007,-354.66 997.85,-356.55 988.26,-359.26 979.16,-362.21"/>
|
||||
<polygon fill="black" stroke="black" points="977.86,-358.96 969.51,-365.48 980.11,-365.59 977.86,-358.96"/>
|
||||
</g>
|
||||
<!-- u7 -->
|
||||
<g id="node30" class="node">
|
||||
<title>u7</title>
|
||||
<ellipse fill="#ffbbff" stroke="black" stroke-width="0" cx="1030" cy="-213.66" rx="44.39" ry="18"/>
|
||||
<text text-anchor="middle" x="1030" y="-209.96" font-family="Times-Roman" font-size="14.00">Prelude</text>
|
||||
</g>
|
||||
<!-- u5->u7 -->
|
||||
<g id="edge50" class="edge">
|
||||
<title>u5->u7</title>
|
||||
<path fill="none" stroke="black" d="M1218.91,-276.55C1213.05,-272.65 1206.44,-268.67 1200,-265.66 1160.61,-247.27 1113.01,-233.67 1078.21,-225.15"/>
|
||||
<polygon fill="black" stroke="black" points="1078.83,-221.7 1068.29,-222.78 1077.21,-228.51 1078.83,-221.7"/>
|
||||
</g>
|
||||
<!-- u9 -->
|
||||
<g id="node25" class="node">
|
||||
<title>u9</title>
|
||||
<ellipse fill="#77ff77" stroke="black" stroke-width="0" cx="803" cy="-291.66" rx="51.19" ry="18"/>
|
||||
<text text-anchor="middle" x="803" y="-287.96" font-family="Times-Roman" font-size="14.00">Common</text>
|
||||
</g>
|
||||
<!-- u12->u9 -->
|
||||
<g id="edge59" class="edge">
|
||||
<title>u12->u9</title>
|
||||
<path fill="none" stroke="black" d="M820.65,-362.47C817.58,-350.32 813.4,-333.77 809.87,-319.84"/>
|
||||
<polygon fill="black" stroke="black" points="813.18,-318.65 807.34,-309.81 806.4,-320.37 813.18,-318.65"/>
|
||||
</g>
|
||||
<!-- u9->u7 -->
|
||||
<g id="edge60" class="edge">
|
||||
<title>u9->u7</title>
|
||||
<path fill="none" stroke="black" d="M831.8,-276.66C840.15,-272.85 849.35,-268.89 858,-265.66 899.83,-250.04 948.74,-235.92 983.69,-226.52"/>
|
||||
<polygon fill="black" stroke="black" points="984.85,-229.83 993.61,-223.88 983.05,-223.07 984.85,-229.83"/>
|
||||
</g>
|
||||
<!-- u10 -->
|
||||
<g id="node26" class="node">
|
||||
<title>u10</title>
|
||||
<ellipse fill="#ffff77" stroke="black" stroke-width="0" cx="1030" cy="-53.66" rx="27" ry="18"/>
|
||||
<text text-anchor="middle" x="1030" y="-49.96" font-family="Times-Roman" font-size="14.00">QQ</text>
|
||||
</g>
|
||||
<!-- u16 -->
|
||||
<g id="node27" class="node">
|
||||
<title>u16</title>
|
||||
<ellipse fill="#7777ff" stroke="black" stroke-width="0" cx="629" cy="-380.66" rx="27" ry="18"/>
|
||||
<text text-anchor="middle" x="629" y="-376.96" font-family="Times-Roman" font-size="14.00">QQ</text>
|
||||
</g>
|
||||
<!-- u15->u1 -->
|
||||
<g id="edge51" class="edge">
|
||||
<title>u15->u1</title>
|
||||
<path fill="none" stroke="black" d="M707.32,-398.87C710.83,-417.56 719.45,-446.6 740,-460.66 773.6,-483.65 1065.83,-471.03 1106,-477.66 1109.69,-478.27 1113.47,-479.03 1117.26,-479.89"/>
|
||||
<polygon fill="black" stroke="black" points="1116.67,-483.35 1127.21,-482.36 1118.35,-476.55 1116.67,-483.35"/>
|
||||
</g>
|
||||
<!-- u6->u3 -->
|
||||
<g id="edge52" class="edge">
|
||||
<title>u6->u3</title>
|
||||
<path fill="none" stroke="black" d="M969.52,-365.51C981.28,-361.37 994.54,-357.25 1007,-354.66 1044.76,-346.8 1151.18,-366.3 1180,-340.66 1205.4,-318.06 1177.53,-294.82 1195,-265.66 1202.54,-253.08 1214.35,-242.23 1225.65,-233.81"/>
|
||||
<polygon fill="black" stroke="black" points="1227.95,-236.47 1234.11,-227.86 1223.92,-230.75 1227.95,-236.47"/>
|
||||
</g>
|
||||
<!-- u8 -->
|
||||
<g id="node31" class="node">
|
||||
<title>u8</title>
|
||||
<ellipse fill="#ffbbff" stroke="black" stroke-width="0" cx="1030" cy="-135.66" rx="42.49" ry="18"/>
|
||||
<text text-anchor="middle" x="1030" y="-131.96" font-family="Times-Roman" font-size="14.00">Logger</text>
|
||||
</g>
|
||||
<!-- u7->u8 -->
|
||||
<g id="edge54" class="edge">
|
||||
<title>u7->u8</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M1030,-195.41C1030,-186.18 1030,-174.59 1030,-164.15"/>
|
||||
<polygon fill="black" stroke="black" points="1033.5,-163.84 1030,-153.84 1026.5,-163.84 1033.5,-163.84"/>
|
||||
</g>
|
||||
<!-- u2 -->
|
||||
<g id="node34" class="node">
|
||||
<title>u2</title>
|
||||
<ellipse fill="#ffffbb" stroke="black" stroke-width="0" cx="1128" cy="-291.66" rx="37.89" ry="18"/>
|
||||
<text text-anchor="middle" x="1128" y="-287.96" font-family="Times-Roman" font-size="14.00">Errors</text>
|
||||
</g>
|
||||
<!-- u7->u2 -->
|
||||
<g id="edge53" class="edge">
|
||||
<title>u7->u2</title>
|
||||
<path fill="none" stroke="black" d="M1049.85,-230.05C1064.58,-241.48 1084.85,-257.2 1101.05,-269.76"/>
|
||||
<polygon fill="black" stroke="black" points="1099.06,-272.64 1109.1,-276.01 1103.35,-267.11 1099.06,-272.64"/>
|
||||
</g>
|
||||
<!-- u8->u4 -->
|
||||
<g id="edge55" class="edge">
|
||||
<title>u8->u4</title>
|
||||
<path fill="none" stroke="black" d="M1071.74,-139.12C1139.49,-143.98 1269.17,-157.08 1302,-187.66 1322.76,-207 1328.33,-240.18 1329.47,-263.64"/>
|
||||
<polygon fill="black" stroke="black" points="1325.97,-263.75 1329.71,-273.66 1332.97,-263.58 1325.97,-263.75"/>
|
||||
</g>
|
||||
<!-- u8->u9 -->
|
||||
<g id="edge56" class="edge">
|
||||
<title>u8->u9</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M1008.49,-151.25C968.13,-178.63 880.88,-237.82 834.11,-269.55"/>
|
||||
<polygon fill="black" stroke="black" points="831.91,-266.82 825.6,-275.33 835.84,-272.61 831.91,-266.82"/>
|
||||
</g>
|
||||
<!-- u8->u10 -->
|
||||
<g id="edge57" class="edge">
|
||||
<title>u8->u10</title>
|
||||
<path fill="none" stroke="black" d="M1030,-117.3C1030,-106.96 1030,-93.6 1030,-81.88"/>
|
||||
<polygon fill="black" stroke="black" points="1033.5,-81.71 1030,-71.71 1026.5,-81.71 1033.5,-81.71"/>
|
||||
</g>
|
||||
<!-- u11->u5 -->
|
||||
<g id="edge58" class="edge">
|
||||
<title>u11->u5</title>
|
||||
<path fill="none" stroke="black" d="M1060.4,-365.35C1065.63,-361.25 1071.74,-357.21 1078,-354.66 1124.47,-335.76 1144.94,-362.7 1190,-340.66 1201.46,-335.05 1211.82,-325.6 1219.95,-316.56"/>
|
||||
<polygon fill="black" stroke="black" points="1222.7,-318.72 1226.49,-308.83 1217.36,-314.2 1222.7,-318.72"/>
|
||||
</g>
|
||||
<!-- u0->u16 -->
|
||||
<g id="edge4" class="edge">
|
||||
<title>u0->u16</title>
|
||||
<path fill="none" stroke="black" d="M698.39,-558.78C685.1,-524.87 655.09,-448.27 639.25,-407.82"/>
|
||||
<polygon fill="black" stroke="black" points="642.45,-406.39 635.54,-398.36 635.93,-408.95 642.45,-406.39"/>
|
||||
</g>
|
||||
<!-- u0->u15 -->
|
||||
<g id="edge3" class="edge">
|
||||
<title>u0->u15</title>
|
||||
<path fill="none" stroke="black" d="M705,-558.44C705,-524.72 705,-449.72 705,-409.09"/>
|
||||
<polygon fill="black" stroke="black" points="708.5,-408.84 705,-398.84 701.5,-408.84 708.5,-408.84"/>
|
||||
</g>
|
||||
<!-- u0->u14 -->
|
||||
<g id="edge2" class="edge">
|
||||
<title>u0->u14</title>
|
||||
<path fill="none" stroke="black" d="M736.84,-564.68C776.8,-550.89 845.52,-527.18 890.35,-511.72"/>
|
||||
<polygon fill="black" stroke="black" points="891.51,-515.02 899.82,-508.45 889.22,-508.4 891.51,-515.02"/>
|
||||
</g>
|
||||
<!-- u2->u3 -->
|
||||
<g id="edge5" class="edge">
|
||||
<title>u2->u3</title>
|
||||
<path fill="none" stroke="black" d="M1150.77,-277.25C1171.58,-264.98 1202.56,-246.73 1225.7,-233.1"/>
|
||||
<polygon fill="black" stroke="black" points="1227.62,-236.03 1234.46,-227.94 1224.07,-230 1227.62,-236.03"/>
|
||||
</g>
|
||||
<!-- u13->u3 -->
|
||||
<g id="edge6" class="edge">
|
||||
<title>u13->u3</title>
|
||||
<path fill="none" stroke="black" d="M1412.98,-362.38C1410.65,-337.92 1403.02,-293.12 1378,-265.66 1357.81,-243.49 1326.42,-230.64 1300.67,-223.38"/>
|
||||
<polygon fill="black" stroke="black" points="1301.32,-219.94 1290.76,-220.78 1299.54,-226.71 1301.32,-219.94"/>
|
||||
</g>
|
||||
<!-- u14->u5 -->
|
||||
<g id="edge7" class="edge">
|
||||
<title>u14->u5</title>
|
||||
<path fill="none" stroke="black" d="M980.15,-490.19C1019.57,-485.37 1072.04,-476.2 1086,-460.66 1117.68,-425.38 1065.12,-388.82 1098,-354.66 1126.68,-324.86 1153.09,-359.32 1190,-340.66 1201.39,-334.9 1211.73,-325.43 1219.87,-316.41"/>
|
||||
<polygon fill="black" stroke="black" points="1222.61,-318.59 1226.43,-308.71 1217.28,-314.05 1222.61,-318.59"/>
|
||||
</g>
|
||||
<!-- u14->u12 -->
|
||||
<g id="edge8" class="edge">
|
||||
<title>u14->u12</title>
|
||||
<path fill="none" stroke="black" d="M895.43,-484.64C881.53,-479.41 866.66,-471.72 856,-460.66 842.29,-446.43 834.43,-425.42 830.06,-408.64"/>
|
||||
<polygon fill="black" stroke="black" points="833.46,-407.78 827.77,-398.84 826.64,-409.37 833.46,-407.78"/>
|
||||
</g>
|
||||
<!-- u18->u5 -->
|
||||
<g id="edge10" class="edge">
|
||||
<title>u18->u5</title>
|
||||
<path fill="none" stroke="black" d="M1468.63,-477.37C1480.29,-447.97 1498.11,-388.19 1467,-354.66 1438.65,-324.11 1317.28,-359.28 1280,-340.66 1269.49,-335.41 1260.48,-326.27 1253.53,-317.36"/>
|
||||
<polygon fill="black" stroke="black" points="1256.2,-315.09 1247.51,-309.03 1250.53,-319.18 1256.2,-315.09"/>
|
||||
</g>
|
||||
<!-- u18->u13 -->
|
||||
<g id="edge9" class="edge">
|
||||
<title>u18->u13</title>
|
||||
<path fill="none" stroke="black" d="M1453.86,-477.5C1446.19,-459.06 1433.9,-429.51 1425,-408.1"/>
|
||||
<polygon fill="black" stroke="black" points="1428.12,-406.5 1421.05,-398.61 1421.66,-409.19 1428.12,-406.5"/>
|
||||
</g>
|
||||
<!-- u20 -->
|
||||
<g id="node38" class="node">
|
||||
<title>u20</title>
|
||||
<ellipse fill="#bbffbb" stroke="black" stroke-width="0" cx="742" cy="-925.66" rx="32.49" ry="18"/>
|
||||
<text text-anchor="middle" x="742" y="-921.96" font-family="Times-Roman" font-size="14.00">Main</text>
|
||||
</g>
|
||||
<!-- u20->u21 -->
|
||||
<g id="edge1" class="edge">
|
||||
<title>u20->u21</title>
|
||||
<path fill="none" stroke="black" d="M742,-907.5C742,-889.33 742,-860.38 742,-839.05"/>
|
||||
<polygon fill="black" stroke="black" points="745.5,-838.98 742,-828.98 738.5,-838.98 745.5,-838.98"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 33 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 |
201
docs/overrides/base.html
Normal file
@@ -0,0 +1,201 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{ config.theme.locale|default('en') }}">
|
||||
<head>
|
||||
{%- block site_meta %}
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
{% if page and page.is_homepage %}<meta name="description" content="{{ config['site_description'] }}">{% endif %}
|
||||
{% if config.site_author %}<meta name="author" content="{{ config.site_author }}">{% endif %}
|
||||
{% if page and page.canonical_url %}<link rel="canonical" href="{{ page.canonical_url }}">{% endif %}
|
||||
{% if config.site_favicon %}<link rel="shortcut icon" href="{{ config.site_favicon|url }}">
|
||||
{% else %}<link rel="shortcut icon" href="{{ 'img/favicon.ico'|url }}">{% endif %}
|
||||
{%- endblock %}
|
||||
|
||||
{%- block htmltitle %}
|
||||
<title>{% if page and page.title and not page.is_homepage %}{{ page.title }} - {% endif %}{{ config.site_name }}</title>
|
||||
{%- endblock %}
|
||||
|
||||
{%- block styles %}
|
||||
<link href="{{ 'css/bootstrap.min.css'|url }}" rel="stylesheet">
|
||||
<link href="{{ 'css/font-awesome.min.css'|url }}" rel="stylesheet">
|
||||
<link href="{{ 'css/base.css'|url }}" rel="stylesheet">
|
||||
{%- if config.theme.highlightjs %}
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.5.0/styles/{{ config.theme.hljs_style }}.min.css">
|
||||
{%- endif %}
|
||||
{%- for path in extra_css %}
|
||||
<link href="{{ path }}" rel="stylesheet">
|
||||
{%- endfor %}
|
||||
{%- endblock %}
|
||||
|
||||
{%- block libs %}
|
||||
|
||||
<script src="{{ 'js/jquery-1.10.2.min.js'|url }}" defer></script>
|
||||
<script src="{{ 'js/bootstrap.min.js'|url }}" defer></script>
|
||||
{%- if config.theme.highlightjs %}
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.5.0/highlight.min.js"></script>
|
||||
{%- for lang in config.theme.hljs_languages %}
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.5.0/languages/{{lang}}.min.js"></script>
|
||||
{%- endfor %}
|
||||
<script>hljs.initHighlightingOnLoad();</script>
|
||||
{%- endif %}
|
||||
{%- endblock %}
|
||||
|
||||
{%- block analytics %}
|
||||
{%- if config.theme.analytics.gtag %}
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id={{ config.theme.analytics.gtag }}"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', '{{ config.theme.analytics.gtag }}');
|
||||
</script>
|
||||
{%- elif config.google_analytics %}
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', '{{ config.google_analytics[0] }}', '{{ config.google_analytics[1] }}');
|
||||
ga('send', 'pageview');
|
||||
</script>
|
||||
{%- endif %}
|
||||
{%- endblock %}
|
||||
|
||||
{%- block extrahead %} {% endblock %}
|
||||
</head>
|
||||
|
||||
<body{% if page and page.is_homepage %} class="homepage"{% endif %}>
|
||||
<div class="navbar fixed-top navbar-expand-lg navbar-{% if config.theme.nav_style == "light" %}light{% else %}dark{% endif %} bg-{{ config.theme.nav_style }}">
|
||||
<div class="container">
|
||||
|
||||
{%- block site_name %}
|
||||
<a class="navbar-brand" href="{{ nav.homepage.url|url }}">{{ config.site_name }}</a>
|
||||
{%- endblock %}
|
||||
|
||||
{%- if nav|length>1 or (page and (page.next_page or page.previous_page)) or config.repo_url %}
|
||||
<!-- Expander button -->
|
||||
<button type="button" class="navbar-toggler" data-toggle="collapse" data-target="#navbar-collapse">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
{%- endif %}
|
||||
|
||||
<!-- Expanded navigation -->
|
||||
<div id="navbar-collapse" class="navbar-collapse collapse">
|
||||
{%- block site_nav %}
|
||||
{%- if nav|length>1 %}
|
||||
<!-- Main navigation -->
|
||||
<ul class="nav navbar-nav">
|
||||
{%- for nav_item in nav %}
|
||||
{%- if nav_item.children %}
|
||||
<li class="dropdown{% if nav_item.active %} active{% endif %}">
|
||||
<a href="#" class="nav-link dropdown-toggle" data-toggle="dropdown">{{ nav_item.title }} <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
{%- for nav_item in nav_item.children %}
|
||||
{% include "nav-sub.html" %}
|
||||
{%- endfor %}
|
||||
</ul>
|
||||
</li>
|
||||
{%- else %}
|
||||
<li class="navitem{% if nav_item.active %} active{% endif %}">
|
||||
<a href="{{ nav_item.url|url }}" class="nav-link">{{ nav_item.title }}</a>
|
||||
</li>
|
||||
{%- endif %}
|
||||
{%- endfor %}
|
||||
</ul>
|
||||
{%- endif %}
|
||||
{%- endblock %}
|
||||
|
||||
<ul class="nav navbar-nav ml-auto">
|
||||
{%- block search_button %}
|
||||
{%- if 'search' in config['plugins'] %}
|
||||
<li class="nav-item">
|
||||
<a href="#" class="nav-link" data-toggle="modal" data-target="#mkdocs_search_modal">
|
||||
<i class="fa fa-search"></i> {% trans %}Search{% endtrans %}
|
||||
</a>
|
||||
</li>
|
||||
{%- endif %}
|
||||
{%- endblock %}
|
||||
|
||||
{%- block next_prev %}
|
||||
{%- endblock %}
|
||||
|
||||
{%- block repo %}
|
||||
{%- if page and page.edit_url %}
|
||||
<li class="nav-item">
|
||||
<a href="{{ page.edit_url }}" class="nav-link">
|
||||
{%- if config.repo_name == 'GitHub' -%}
|
||||
<i class="fa fa-github"></i> {% trans repo_name=config.repo_name %}Edit on {{ repo_name }}{% endtrans %}
|
||||
{%- elif config.repo_name == 'Bitbucket' -%}
|
||||
<i class="fa fa-bitbucket"></i> {% trans repo_name=config.repo_name %}Edit on {{ repo_name }}{% endtrans %}
|
||||
{%- elif config.repo_name == 'GitLab' -%}
|
||||
<i class="fa fa-gitlab"></i> {% trans repo_name=config.repo_name %}Edit on {{ repo_name }}{% endtrans %}
|
||||
{%- else -%}
|
||||
{% trans repo_name=config.repo_name%}Edit on {{ repo_name }}{% endtrans %}
|
||||
{%- endif -%}
|
||||
</a>
|
||||
</li>
|
||||
{%- elif config.repo_url %}
|
||||
<li class="nav-item">
|
||||
<a href="{{ config.repo_url }}" class="nav-link">
|
||||
{%- if config.repo_name == 'GitHub' -%}
|
||||
<i class="fa fa-github"></i> {{ config.repo_name }}
|
||||
{%- elif config.repo_name == 'Bitbucket' -%}
|
||||
<i class="fa fa-bitbucket"></i> {{ config.repo_name }}
|
||||
{%- elif config.repo_name == 'GitLab' -%}
|
||||
<i class="fa fa-gitlab"></i> {{ config.repo_name }}
|
||||
{%- else -%}
|
||||
{{ config.repo_name }}
|
||||
{%- endif -%}
|
||||
</a>
|
||||
</li>
|
||||
{%- endif %}
|
||||
{%- endblock %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
{%- block content %}
|
||||
<div class="col-md-3">{% include "toc.html" %}</div>
|
||||
<div class="col-md-9" role="main">{% include "content.html" %}</div>
|
||||
{%- endblock %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer class="col-md-12">
|
||||
{%- block footer %}
|
||||
<hr>
|
||||
{%- if config.copyright %}
|
||||
<p>{{ config.copyright }}</p>
|
||||
{%- endif %}
|
||||
<p>{% trans mkdocs_link='<a href="https://www.mkdocs.org/">MkDocs</a>' %}Documentation built with {{ mkdocs_link }}.{% endtrans %}</p>
|
||||
{%- endblock %}
|
||||
</footer>
|
||||
|
||||
{%- block scripts %}
|
||||
<script>
|
||||
var base_url = {{ base_url | tojson }},
|
||||
shortcuts = {{ config.theme.shortcuts | tojson }};
|
||||
</script>
|
||||
<script src="{{ 'js/base.js'|url }}" defer></script>
|
||||
{%- for path in extra_javascript %}
|
||||
<script src="{{ path }}" defer></script>
|
||||
{%- endfor %}
|
||||
{%- endblock %}
|
||||
|
||||
{% if 'search' in config['plugins'] %}{%- include "search-modal.html" %}{% endif %}
|
||||
{%- include "keyboard-modal.html" %}
|
||||
|
||||
</body>
|
||||
</html>
|
||||
{% if page and page.is_homepage %}
|
||||
<!--
|
||||
MkDocs version : {{ mkdocs_version }}
|
||||
Build Date UTC : {{ build_date_utc }}
|
||||
-->
|
||||
{% endif %}
|
||||
519
ghcup.cabal
@@ -1,234 +1,311 @@
|
||||
cabal-version: 2.2
|
||||
cabal-version: 3.0
|
||||
name: ghcup
|
||||
version: 0.1.17.3
|
||||
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.
|
||||
|
||||
name: ghcup
|
||||
version: 0.1.0.0
|
||||
synopsis: ghc toolchain installer as an exe/library
|
||||
description: A rewrite of the shell script ghcup, for providing
|
||||
a more stable user experience and exposing an API.
|
||||
homepage: https://github.com/hasufell/ghcup-hs
|
||||
bug-reports: https://github.com/hasufell/ghcup-hs/issues
|
||||
license: LGPL-3.0-only
|
||||
license-file: LICENSE
|
||||
author: Julian Ospald
|
||||
maintainer: hasufell@posteo.de
|
||||
copyright: Julian Ospald 2020
|
||||
category: System
|
||||
build-type: Simple
|
||||
extra-source-files: CHANGELOG.md
|
||||
category: System
|
||||
build-type: Simple
|
||||
extra-doc-files:
|
||||
CHANGELOG.md
|
||||
data/config.yaml
|
||||
README.md
|
||||
|
||||
extra-source-files:
|
||||
data/build_mk/cross
|
||||
data/build_mk/default
|
||||
test/golden/GHCupInfo.json
|
||||
|
||||
source-repository head
|
||||
type: git
|
||||
location: https://github.com/hasufell/ghcup-hs
|
||||
type: git
|
||||
location: https://gitlab.haskell.org/haskell/ghcup-hs.git
|
||||
|
||||
common HsOpenSSL { build-depends: HsOpenSSL >= 0.11 }
|
||||
common aeson { build-depends: aeson >= 1.4 }
|
||||
common aeson-pretty { build-depends: aeson-pretty >= 0.8.8 }
|
||||
common ascii-string { build-depends: ascii-string >= 1.0 }
|
||||
common async { build-depends: async >= 0.8 }
|
||||
common attoparsec { build-depends: attoparsec >= 0.13 }
|
||||
common base { build-depends: base >= 4.12 && < 5 }
|
||||
common binary { build-depends: binary >= 0.8.6.0 }
|
||||
common bytestring { build-depends: bytestring >= 0.10 }
|
||||
common bzlib { build-depends: bzlib >= 0.5.0.5 }
|
||||
common case-insensitive { build-depends: case-insensitive >= 1.2.1.0 }
|
||||
common containers { build-depends: containers >= 0.6 }
|
||||
common generics-sop { build-depends: generics-sop >= 0.5 }
|
||||
common haskus-utils-types { build-depends: haskus-utils-types >= 1.5 }
|
||||
common haskus-utils-variant { build-depends: haskus-utils-variant >= 3.0 }
|
||||
common hopenssl { build-depends: hopenssl >= 2.2.4 }
|
||||
common hpath { build-depends: hpath >= 0.11 }
|
||||
common hpath-directory { build-depends: hpath-directory >= 0.13.2 }
|
||||
common hpath-filepath { build-depends: hpath-filepath >= 0.10.3 }
|
||||
common hpath-io { build-depends: hpath-io >= 0.13.1 }
|
||||
common hpath-posix { build-depends: hpath-posix >= 0.11.1 }
|
||||
common http-io-streams { build-depends: http-io-streams >= 0.1.2.0 }
|
||||
common io-streams { build-depends: io-streams >= 1.5 }
|
||||
common language-bash { build-depends: language-bash >= 0.9 }
|
||||
common lzma { build-depends: lzma >= 0.0.0.3 }
|
||||
common monad-logger { build-depends: monad-logger >= 0.3.31 }
|
||||
common mtl { build-depends: mtl >= 2.2 }
|
||||
common optics { build-depends: optics >= 0.2 }
|
||||
common optics-vl { build-depends: optics-vl >= 0.2 }
|
||||
common optparse-applicative { build-depends: optparse-applicative >= 0.15.1.0 }
|
||||
common parsec { build-depends: parsec >= 3.1 }
|
||||
common pretty-terminal { build-depends: pretty-terminal >= 0.1.0.0 }
|
||||
common resourcet { build-depends: resourcet >= 1.2.2 }
|
||||
common safe { build-depends: safe >= 0.3.18 }
|
||||
common safe-exceptions { build-depends: safe-exceptions >= 0.1 }
|
||||
common streamly { build-depends: streamly >= 0.7.1 }
|
||||
common streamly-posix { build-depends: streamly-posix >= 0.1.0.0 }
|
||||
common streamly-bytestring { build-depends: streamly-bytestring >= 0.1.2 }
|
||||
common strict-base { build-depends: strict-base >= 0.4 }
|
||||
common string-interpolate { build-depends: string-interpolate >= 0.2.0.0 }
|
||||
common table-layout { build-depends: table-layout >= 0.8 }
|
||||
common tar-bytestring { build-depends: tar-bytestring >= 0.6.3.0 }
|
||||
common template-haskell { build-depends: template-haskell >= 2.7 }
|
||||
common terminal-progress-bar { build-depends: terminal-progress-bar >= 0.4.1 }
|
||||
common text { build-depends: text >= 1.2 }
|
||||
common text-icu { build-depends: text-icu >= 0.7 }
|
||||
common time { build-depends: time >= 1.9.3 }
|
||||
common transformers { build-depends: transformers >= 0.5 }
|
||||
common unix { build-depends: unix >= 2.7 }
|
||||
common unix-bytestring { build-depends: unix-bytestring >= 0.3 }
|
||||
common uri-bytestring { build-depends: uri-bytestring >= 0.3.2.2 }
|
||||
common utf8-string { build-depends: utf8-string >= 1.0 }
|
||||
common vector { build-depends: vector >= 0.12 }
|
||||
common versions { build-depends: versions >= 3.5 }
|
||||
common waargonaut { build-depends: waargonaut >= 0.8 }
|
||||
common word8 { build-depends: word8 >= 0.1.3 }
|
||||
common zlib { build-depends: zlib >= 0.6.2.1 }
|
||||
flag tui
|
||||
description:
|
||||
Build the brick powered tui (ghcup tui). This is disabled on windows.
|
||||
|
||||
default: False
|
||||
manual: True
|
||||
|
||||
common config
|
||||
default-language: Haskell2010
|
||||
ghc-options: -Wall -fwarn-tabs -fwarn-incomplete-uni-patterns -fwarn-incomplete-record-updates -threaded
|
||||
default-extensions: LambdaCase
|
||||
, MultiWayIf
|
||||
, PackageImports
|
||||
, RecordWildCards
|
||||
, ScopedTypeVariables
|
||||
, StrictData
|
||||
, Strict
|
||||
, TupleSections
|
||||
flag internal-downloader
|
||||
description:
|
||||
Compile the internal downloader, which links against OpenSSL. This is disabled on windows.
|
||||
|
||||
default: False
|
||||
manual: True
|
||||
|
||||
flag no-exe
|
||||
description: Don't build any executables
|
||||
default: False
|
||||
manual: True
|
||||
|
||||
library
|
||||
import: config
|
||||
, base
|
||||
-- deps
|
||||
, HsOpenSSL
|
||||
, aeson
|
||||
, ascii-string
|
||||
, async
|
||||
, attoparsec
|
||||
, binary
|
||||
, bytestring
|
||||
, bzlib
|
||||
, case-insensitive
|
||||
, containers
|
||||
, generics-sop
|
||||
, haskus-utils-types
|
||||
, haskus-utils-variant
|
||||
, hopenssl
|
||||
, hpath
|
||||
, hpath-directory
|
||||
, hpath-filepath
|
||||
, hpath-io
|
||||
, hpath-posix
|
||||
, http-io-streams
|
||||
, io-streams
|
||||
, language-bash
|
||||
, lzma
|
||||
, monad-logger
|
||||
, mtl
|
||||
, optics
|
||||
, optics-vl
|
||||
, parsec
|
||||
, pretty-terminal
|
||||
, resourcet
|
||||
, safe
|
||||
, safe-exceptions
|
||||
, streamly
|
||||
, streamly-posix
|
||||
, streamly-bytestring
|
||||
, strict-base
|
||||
, string-interpolate
|
||||
, tar-bytestring
|
||||
, template-haskell
|
||||
, terminal-progress-bar
|
||||
, text
|
||||
, text-icu
|
||||
, time
|
||||
, transformers
|
||||
, unix
|
||||
, unix-bytestring
|
||||
, uri-bytestring
|
||||
, utf8-string
|
||||
, vector
|
||||
, versions
|
||||
, word8
|
||||
, zlib
|
||||
exposed-modules: GHCup
|
||||
GHCup.Download
|
||||
GHCup.Errors
|
||||
GHCup.Platform
|
||||
GHCup.Types
|
||||
GHCup.Types.JSON
|
||||
GHCup.Types.Optics
|
||||
GHCup.Utils
|
||||
GHCup.Utils.Bash
|
||||
GHCup.Utils.Dirs
|
||||
GHCup.Utils.File
|
||||
GHCup.Utils.Logger
|
||||
GHCup.Utils.Prelude
|
||||
GHCup.Utils.String.QQ
|
||||
GHCup.Utils.Version.QQ
|
||||
GHCup.Version
|
||||
-- other-modules:
|
||||
-- other-extensions:
|
||||
hs-source-dirs: lib
|
||||
exposed-modules:
|
||||
GHCup
|
||||
GHCup.Data.Versions
|
||||
GHCup.GHC
|
||||
GHCup.GHC.Rm
|
||||
GHCup.GHC.Unset
|
||||
GHCup.GHC.Set
|
||||
GHCup.GHC.Compile
|
||||
GHCup.GHC.Common
|
||||
GHCup.GHC.Install
|
||||
GHCup.Download
|
||||
GHCup.Download.Common
|
||||
GHCup.Errors
|
||||
GHCup.Platform
|
||||
GHCup.Requirements
|
||||
GHCup.Types
|
||||
GHCup.Types.JSON
|
||||
GHCup.Types.Optics
|
||||
GHCup.Utils
|
||||
GHCup.Directories
|
||||
GHCup.System.Process
|
||||
GHCup.System.Directory
|
||||
GHCup.System.Process.Common
|
||||
GHCup.System.Console
|
||||
GHCup.Logger
|
||||
GHCup.MegaParsec
|
||||
GHCup.Prelude
|
||||
GHCup.QQ.String
|
||||
GHCup.QQ.Version
|
||||
GHCup.Version
|
||||
|
||||
hs-source-dirs: lib
|
||||
other-modules: Paths_ghcup
|
||||
autogen-modules: Paths_ghcup
|
||||
default-language: Haskell2010
|
||||
default-extensions:
|
||||
DeriveGeneric
|
||||
LambdaCase
|
||||
MultiWayIf
|
||||
NamedFieldPuns
|
||||
PackageImports
|
||||
QuasiQuotes
|
||||
RecordWildCards
|
||||
ScopedTypeVariables
|
||||
StrictData
|
||||
TupleSections
|
||||
TypeApplications
|
||||
TypeFamilies
|
||||
ViewPatterns
|
||||
|
||||
ghc-options:
|
||||
-Wall -fwarn-tabs -fwarn-incomplete-uni-patterns
|
||||
-fwarn-incomplete-record-updates
|
||||
|
||||
build-depends:
|
||||
, aeson >=1.4
|
||||
, async >=0.8 && <2.3
|
||||
, base >=4.12 && <5
|
||||
, 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
|
||||
, 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
|
||||
, filepath ^>=1.4.2.1
|
||||
, haskus-utils-types ^>=1.5
|
||||
, haskus-utils-variant >=3.0 && <3.2
|
||||
, libarchive ^>=3.0.3.0
|
||||
, lzma-static ^>=5.2.5.3
|
||||
, megaparsec >=8.0.0 && <9.1
|
||||
, mtl ^>=2.2
|
||||
, optics ^>=0.4
|
||||
, os-release ^>=1.0.0
|
||||
, pretty ^>=1.1.3.1
|
||||
, pretty-terminal ^>=0.1.0.0
|
||||
, regex-posix ^>=0.96
|
||||
, resourcet ^>=1.2.2
|
||||
, retry ^>=0.8.1.2
|
||||
, safe ^>=0.3.18
|
||||
, safe-exceptions ^>=0.1
|
||||
, split ^>=0.2.3.4
|
||||
, strict-base ^>=0.4
|
||||
, template-haskell >=2.7 && <2.18
|
||||
, temporary ^>=1.3
|
||||
, text ^>=1.2.4.0
|
||||
, time ^>=1.9.3
|
||||
, transformers ^>=0.5
|
||||
, unliftio-core ^>=0.2.0.1
|
||||
, unordered-containers ^>=0.2.10.0
|
||||
, uri-bytestring ^>=0.3.2.2
|
||||
, vector ^>=0.12
|
||||
, versions >=4.0.1 && <5.1
|
||||
, word8 ^>=0.1.3
|
||||
, yaml-streamly ^>=0.12.0
|
||||
, zlib ^>=0.6.2.2
|
||||
|
||||
if (flag(internal-downloader) && !os(windows))
|
||||
exposed-modules: GHCup.Download.IOStreams
|
||||
cpp-options: -DINTERNAL_DOWNLOADER
|
||||
build-depends:
|
||||
, HsOpenSSL >=0.11.4.18
|
||||
, http-io-streams >=0.1.2.0
|
||||
, io-streams >=1.5.2.1
|
||||
, terminal-progress-bar >=0.4.1
|
||||
|
||||
if os(windows)
|
||||
cpp-options: -DIS_WINDOWS
|
||||
other-modules:
|
||||
GHCup.System.Process.Windows
|
||||
GHCup.Prelude.Windows
|
||||
GHCup.System.Console.Windows
|
||||
|
||||
build-depends:
|
||||
, bzlib
|
||||
, process ^>=1.6.11.0
|
||||
, Win32 ^>=2.10
|
||||
|
||||
else
|
||||
other-modules:
|
||||
GHCup.System.Process.Posix
|
||||
GHCup.System.Console.Posix
|
||||
GHCup.Prelude.Posix
|
||||
System.Console.Terminal.Common
|
||||
System.Console.Terminal.Posix
|
||||
|
||||
build-depends:
|
||||
, bz2 >=0.5.0.5 && <1.1
|
||||
, unix ^>=2.7
|
||||
, unix-bytestring ^>=0.3.7.3
|
||||
|
||||
if (flag(tui) && !os(windows))
|
||||
cpp-options: -DBRICK
|
||||
build-depends: vty >=5.28.2 && <5.34
|
||||
|
||||
executable ghcup
|
||||
import: config
|
||||
, base
|
||||
--
|
||||
, bytestring
|
||||
, containers
|
||||
, haskus-utils-variant
|
||||
, monad-logger
|
||||
, mtl
|
||||
, optparse-applicative
|
||||
, text
|
||||
, versions
|
||||
, hpath
|
||||
, hpath-io
|
||||
, pretty-terminal
|
||||
, resourcet
|
||||
, string-interpolate
|
||||
, table-layout
|
||||
, uri-bytestring
|
||||
, utf8-string
|
||||
main-is: Main.hs
|
||||
-- other-modules:
|
||||
-- other-extensions:
|
||||
build-depends: ghcup
|
||||
hs-source-dirs: app/ghcup
|
||||
default-language: Haskell2010
|
||||
main-is: Main.hs
|
||||
other-modules:
|
||||
GHCup.OptParse
|
||||
GHCup.OptParse.ChangeLog
|
||||
GHCup.OptParse.Common
|
||||
GHCup.OptParse.Compile
|
||||
GHCup.OptParse.Config
|
||||
GHCup.OptParse.DInfo
|
||||
GHCup.OptParse.GC
|
||||
GHCup.OptParse.Install
|
||||
GHCup.OptParse.List
|
||||
GHCup.OptParse.Nuke
|
||||
GHCup.OptParse.Prefetch
|
||||
GHCup.OptParse.Rm
|
||||
GHCup.OptParse.Set
|
||||
GHCup.OptParse.ToolRequirements
|
||||
GHCup.OptParse.UnSet
|
||||
GHCup.OptParse.Upgrade
|
||||
GHCup.OptParse.Whereis
|
||||
|
||||
executable ghcup-gen
|
||||
import: config
|
||||
, base
|
||||
--
|
||||
, aeson
|
||||
, aeson-pretty
|
||||
, bytestring
|
||||
, containers
|
||||
, safe-exceptions
|
||||
, haskus-utils-variant
|
||||
, monad-logger
|
||||
, mtl
|
||||
, optics
|
||||
, optparse-applicative
|
||||
, text
|
||||
, versions
|
||||
, hpath
|
||||
, pretty-terminal
|
||||
, resourcet
|
||||
, string-interpolate
|
||||
, table-layout
|
||||
, transformers
|
||||
, uri-bytestring
|
||||
, utf8-string
|
||||
main-is: Main.hs
|
||||
other-modules: GHCupDownloads
|
||||
Validate
|
||||
-- other-extensions:
|
||||
build-depends: ghcup
|
||||
hs-source-dirs: app/ghcup-gen
|
||||
default-language: Haskell2010
|
||||
hs-source-dirs: app/ghcup
|
||||
default-language: Haskell2010
|
||||
default-extensions:
|
||||
LambdaCase
|
||||
MultiWayIf
|
||||
NamedFieldPuns
|
||||
PackageImports
|
||||
RecordWildCards
|
||||
ScopedTypeVariables
|
||||
StrictData
|
||||
TupleSections
|
||||
|
||||
ghc-options:
|
||||
-Wall -fwarn-tabs -fwarn-incomplete-uni-patterns
|
||||
-fwarn-incomplete-record-updates -threaded
|
||||
|
||||
build-depends:
|
||||
, aeson >=1.4
|
||||
, aeson-pretty ^>=0.8.8
|
||||
, async ^>=2.2.3
|
||||
, base >=4.12 && <5
|
||||
, bytestring ^>=0.10
|
||||
, cabal-plan ^>=0.7.2
|
||||
, containers ^>=0.6
|
||||
, deepseq ^>=1.4
|
||||
, directory ^>=1.3.6.0
|
||||
, filepath ^>=1.4.2.1
|
||||
, ghcup
|
||||
, haskus-utils-variant >=3.0 && <3.2
|
||||
, libarchive ^>=3.0.3.0
|
||||
, megaparsec >=8.0.0 && <9.1
|
||||
, mtl ^>=2.2
|
||||
, optparse-applicative-fork >=0.15.1.0 && <0.17
|
||||
, pretty ^>=1.1.3.1
|
||||
, pretty-terminal ^>=0.1.0.0
|
||||
, resourcet ^>=1.2.2
|
||||
, safe ^>=0.3.18
|
||||
, safe-exceptions ^>=0.1
|
||||
, 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 && <5.1
|
||||
, yaml-streamly ^>=0.12.0
|
||||
|
||||
if flag(internal-downloader)
|
||||
cpp-options: -DINTERNAL_DOWNLOADER
|
||||
|
||||
if (flag(tui) && !os(windows))
|
||||
cpp-options: -DBRICK
|
||||
other-modules: BrickMain
|
||||
build-depends:
|
||||
, brick ^>=0.64
|
||||
, transformers ^>=0.5
|
||||
, unix ^>=2.7
|
||||
, vector ^>=0.12
|
||||
, vty >=5.28.2 && <5.34
|
||||
|
||||
if os(windows)
|
||||
cpp-options: -DIS_WINDOWS
|
||||
|
||||
if flag(no-exe)
|
||||
buildable: False
|
||||
|
||||
test-suite ghcup-test
|
||||
default-language: Haskell2010
|
||||
type: exitcode-stdio-1.0
|
||||
hs-source-dirs: test
|
||||
main-is: MyLibTest.hs
|
||||
build-depends: base ^>=4.12.0.0
|
||||
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
|
||||
GHCup.Types.JSONSpec
|
||||
Spec
|
||||
|
||||
default-language: Haskell2010
|
||||
default-extensions:
|
||||
LambdaCase
|
||||
MultiWayIf
|
||||
PackageImports
|
||||
RecordWildCards
|
||||
ScopedTypeVariables
|
||||
TupleSections
|
||||
|
||||
ghc-options:
|
||||
-Wall -fwarn-tabs -fwarn-incomplete-uni-patterns
|
||||
-fwarn-incomplete-record-updates
|
||||
|
||||
build-depends:
|
||||
, base >=4.12 && <5
|
||||
, bytestring ^>=0.10
|
||||
, containers ^>=0.6
|
||||
, generic-arbitrary ^>=0.1.0
|
||||
, ghcup
|
||||
, hspec ^>=2.7.10
|
||||
, hspec-golden-aeson ^>=0.9
|
||||
, QuickCheck ^>=2.14.1
|
||||
, quickcheck-arbitrary-adt ^>=0.3.1.0
|
||||
, text ^>=1.2.4.0
|
||||
, uri-bytestring ^>=0.3.2.2
|
||||
, versions >=4.0.1 && <5.1
|
||||
|
||||
8
hie.yaml
Normal file
@@ -0,0 +1,8 @@
|
||||
cradle:
|
||||
cabal:
|
||||
- component: "ghcup:lib:ghcup"
|
||||
path: ./lib
|
||||
- component: "ghcup:exe:ghcup"
|
||||
path: ./app/ghcup
|
||||
- component: "ghcup:test:ghcup-test"
|
||||
path: ./test
|
||||
2239
lib/GHCup.hs
346
lib/GHCup/Directories.hs
Normal file
@@ -0,0 +1,346 @@
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE ViewPatterns #-}
|
||||
|
||||
{-|
|
||||
Module : GHCup.Directories
|
||||
Description : Definition of GHCup directories
|
||||
Copyright : (c) Julian Ospald, 2020
|
||||
License : LGPL-3.0
|
||||
Maintainer : hasufell@hasufell.de
|
||||
Stability : experimental
|
||||
Portability : portable
|
||||
-}
|
||||
module GHCup.Directories
|
||||
( getAllDirs
|
||||
, ghcupBaseDir
|
||||
, ghcupConfigFile
|
||||
, ghcupCacheDir
|
||||
, ghcupGHCBaseDir
|
||||
, ghcupGHCDir
|
||||
, mkGhcupTmpDir
|
||||
, parseGHCupGHCDir
|
||||
, relativeSymlink
|
||||
, withGHCupTmpDir
|
||||
, getConfigFilePath
|
||||
, useXDG
|
||||
, cleanupTrash
|
||||
)
|
||||
where
|
||||
|
||||
|
||||
import GHCup.Errors
|
||||
import GHCup.Types
|
||||
import GHCup.Types.JSON ( )
|
||||
import GHCup.Types.Optics
|
||||
import GHCup.MegaParsec
|
||||
import GHCup.Logger
|
||||
import GHCup.Prelude
|
||||
|
||||
import Control.Exception.Safe
|
||||
import Control.Monad
|
||||
import Control.Monad.IO.Unlift
|
||||
import Control.Monad.Reader
|
||||
import Control.Monad.Trans.Resource hiding (throwM)
|
||||
import Data.Bifunctor
|
||||
import Data.Maybe
|
||||
import GHC.IO.Exception ( IOErrorType(NoSuchThing) )
|
||||
import Haskus.Utils.Variant.Excepts
|
||||
import Optics
|
||||
import System.Directory
|
||||
import System.DiskSpace
|
||||
import System.Environment
|
||||
import System.FilePath
|
||||
import System.IO.Temp
|
||||
|
||||
import qualified Data.ByteString as BS
|
||||
import qualified Data.Text as T
|
||||
import qualified Data.Yaml.Aeson as Y
|
||||
import qualified Text.Megaparsec as MP
|
||||
import Control.Concurrent (threadDelay)
|
||||
|
||||
|
||||
|
||||
------------------------------
|
||||
--[ GHCup base directories ]--
|
||||
------------------------------
|
||||
|
||||
|
||||
-- | ~/.ghcup by default
|
||||
--
|
||||
-- If 'GHCUP_USE_XDG_DIRS' is set (to anything),
|
||||
-- then uses 'XDG_DATA_HOME/ghcup' as per xdg spec.
|
||||
ghcupBaseDir :: IO FilePath
|
||||
ghcupBaseDir
|
||||
| isWindows = do
|
||||
bdir <- fromMaybe "C:\\" <$> lookupEnv "GHCUP_INSTALL_BASE_PREFIX"
|
||||
pure (bdir </> "ghcup")
|
||||
| otherwise = do
|
||||
xdg <- useXDG
|
||||
if xdg
|
||||
then do
|
||||
bdir <- lookupEnv "XDG_DATA_HOME" >>= \case
|
||||
Just r -> pure r
|
||||
Nothing -> do
|
||||
home <- liftIO getHomeDirectory
|
||||
pure (home </> ".local" </> "share")
|
||||
pure (bdir </> "ghcup")
|
||||
else do
|
||||
bdir <- lookupEnv "GHCUP_INSTALL_BASE_PREFIX" >>= \case
|
||||
Just r -> pure r
|
||||
Nothing -> liftIO getHomeDirectory
|
||||
pure (bdir </> ".ghcup")
|
||||
|
||||
|
||||
-- | ~/.ghcup by default
|
||||
--
|
||||
-- If 'GHCUP_USE_XDG_DIRS' is set (to anything),
|
||||
-- then uses 'XDG_CONFIG_HOME/ghcup' as per xdg spec.
|
||||
ghcupConfigDir :: IO FilePath
|
||||
ghcupConfigDir
|
||||
| isWindows = ghcupBaseDir
|
||||
| otherwise = do
|
||||
xdg <- useXDG
|
||||
if xdg
|
||||
then do
|
||||
bdir <- lookupEnv "XDG_CONFIG_HOME" >>= \case
|
||||
Just r -> pure r
|
||||
Nothing -> do
|
||||
home <- liftIO getHomeDirectory
|
||||
pure (home </> ".config")
|
||||
pure (bdir </> "ghcup")
|
||||
else do
|
||||
bdir <- lookupEnv "GHCUP_INSTALL_BASE_PREFIX" >>= \case
|
||||
Just r -> pure r
|
||||
Nothing -> liftIO getHomeDirectory
|
||||
pure (bdir </> ".ghcup")
|
||||
|
||||
|
||||
-- | If 'GHCUP_USE_XDG_DIRS' is set (to anything),
|
||||
-- then uses 'XDG_BIN_HOME' env var or defaults to '~/.local/bin'
|
||||
-- (which, sadly is not strictly xdg spec).
|
||||
ghcupBinDir :: IO FilePath
|
||||
ghcupBinDir
|
||||
| isWindows = ghcupBaseDir <&> (</> "bin")
|
||||
| otherwise = do
|
||||
xdg <- useXDG
|
||||
if xdg
|
||||
then do
|
||||
lookupEnv "XDG_BIN_HOME" >>= \case
|
||||
Just r -> pure r
|
||||
Nothing -> do
|
||||
home <- liftIO getHomeDirectory
|
||||
pure (home </> ".local" </> "bin")
|
||||
else ghcupBaseDir <&> (</> "bin")
|
||||
|
||||
|
||||
-- | Defaults to '~/.ghcup/cache'.
|
||||
--
|
||||
-- If 'GHCUP_USE_XDG_DIRS' is set (to anything),
|
||||
-- then uses 'XDG_CACHE_HOME/ghcup' as per xdg spec.
|
||||
ghcupCacheDir :: IO FilePath
|
||||
ghcupCacheDir
|
||||
| isWindows = ghcupBaseDir <&> (</> "cache")
|
||||
| otherwise = do
|
||||
xdg <- useXDG
|
||||
if xdg
|
||||
then do
|
||||
bdir <- lookupEnv "XDG_CACHE_HOME" >>= \case
|
||||
Just r -> pure r
|
||||
Nothing -> do
|
||||
home <- liftIO getHomeDirectory
|
||||
pure (home </> ".cache")
|
||||
pure (bdir </> "ghcup")
|
||||
else ghcupBaseDir <&> (</> "cache")
|
||||
|
||||
|
||||
-- | Defaults to '~/.ghcup/logs'.
|
||||
--
|
||||
-- If 'GHCUP_USE_XDG_DIRS' is set (to anything),
|
||||
-- then uses 'XDG_CACHE_HOME/ghcup/logs' as per xdg spec.
|
||||
ghcupLogsDir :: IO FilePath
|
||||
ghcupLogsDir
|
||||
| isWindows = ghcupBaseDir <&> (</> "logs")
|
||||
| otherwise = do
|
||||
xdg <- useXDG
|
||||
if xdg
|
||||
then do
|
||||
bdir <- lookupEnv "XDG_CACHE_HOME" >>= \case
|
||||
Just r -> pure r
|
||||
Nothing -> do
|
||||
home <- liftIO getHomeDirectory
|
||||
pure (home </> ".cache")
|
||||
pure (bdir </> "ghcup" </> "logs")
|
||||
else ghcupBaseDir <&> (</> "logs")
|
||||
|
||||
|
||||
-- | '~/.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 { .. }
|
||||
|
||||
|
||||
|
||||
-------------------
|
||||
--[ 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
|
||||
filepath <- getConfigFilePath
|
||||
contents <- liftIO $ handleIO' NoSuchThing (\_ -> pure Nothing) $ Just <$> BS.readFile filepath
|
||||
case contents of
|
||||
Nothing -> pure defaultUserSettings
|
||||
Just contents' -> lE' JSONDecodeError . first displayException . Y.decodeEither' $ contents'
|
||||
|
||||
|
||||
-------------------------
|
||||
--[ GHCup directories ]--
|
||||
-------------------------
|
||||
|
||||
|
||||
-- | ~/.ghcup/ghc by default.
|
||||
ghcupGHCBaseDir :: (MonadReader env m, HasDirs env) => m FilePath
|
||||
ghcupGHCBaseDir = do
|
||||
Dirs {..} <- getDirs
|
||||
pure (baseDir </> "ghc")
|
||||
|
||||
|
||||
-- | Gets '~/.ghcup/ghc/<ghcupGHCDir>'.
|
||||
-- The dir may be of the form
|
||||
-- * armv7-unknown-linux-gnueabihf-8.8.3
|
||||
-- * 8.8.4
|
||||
ghcupGHCDir :: (MonadReader env m, HasDirs env, MonadThrow m)
|
||||
=> GHCTargetVersion
|
||||
-> m FilePath
|
||||
ghcupGHCDir ver = do
|
||||
ghcbasedir <- ghcupGHCBaseDir
|
||||
let verdir = T.unpack $ tVerToText ver
|
||||
pure (ghcbasedir </> verdir)
|
||||
|
||||
|
||||
-- | See 'ghcupToolParser'.
|
||||
parseGHCupGHCDir :: MonadThrow m => FilePath -> m GHCTargetVersion
|
||||
parseGHCupGHCDir (T.pack -> fp) =
|
||||
throwEither $ MP.parse ghcTargetVerP "" fp
|
||||
|
||||
|
||||
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 ("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 = 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 :: ( 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))
|
||||
|
||||
|
||||
|
||||
|
||||
--------------
|
||||
--[ Others ]--
|
||||
--------------
|
||||
|
||||
|
||||
useXDG :: IO Bool
|
||||
useXDG = isJust <$> lookupEnv "GHCUP_USE_XDG_DIRS"
|
||||
|
||||
|
||||
relativeSymlink :: FilePath -- ^ the path in which to create the symlink
|
||||
-> FilePath -- ^ the symlink destination
|
||||
-> FilePath
|
||||
relativeSymlink p1 p2 =
|
||||
let d1 = splitDirectories p1
|
||||
d2 = splitDirectories p2
|
||||
common = takeWhile (\(x, y) -> x == y) $ zip d1 d2
|
||||
cPrefix = drop (length common) d1
|
||||
in joinPath (replicate (length cPrefix) "..")
|
||||
<> 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))
|
||||
|
||||
60
lib/GHCup/Download/Common.hs
Normal file
@@ -0,0 +1,60 @@
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE TypeFamilies #-}
|
||||
|
||||
|
||||
module GHCup.Download.Common where
|
||||
|
||||
|
||||
import GHCup.Errors
|
||||
import GHCup.Types.Optics
|
||||
import GHCup.Types.JSON ( )
|
||||
import GHCup.Prelude
|
||||
|
||||
import Control.Applicative
|
||||
import Control.Monad
|
||||
import Data.ByteString ( ByteString )
|
||||
import Data.Maybe
|
||||
import Haskus.Utils.Variant.Excepts
|
||||
import Optics
|
||||
import Prelude hiding ( abs
|
||||
, readFile
|
||||
, writeFile
|
||||
)
|
||||
import URI.ByteString
|
||||
|
||||
import qualified Data.Binary.Builder as B
|
||||
import qualified Data.ByteString as BS
|
||||
import qualified Data.ByteString.Lazy as L
|
||||
|
||||
|
||||
-- | Extracts from a URI type: (https?, host, path+query, port)
|
||||
uriToQuadruple :: Monad m
|
||||
=> URI
|
||||
-> Excepts
|
||||
'[UnsupportedScheme]
|
||||
m
|
||||
(Bool, ByteString, ByteString, Maybe Int)
|
||||
uriToQuadruple URI {..} = do
|
||||
let scheme = view schemeBSL' uriScheme
|
||||
|
||||
host <-
|
||||
preview (_Just % authorityHostL' % hostBSL') uriAuthority
|
||||
?? UnsupportedScheme
|
||||
|
||||
https <- if
|
||||
| scheme == "https" -> pure True
|
||||
| scheme == "http" -> pure False
|
||||
| otherwise -> throwE UnsupportedScheme
|
||||
|
||||
let queryBS =
|
||||
BS.intercalate "&"
|
||||
. fmap (\(x, y) -> encodeQuery x <> "=" <> encodeQuery y)
|
||||
$ queryPairs uriQuery
|
||||
port =
|
||||
preview (_Just % authorityPortL' % _Just % portNumberL') uriAuthority
|
||||
fullpath = if BS.null queryBS then uriPath else uriPath <> "?" <> queryBS
|
||||
pure (https, host, fullpath, port)
|
||||
where encodeQuery = L.toStrict . B.toLazyByteString . urlEncodeQuery
|
||||
|
||||
179
lib/GHCup/Download/IOStreams.hs
Normal file
@@ -0,0 +1,179 @@
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE TypeFamilies #-}
|
||||
|
||||
|
||||
module GHCup.Download.IOStreams where
|
||||
|
||||
|
||||
import GHCup.Download.Common
|
||||
import GHCup.Errors
|
||||
import GHCup.Types.JSON ( )
|
||||
import GHCup.Prelude
|
||||
|
||||
import Control.Applicative
|
||||
import Control.Exception.Safe
|
||||
import Control.Monad
|
||||
import Control.Monad.Reader
|
||||
import Data.ByteString ( ByteString )
|
||||
import Data.ByteString.Builder
|
||||
import Data.CaseInsensitive ( CI, original, mk )
|
||||
import Data.IORef
|
||||
import Data.Maybe
|
||||
import Data.Text.Read
|
||||
import Haskus.Utils.Variant.Excepts
|
||||
import Network.Http.Client hiding ( URL )
|
||||
import Optics
|
||||
import Prelude hiding ( abs
|
||||
, readFile
|
||||
, writeFile
|
||||
)
|
||||
import System.ProgressBar
|
||||
import URI.ByteString
|
||||
|
||||
import qualified Data.ByteString as BS
|
||||
import qualified Data.ByteString.Lazy as L
|
||||
import qualified Data.Map.Strict as M
|
||||
import qualified System.IO.Streams as Streams
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
----------------------------
|
||||
--[ Low-level (non-curl) ]--
|
||||
----------------------------
|
||||
|
||||
|
||||
-- | Load the result of this download into memory at once.
|
||||
downloadBS' :: MonadIO m
|
||||
=> Bool -- ^ https?
|
||||
-> ByteString -- ^ host (e.g. "www.example.com")
|
||||
-> ByteString -- ^ path (e.g. "/my/file") including query
|
||||
-> Maybe Int -- ^ optional port (e.g. 3000)
|
||||
-> Excepts
|
||||
'[ HTTPStatusError
|
||||
, URIParseError
|
||||
, UnsupportedScheme
|
||||
, NoLocationHeader
|
||||
, TooManyRedirs
|
||||
]
|
||||
m
|
||||
L.ByteString
|
||||
downloadBS' https host path port = do
|
||||
bref <- liftIO $ newIORef (mempty :: Builder)
|
||||
let stepper bs = modifyIORef bref (<> byteString bs)
|
||||
void $ downloadInternal False https host path port stepper (pure ()) mempty
|
||||
liftIO (readIORef bref <&> toLazyByteString)
|
||||
|
||||
|
||||
downloadToFile :: (MonadMask m, MonadIO m)
|
||||
=> Bool -- ^ https?
|
||||
-> ByteString -- ^ host (e.g. "www.example.com")
|
||||
-> ByteString -- ^ path (e.g. "/my/file") including query
|
||||
-> Maybe Int -- ^ optional port (e.g. 3000)
|
||||
-> FilePath -- ^ destination file to create and write to
|
||||
-> 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
|
||||
=> Bool -- ^ whether to show a progress bar
|
||||
-> Bool -- ^ https?
|
||||
-> ByteString -- ^ host
|
||||
-> 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
|
||||
, UnsupportedScheme
|
||||
, NoLocationHeader
|
||||
, TooManyRedirs
|
||||
]
|
||||
m
|
||||
Response
|
||||
downloadInternal = go (5 :: Int)
|
||||
|
||||
where
|
||||
go redirs progressBar https host path port consumer setup addHeaders = do
|
||||
r <- liftIO $ withConnection' https host port action
|
||||
veitherToExcepts r >>= \case
|
||||
Right r' ->
|
||||
if redirs > 0 then followRedirectURL r' else throwE TooManyRedirs
|
||||
Left res -> pure res
|
||||
where
|
||||
action c = do
|
||||
let q = buildRequest1 $ do
|
||||
http GET path
|
||||
flip M.traverseWithKey addHeaders $ \key val -> setHeader (original key) val
|
||||
|
||||
sendRequest c q emptyBody
|
||||
|
||||
receiveResponse
|
||||
c
|
||||
(\r i' -> runE $ do
|
||||
let scode = getStatusCode r
|
||||
if
|
||||
| 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 $ Right r'
|
||||
Nothing -> throwE NoLocationHeader
|
||||
| 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 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 :: Maybe (ProgressBar ())) <- if progressBar
|
||||
then Just <$> newProgressBar defStyle 10 (Progress 0 size ())
|
||||
else pure Nothing
|
||||
|
||||
outStream <- liftIO $ Streams.makeOutputStream
|
||||
(\case
|
||||
Just bs -> do
|
||||
forM_ mpb $ \pb -> incProgress pb (BS.length bs)
|
||||
void $ consumer bs
|
||||
Nothing -> pure ()
|
||||
)
|
||||
liftIO $ Streams.connect i' outStream
|
||||
|
||||
|
||||
|
||||
withConnection' :: Bool
|
||||
-> ByteString
|
||||
-> Maybe Int
|
||||
-> (Connection -> IO a)
|
||||
-> IO a
|
||||
withConnection' https host port = bracket acquire closeConnection
|
||||
|
||||
where
|
||||
acquire = case https of
|
||||
True -> do
|
||||
ctx <- baselineContextSSL
|
||||
openConnectionSSL ctx host (fromIntegral $ fromMaybe 443 port)
|
||||
False -> openConnection host (fromIntegral $ fromMaybe 80 port)
|
||||
@@ -1,18 +1,38 @@
|
||||
{-# OPTIONS_GHC -Wno-orphans #-}
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE ExistentialQuantification #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE StandaloneDeriving #-}
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE TypeOperators #-}
|
||||
{-# LANGUAGE FlexibleInstances #-}
|
||||
|
||||
{-|
|
||||
Module : GHCup.Errors
|
||||
Description : GHCup error types
|
||||
Copyright : (c) Julian Ospald, 2020
|
||||
License : LGPL-3.0
|
||||
Maintainer : hasufell@hasufell.de
|
||||
Stability : experimental
|
||||
Portability : portable
|
||||
-}
|
||||
module GHCup.Errors where
|
||||
|
||||
import GHCup.Types
|
||||
|
||||
import Codec.Archive
|
||||
import Control.Exception.Safe
|
||||
import Data.ByteString ( ByteString )
|
||||
import Data.CaseInsensitive ( CI )
|
||||
import Data.Text ( Text )
|
||||
import Data.Versions
|
||||
import Haskus.Utils.Variant
|
||||
import HPath
|
||||
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
|
||||
|
||||
|
||||
|
||||
@@ -26,68 +46,250 @@ import HPath
|
||||
data NoCompatiblePlatform = NoCompatiblePlatform String -- the platform we got
|
||||
deriving Show
|
||||
|
||||
-- | Unable to find a download for the requested versio/distro.
|
||||
instance Pretty NoCompatiblePlatform where
|
||||
pPrint (NoCompatiblePlatform str') =
|
||||
text ("Could not find a compatible platform. Got: " ++ str')
|
||||
|
||||
-- | Unable to find a download for the requested version/distro.
|
||||
data NoDownload = NoDownload
|
||||
deriving Show
|
||||
|
||||
instance Pretty NoDownload where
|
||||
pPrint NoDownload =
|
||||
text "Unable to find a download for the requested version/distro."
|
||||
|
||||
-- | No update available or necessary.
|
||||
data NoUpdate = NoUpdate
|
||||
deriving Show
|
||||
|
||||
instance Pretty NoUpdate where
|
||||
pPrint NoUpdate = text "No update available or necessary."
|
||||
|
||||
-- | The Architecture is unknown and unsupported.
|
||||
data NoCompatibleArch = NoCompatibleArch String
|
||||
deriving Show
|
||||
|
||||
instance Pretty NoCompatibleArch where
|
||||
pPrint (NoCompatibleArch arch) =
|
||||
text ("The Architecture is unknown or unsupported. Got: " ++ arch)
|
||||
|
||||
-- | Unable to figure out the distribution of the host.
|
||||
data DistroNotFound = DistroNotFound
|
||||
deriving Show
|
||||
|
||||
instance Pretty DistroNotFound where
|
||||
pPrint DistroNotFound =
|
||||
text "Unable to figure out the distribution of the host."
|
||||
|
||||
-- | The archive format is unknown. We don't know how to extract it.
|
||||
data UnknownArchive = UnknownArchive ByteString
|
||||
data UnknownArchive = UnknownArchive FilePath
|
||||
deriving Show
|
||||
|
||||
instance Pretty UnknownArchive where
|
||||
pPrint (UnknownArchive 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
|
||||
deriving Show
|
||||
|
||||
instance Pretty UnsupportedScheme where
|
||||
pPrint UnsupportedScheme = text "The scheme is not supported (such as ftp)."
|
||||
|
||||
-- | Unable to copy a file.
|
||||
data CopyError = CopyError String
|
||||
deriving Show
|
||||
|
||||
instance Pretty CopyError where
|
||||
pPrint (CopyError reason) =
|
||||
text ("Unable to copy a file. Reason was: " ++ reason)
|
||||
|
||||
-- | Unable to find a tag of a tool.
|
||||
data TagNotFound = TagNotFound Tag Tool
|
||||
deriving Show
|
||||
|
||||
instance Pretty TagNotFound where
|
||||
pPrint (TagNotFound tag 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).
|
||||
data NextVerNotFound = NextVerNotFound Tool
|
||||
deriving Show
|
||||
|
||||
instance Pretty NextVerNotFound where
|
||||
pPrint (NextVerNotFound 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
|
||||
deriving Show
|
||||
|
||||
instance Pretty AlreadyInstalled where
|
||||
pPrint (AlreadyInstalled tool ver') =
|
||||
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).
|
||||
data NotInstalled = NotInstalled Tool Version
|
||||
data NotInstalled = NotInstalled Tool GHCTargetVersion
|
||||
deriving Show
|
||||
|
||||
instance Pretty NotInstalled where
|
||||
pPrint (NotInstalled tool ver) =
|
||||
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 $ "The exe " <> exe <> " was not found in PATH."
|
||||
|
||||
-- | JSON decoding failed.
|
||||
data JSONError = JSONDecodeError String
|
||||
deriving Show
|
||||
|
||||
instance Pretty JSONError where
|
||||
pPrint (JSONDecodeError 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).
|
||||
data FileDoesNotExistError = FileDoesNotExistError ByteString
|
||||
data FileDoesNotExistError = FileDoesNotExistError FilePath
|
||||
deriving Show
|
||||
|
||||
instance Pretty FileDoesNotExistError where
|
||||
pPrint (FileDoesNotExistError file) =
|
||||
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
|
||||
|
||||
instance Pretty TarDirDoesNotExist where
|
||||
pPrint (TarDirDoesNotExist dir) =
|
||||
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 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 "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
|
||||
deriving Show
|
||||
|
||||
instance Pretty NoLocationHeader where
|
||||
pPrint NoLocationHeader =
|
||||
text "The 'Location' header was expected during a 3xx redirect, but not found."
|
||||
|
||||
-- | Too many redirects.
|
||||
data TooManyRedirs = TooManyRedirs
|
||||
deriving Show
|
||||
|
||||
instance Pretty TooManyRedirs where
|
||||
pPrint TooManyRedirs =
|
||||
text "Too many redirections."
|
||||
|
||||
-- | A patch could not be applied.
|
||||
data PatchFailed = PatchFailed
|
||||
deriving Show
|
||||
|
||||
instance Pretty PatchFailed where
|
||||
pPrint PatchFailed =
|
||||
text "A patch could not be applied."
|
||||
|
||||
-- | The tool requirements could not be found.
|
||||
data NoToolRequirements = NoToolRequirements
|
||||
deriving Show
|
||||
|
||||
instance Pretty NoToolRequirements where
|
||||
pPrint NoToolRequirements =
|
||||
text "The Tool requirements could not be found."
|
||||
|
||||
data InvalidBuildConfig = InvalidBuildConfig Text
|
||||
deriving Show
|
||||
|
||||
instance Pretty InvalidBuildConfig where
|
||||
pPrint (InvalidBuildConfig 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 "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?"
|
||||
|
||||
|
||||
-------------------------
|
||||
@@ -95,19 +297,37 @@ data TooManyRedirs = TooManyRedirs
|
||||
-------------------------
|
||||
|
||||
-- | A download failed. The underlying error is encapsulated.
|
||||
data DownloadFailed = forall es . Show (V es) => DownloadFailed (V es)
|
||||
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) =
|
||||
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 (Path Abs) (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) =
|
||||
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) =
|
||||
case reason of
|
||||
VMaybe (_ :: GHCupSetError) -> pPrint reason
|
||||
_ -> text "Setting the current GHC version failed:" <+> pPrint reason
|
||||
|
||||
deriving instance Show GHCupSetError
|
||||
|
||||
@@ -121,4 +341,75 @@ deriving instance Show GHCupSetError
|
||||
data ParseError = ParseError String
|
||||
deriving Show
|
||||
|
||||
instance Pretty ParseError where
|
||||
pPrint (ParseError reason) =
|
||||
text "Parsing failed:" <+> pPrint reason
|
||||
|
||||
instance Exception ParseError
|
||||
|
||||
|
||||
data UnexpectedListLength = UnexpectedListLength String
|
||||
deriving Show
|
||||
|
||||
instance Pretty UnexpectedListLength where
|
||||
pPrint (UnexpectedListLength 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
|
||||
|
||||
|
||||
|
||||
------------------------
|
||||
--[ orphan instances ]--
|
||||
------------------------
|
||||
|
||||
instance Pretty (V '[]) where
|
||||
{-# INLINABLE pPrint #-}
|
||||
pPrint _ = undefined
|
||||
|
||||
instance
|
||||
( Pretty x
|
||||
, Pretty (V xs)
|
||||
) => Pretty (V (x ': xs))
|
||||
where
|
||||
pPrint v = case popVariantHead v of
|
||||
Right x -> pPrint x
|
||||
Left xs -> pPrint xs
|
||||
|
||||
instance Pretty URIParseError where
|
||||
pPrint (MalformedScheme reason) =
|
||||
text "Failed to parse URI. Malformed scheme:" <+> text (show reason)
|
||||
pPrint MalformedUserInfo =
|
||||
text "Failed to parse URI. Malformed user info."
|
||||
pPrint MalformedQuery =
|
||||
text "Failed to parse URI. Malformed query."
|
||||
pPrint MalformedFragment =
|
||||
text "Failed to parse URI. Malformed fragment."
|
||||
pPrint MalformedHost =
|
||||
text "Failed to parse URI. Malformed host."
|
||||
pPrint MalformedPort =
|
||||
text "Failed to parse URI. Malformed port."
|
||||
pPrint MalformedPath =
|
||||
text "Failed to parse URI. Malformed path."
|
||||
pPrint (OtherError err) =
|
||||
text "Failed to parse URI:" <+> pPrint err
|
||||
|
||||
instance Pretty ArchiveResult where
|
||||
pPrint ArchiveFatal = text "Archive result: fatal"
|
||||
pPrint ArchiveFailed = text "Archive result: failed"
|
||||
pPrint ArchiveWarn = text "Archive result: warning"
|
||||
pPrint ArchiveRetry = text "Archive result: retry"
|
||||
pPrint ArchiveOk = text "Archive result: Ok"
|
||||
pPrint ArchiveEOF = text "Archive result: EOF"
|
||||
|
||||
instance Pretty T.Text where
|
||||
pPrint = text . T.unpack
|
||||
|
||||
131
lib/GHCup/Logger.hs
Normal file
@@ -0,0 +1,131 @@
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE QuasiQuotes #-}
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
|
||||
{-|
|
||||
Module : GHCup.Logger
|
||||
Description : logger definition
|
||||
Copyright : (c) Julian Ospald, 2020
|
||||
License : LGPL-3.0
|
||||
Maintainer : hasufell@hasufell.de
|
||||
Stability : experimental
|
||||
Portability : portable
|
||||
|
||||
Here we define our main logger.
|
||||
-}
|
||||
module GHCup.Logger where
|
||||
|
||||
import GHCup.Types
|
||||
import GHCup.Types.Optics
|
||||
import {-# SOURCE #-} GHCup.System.Directory
|
||||
import GHCup.QQ.String
|
||||
|
||||
import Control.Exception.Safe
|
||||
import Control.Monad
|
||||
import Control.Monad.IO.Class
|
||||
import Control.Monad.Reader
|
||||
import Data.Text ( Text )
|
||||
import Optics
|
||||
import Prelude hiding ( appendFile )
|
||||
import System.Console.Pretty
|
||||
import System.FilePath
|
||||
import System.IO.Error
|
||||
import Text.Regex.Posix
|
||||
|
||||
import qualified Data.ByteString as B
|
||||
import GHCup.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
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
initGHCupFileLogging :: ( MonadReader env m
|
||||
, HasDirs env
|
||||
, MonadIO m
|
||||
, MonadMask m
|
||||
) => m FilePath
|
||||
initGHCupFileLogging = do
|
||||
Dirs { logsDir } <- getDirs
|
||||
let logfile = logsDir </> "ghcup.log"
|
||||
logFiles <- liftIO $ findFiles
|
||||
logsDir
|
||||
(makeRegexOpts compExtended
|
||||
execBlank
|
||||
([s|^.*\.log$|] :: B.ByteString)
|
||||
)
|
||||
forM_ logFiles $ hideError doesNotExistErrorType . recycleFile . (logsDir </>)
|
||||
|
||||
liftIO $ writeFile logfile ""
|
||||
pure logfile
|
||||
21
lib/GHCup/Logger.hs-boot
Normal file
@@ -0,0 +1,21 @@
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE QuasiQuotes #-}
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
|
||||
module GHCup.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 ()
|
||||
|
||||
124
lib/GHCup/MegaParsec.hs
Normal file
@@ -0,0 +1,124 @@
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
|
||||
{-|
|
||||
Module : GHCup.MegaParsec
|
||||
Description : MegaParsec utilities
|
||||
Copyright : (c) Julian Ospald, 2020
|
||||
License : LGPL-3.0
|
||||
Maintainer : hasufell@hasufell.de
|
||||
Stability : experimental
|
||||
Portability : portable
|
||||
-}
|
||||
module GHCup.MegaParsec where
|
||||
|
||||
import GHCup.Types
|
||||
|
||||
import Control.Applicative
|
||||
#if !MIN_VERSION_base(4,13,0)
|
||||
import Control.Monad.Fail ( MonadFail )
|
||||
#endif
|
||||
import Data.Functor
|
||||
import Data.Maybe
|
||||
import Data.Text ( Text )
|
||||
import Data.Versions
|
||||
import Data.Void
|
||||
import System.FilePath
|
||||
|
||||
import qualified Data.List.NonEmpty as NE
|
||||
import qualified Data.Text as T
|
||||
import qualified Text.Megaparsec as MP
|
||||
|
||||
|
||||
choice' :: (MonadFail f, MP.MonadParsec e s f) => [f a] -> f a
|
||||
choice' [] = fail "Empty list"
|
||||
choice' [x ] = x
|
||||
choice' (x : xs) = MP.try x <|> choice' xs
|
||||
|
||||
|
||||
parseUntil :: MP.Parsec Void Text a -> MP.Parsec Void Text Text
|
||||
parseUntil p = do
|
||||
(MP.try (MP.lookAhead p) $> mempty)
|
||||
<|> (do
|
||||
c <- T.singleton <$> MP.anySingle
|
||||
c2 <- parseUntil p
|
||||
pure (c `mappend` c2)
|
||||
)
|
||||
|
||||
parseUntil1 :: MP.Parsec Void Text a -> MP.Parsec Void Text Text
|
||||
parseUntil1 p = do
|
||||
i1 <- MP.getOffset
|
||||
t <- parseUntil p
|
||||
i2 <- MP.getOffset
|
||||
if i1 == i2 then fail "empty parse" else pure t
|
||||
|
||||
|
||||
|
||||
-- | Parses e.g.
|
||||
-- * armv7-unknown-linux-gnueabihf-ghc
|
||||
-- * armv7-unknown-linux-gnueabihf-ghci
|
||||
ghcTargetBinP :: Text -> MP.Parsec Void Text (Maybe Text, Text)
|
||||
ghcTargetBinP t =
|
||||
(,)
|
||||
<$> ( MP.try
|
||||
(Just <$> parseUntil1 (MP.chunk "-" *> MP.chunk t) <* MP.chunk "-"
|
||||
)
|
||||
<|> ((\ _ x -> x) Nothing <$> mempty)
|
||||
)
|
||||
<*> (MP.chunk t <* MP.eof)
|
||||
|
||||
|
||||
-- | Extracts the version from @ProjectVersion="8.10.5"@.
|
||||
ghcProjectVersion :: MP.Parsec Void Text Version
|
||||
ghcProjectVersion = do
|
||||
_ <- MP.chunk "ProjectVersion=\""
|
||||
ver <- parseUntil1 $ MP.chunk "\""
|
||||
MP.setInput ver
|
||||
version'
|
||||
|
||||
|
||||
-- | Extracts target triple and version from e.g.
|
||||
-- * armv7-unknown-linux-gnueabihf-8.8.3
|
||||
-- * armv7-unknown-linux-gnueabihf-8.8.3
|
||||
ghcTargetVerP :: MP.Parsec Void Text GHCTargetVersion
|
||||
ghcTargetVerP =
|
||||
(\x y -> GHCTargetVersion x y)
|
||||
<$> (MP.try (Just <$> parseUntil1 (MP.chunk "-" *> verP') <* MP.chunk "-")
|
||||
<|> ((\ _ x -> x) Nothing <$> mempty)
|
||||
)
|
||||
<*> (version' <* MP.eof)
|
||||
where
|
||||
verP' :: MP.Parsec Void Text Text
|
||||
verP' = do
|
||||
v <- version'
|
||||
let startsWithDigists =
|
||||
and
|
||||
. take 3
|
||||
. concatMap
|
||||
(map
|
||||
(\case
|
||||
(Digits _) -> True
|
||||
(Str _) -> False
|
||||
) . NE.toList)
|
||||
. NE.toList
|
||||
$ _vChunks v
|
||||
if startsWithDigists && isNothing (_vEpoch v)
|
||||
then pure $ prettyVer v
|
||||
else fail "Oh"
|
||||
|
||||
|
||||
verP :: MP.Parsec Void Text Text -> MP.Parsec Void Text Versioning
|
||||
verP suffix = do
|
||||
ver <- parseUntil suffix
|
||||
if T.null ver
|
||||
then fail "empty version"
|
||||
else do
|
||||
rest <- MP.getInput
|
||||
MP.setInput ver
|
||||
v <- versioning'
|
||||
MP.setInput rest
|
||||
pure v
|
||||
|
||||
|
||||
pathSep :: MP.Parsec Void Text Char
|
||||
pathSep = MP.oneOf pathSeparators
|
||||
@@ -1,60 +1,95 @@
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE FlexibleInstances #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE QuasiQuotes #-}
|
||||
{-# LANGUAGE TemplateHaskell #-}
|
||||
|
||||
|
||||
{-|
|
||||
Module : GHCup.Plaform
|
||||
Description : Retrieving platform information
|
||||
Copyright : (c) Julian Ospald, 2020
|
||||
License : LGPL-3.0
|
||||
Maintainer : hasufell@hasufell.de
|
||||
Stability : experimental
|
||||
Portability : portable
|
||||
-}
|
||||
module GHCup.Platform where
|
||||
|
||||
|
||||
import GHCup.Errors
|
||||
import GHCup.Types
|
||||
import GHCup.Types.Optics
|
||||
import GHCup.Types.JSON ( )
|
||||
import GHCup.Utils.Bash
|
||||
import GHCup.Utils.File
|
||||
import GHCup.Utils.Prelude
|
||||
import GHCup.Utils.String.QQ
|
||||
import GHCup.System.Process
|
||||
import GHCup.Logger
|
||||
import GHCup.Prelude
|
||||
import GHCup.QQ.String
|
||||
|
||||
#if !MIN_VERSION_base(4,13,0)
|
||||
import Control.Monad.Fail ( MonadFail )
|
||||
#endif
|
||||
import Control.Applicative
|
||||
import Control.Exception.Safe
|
||||
import Control.Monad
|
||||
import Control.Monad.Logger
|
||||
import Control.Monad.Reader
|
||||
import Control.Monad.Trans.Class ( lift )
|
||||
import Data.ByteString ( ByteString )
|
||||
import Data.Foldable
|
||||
import Data.Maybe
|
||||
import Data.String.Interpolate
|
||||
import Data.Text ( Text )
|
||||
import Data.Versions
|
||||
import HPath
|
||||
import HPath.IO
|
||||
import Haskus.Utils.Variant.Excepts
|
||||
import Prelude hiding ( abs
|
||||
, readFile
|
||||
, writeFile
|
||||
)
|
||||
import System.Info
|
||||
import System.Directory
|
||||
import System.OsRelease
|
||||
import Text.PrettyPrint.HughesPJClass ( prettyShow )
|
||||
import Text.Regex.Posix
|
||||
|
||||
import qualified Data.Text as T
|
||||
import qualified Data.Text.Encoding as E
|
||||
import qualified Data.Text.ICU as ICU
|
||||
import qualified Data.Text.IO as T
|
||||
|
||||
|
||||
|
||||
--------------------------
|
||||
--[ Platform detection ]--
|
||||
--------------------------
|
||||
|
||||
|
||||
-- | Get the full platform request, consisting of architecture, distro, ...
|
||||
platformRequest :: (MonadReader env m, Alternative m, MonadFail m, HasLog env, MonadCatch m, MonadIO m)
|
||||
=> Excepts
|
||||
'[NoCompatiblePlatform, NoCompatibleArch, DistroNotFound]
|
||||
m
|
||||
PlatformRequest
|
||||
platformRequest = do
|
||||
(PlatformResult rp rv) <- liftE getPlatform
|
||||
ar <- lE getArchitecture
|
||||
pure $ PlatformRequest ar rp rv
|
||||
|
||||
|
||||
getArchitecture :: Either NoCompatibleArch Architecture
|
||||
getArchitecture = case arch of
|
||||
"x86_64" -> Right A_64
|
||||
"i386" -> Right A_32
|
||||
what -> Left (NoCompatibleArch what)
|
||||
"x86_64" -> Right A_64
|
||||
"i386" -> Right A_32
|
||||
"powerpc" -> Right A_PowerPC
|
||||
"powerpc64" -> Right A_PowerPC64
|
||||
"powerpc64le" -> Right A_PowerPC64
|
||||
"sparc" -> Right A_Sparc
|
||||
"sparc64" -> Right A_Sparc64
|
||||
"arm" -> Right A_ARM
|
||||
"aarch64" -> Right A_ARM64
|
||||
what -> Left (NoCompatibleArch what)
|
||||
|
||||
|
||||
|
||||
getPlatform :: (MonadLogger m, MonadCatch m, MonadIO m)
|
||||
getPlatform :: (Alternative m, MonadReader env m, HasLog env, MonadCatch m, MonadIO m, MonadFail m)
|
||||
=> Excepts
|
||||
'[NoCompatiblePlatform , DistroNotFound]
|
||||
'[NoCompatiblePlatform, DistroNotFound]
|
||||
m
|
||||
PlatformResult
|
||||
getPlatform = do
|
||||
@@ -62,28 +97,39 @@ getPlatform = do
|
||||
"linux" -> do
|
||||
(distro, ver) <- liftE getLinuxDistro
|
||||
pure $ PlatformResult { _platform = Linux distro, _distroVersion = ver }
|
||||
-- TODO: these are not verified
|
||||
"darwin" ->
|
||||
pure $ PlatformResult { _platform = Darwin, _distroVersion = Nothing }
|
||||
"darwin" -> do
|
||||
ver <-
|
||||
either (const Nothing) Just
|
||||
. versioning
|
||||
-- TODO: maybe do this somewhere else
|
||||
. decUTF8Safe'
|
||||
<$> getDarwinVersion
|
||||
pure $ PlatformResult { _platform = Darwin, _distroVersion = ver }
|
||||
"freebsd" -> do
|
||||
ver <- getFreeBSDVersion
|
||||
ver <-
|
||||
either (const Nothing) Just . versioning . decUTF8Safe'
|
||||
<$> getFreeBSDVersion
|
||||
pure $ PlatformResult { _platform = FreeBSD, _distroVersion = ver }
|
||||
"mingw32" -> pure PlatformResult { _platform = Windows, _distroVersion = Nothing }
|
||||
what -> throwE $ NoCompatiblePlatform what
|
||||
lift $ $(logDebug) [i|Identified Platform as: #{pfr}|]
|
||||
lift $ logDebug $ "Identified Platform as: " <> T.pack (prettyShow pfr)
|
||||
pure pfr
|
||||
where getFreeBSDVersion = pure Nothing
|
||||
where
|
||||
getFreeBSDVersion = lift $ fmap _stdOut $ executeOut "freebsd-version" [] Nothing
|
||||
getDarwinVersion = lift $ fmap _stdOut $ executeOut "sw_vers"
|
||||
["-productVersion"]
|
||||
Nothing
|
||||
|
||||
|
||||
getLinuxDistro :: (MonadCatch m, MonadIO m)
|
||||
getLinuxDistro :: (Alternative m, MonadCatch m, MonadIO m, MonadFail m)
|
||||
=> Excepts '[DistroNotFound] m (LinuxDistro, Maybe Versioning)
|
||||
getLinuxDistro = do
|
||||
-- TODO: don't do alternative on IO, because it hides bugs
|
||||
(name, ver) <- handleIO (\_ -> throwE DistroNotFound) $ liftIO $ asum
|
||||
[ try_os_release
|
||||
(name, ver) <- handleIO (\_ -> throwE DistroNotFound) $ lift $ asum
|
||||
[ liftIO try_os_release
|
||||
, try_lsb_release_cmd
|
||||
, try_lsb_release
|
||||
, try_redhat_release
|
||||
, try_debian_version
|
||||
, liftIO try_redhat_release
|
||||
, liftIO try_debian_version
|
||||
]
|
||||
let parsedVer = ver >>= either (const Nothing) Just . versioning
|
||||
distro = if
|
||||
@@ -100,67 +146,54 @@ getLinuxDistro = do
|
||||
| otherwise -> UnknownLinux
|
||||
pure (distro, parsedVer)
|
||||
where
|
||||
hasWord t matches = foldr
|
||||
(\x y ->
|
||||
( isJust
|
||||
. ICU.find (ICU.regex [ICU.CaseInsensitive] ([s|\b|] <> x <> [s|\b|]))
|
||||
$ t
|
||||
)
|
||||
|| y
|
||||
)
|
||||
False
|
||||
(T.pack <$> matches)
|
||||
hasWord t = any (\x -> match (regex x) (T.unpack t))
|
||||
where
|
||||
regex x = makeRegexOpts compIgnoreCase execBlank ([s|\<|] ++ x ++ [s|\>|])
|
||||
|
||||
os_release :: Path Abs
|
||||
os_release = [abs|/etc/os-release|]
|
||||
lsb_release :: Path Abs
|
||||
lsb_release = [abs|/etc/lsb-release|]
|
||||
lsb_release_cmd :: Path Rel
|
||||
lsb_release_cmd = [rel|lsb-release|]
|
||||
redhat_release :: Path Abs
|
||||
redhat_release = [abs|/etc/redhat-release|]
|
||||
debian_version :: Path Abs
|
||||
debian_version = [abs|/etc/debian_version|]
|
||||
lsb_release_cmd :: FilePath
|
||||
lsb_release_cmd = "lsb-release"
|
||||
redhat_release :: FilePath
|
||||
redhat_release = "/etc/redhat-release"
|
||||
debian_version :: FilePath
|
||||
debian_version = "/etc/debian_version"
|
||||
|
||||
try_os_release :: IO (Text, Maybe Text)
|
||||
try_os_release = do
|
||||
(Just name) <- getAssignmentValueFor os_release "NAME"
|
||||
ver <- getAssignmentValueFor os_release "VERSION_ID"
|
||||
pure (T.pack name, fmap T.pack ver)
|
||||
Just OsRelease{ name = name, version_id = version_id } <-
|
||||
fmap osRelease <$> parseOsRelease
|
||||
pure (T.pack name, fmap T.pack version_id)
|
||||
|
||||
try_lsb_release_cmd :: IO (Text, Maybe Text)
|
||||
try_lsb_release_cmd :: (MonadFail m, MonadIO m)
|
||||
=> m (Text, Maybe Text)
|
||||
try_lsb_release_cmd = do
|
||||
(Just _) <- findExecutable lsb_release_cmd
|
||||
name <- fmap _stdOut $ executeOut lsb_release_cmd [[s|-si|]] Nothing
|
||||
ver <- fmap _stdOut $ executeOut lsb_release_cmd [[s|-sr|]] Nothing
|
||||
pure (E.decodeUtf8 name, Just $ E.decodeUtf8 ver)
|
||||
|
||||
try_lsb_release :: IO (Text, Maybe Text)
|
||||
try_lsb_release = do
|
||||
(Just name) <- getAssignmentValueFor lsb_release "DISTRIB_ID"
|
||||
ver <- getAssignmentValueFor lsb_release "DISTRIB_RELEASE"
|
||||
pure (T.pack name, fmap T.pack ver)
|
||||
(Just _) <- liftIO $ findExecutable lsb_release_cmd
|
||||
name <- fmap _stdOut $ executeOut lsb_release_cmd ["-si"] Nothing
|
||||
ver <- fmap _stdOut $ executeOut lsb_release_cmd ["-sr"] Nothing
|
||||
pure (decUTF8Safe' name, Just $ decUTF8Safe' ver)
|
||||
|
||||
try_redhat_release :: IO (Text, Maybe Text)
|
||||
try_redhat_release = do
|
||||
t <- fmap lBS2sT $ readFile redhat_release
|
||||
t <- T.readFile redhat_release
|
||||
let nameRegex n =
|
||||
makeRegexOpts compIgnoreCase
|
||||
execBlank
|
||||
([s|\<|] <> fS n <> [s|\>|] :: ByteString) :: Regex
|
||||
let verRegex =
|
||||
makeRegexOpts compIgnoreCase
|
||||
execBlank
|
||||
([s|\<([0-9])+(.([0-9])+)*\>|] :: ByteString) :: Regex
|
||||
let nameRe n =
|
||||
join
|
||||
. fmap (ICU.group 0)
|
||||
. ICU.find
|
||||
(ICU.regex [ICU.CaseInsensitive] ([s|\b|] <> fS n <> [s|\b|]))
|
||||
$ t
|
||||
verRe =
|
||||
join
|
||||
. fmap (ICU.group 0)
|
||||
. ICU.find
|
||||
(ICU.regex [ICU.CaseInsensitive] [s|\b(\d)+(.(\d)+)*\b|])
|
||||
$ t
|
||||
fromEmpty . match (nameRegex n) $ T.unpack t :: Maybe String
|
||||
verRe = fromEmpty . match verRegex $ T.unpack t :: Maybe String
|
||||
(Just name) <- pure
|
||||
(nameRe "CentOS" <|> nameRe "Fedora" <|> nameRe "Red Hat")
|
||||
pure (name, verRe)
|
||||
pure (T.pack name, fmap T.pack verRe)
|
||||
where
|
||||
fromEmpty :: String -> Maybe String
|
||||
fromEmpty "" = Nothing
|
||||
fromEmpty s' = Just s'
|
||||
|
||||
try_debian_version :: IO (Text, Maybe Text)
|
||||
try_debian_version = do
|
||||
ver <- readFile debian_version
|
||||
pure (T.pack "debian", Just $ lBS2sT ver)
|
||||
ver <- T.readFile debian_version
|
||||
pure (T.pack "debian", Just ver)
|
||||
|
||||
768
lib/GHCup/Prelude.hs
Normal file
@@ -0,0 +1,768 @@
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE FlexibleInstances #-}
|
||||
{-# LANGUAGE ScopedTypeVariables #-}
|
||||
{-# LANGUAGE TypeFamilies #-}
|
||||
{-# LANGUAGE TypeOperators #-}
|
||||
|
||||
{-|
|
||||
Module : GHCup.Prelude
|
||||
Description : MegaParsec utilities
|
||||
Copyright : (c) Julian Ospald, 2020
|
||||
License : LGPL-3.0
|
||||
Maintainer : hasufell@hasufell.de
|
||||
Stability : experimental
|
||||
Portability : portable
|
||||
|
||||
GHCup specific prelude. Lots of Excepts functionality.
|
||||
-}
|
||||
module GHCup.Prelude
|
||||
(module GHCup.Prelude,
|
||||
#if defined(IS_WINDOWS)
|
||||
module GHCup.Prelude.Windows
|
||||
#else
|
||||
module GHCup.Prelude.Posix
|
||||
#endif
|
||||
)
|
||||
where
|
||||
|
||||
import GHCup.Types
|
||||
import GHCup.Errors
|
||||
import GHCup.Types.Optics
|
||||
import {-# SOURCE #-} GHCup.Logger
|
||||
#if defined(IS_WINDOWS)
|
||||
import GHCup.Prelude.Windows
|
||||
#else
|
||||
import GHCup.Prelude.Posix
|
||||
#endif
|
||||
|
||||
import Control.Applicative
|
||||
import Control.Exception.Safe
|
||||
import Control.Monad
|
||||
import Control.Monad.IO.Class
|
||||
import Control.Monad.Reader
|
||||
import Data.Bifunctor
|
||||
import Data.ByteString ( ByteString )
|
||||
import Data.List ( nub, intercalate, stripPrefix, isPrefixOf, dropWhileEnd, intersperse )
|
||||
import Data.Maybe
|
||||
import Data.Foldable
|
||||
import Data.List.NonEmpty ( NonEmpty( (:|) ))
|
||||
import Data.String
|
||||
import Data.Text ( Text )
|
||||
import Data.Versions
|
||||
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
|
||||
import System.IO.Temp
|
||||
import System.IO.Unsafe
|
||||
import System.Directory
|
||||
import System.FilePath
|
||||
|
||||
import Control.Retry
|
||||
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
|
||||
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
|
||||
|
||||
|
||||
-- $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
|
||||
|
||||
fromStrictMaybe :: S.Maybe a -> Maybe a
|
||||
fromStrictMaybe = S.maybe Nothing Just
|
||||
|
||||
fSM :: S.Maybe a -> Maybe a
|
||||
fSM = fromStrictMaybe
|
||||
|
||||
toStrictMaybe :: Maybe a -> S.Maybe a
|
||||
toStrictMaybe = maybe S.Nothing S.Just
|
||||
|
||||
tSM :: Maybe a -> S.Maybe a
|
||||
tSM = toStrictMaybe
|
||||
|
||||
internalError :: String -> IO a
|
||||
internalError = fail . ("Internal error: " <>)
|
||||
|
||||
iE :: String -> IO a
|
||||
iE = internalError
|
||||
|
||||
|
||||
showT :: Show a => a -> Text
|
||||
showT = fS . show
|
||||
|
||||
-- | Like 'when', but where the test can be monadic.
|
||||
whenM :: Monad m => m Bool -> m () -> m ()
|
||||
whenM ~b ~t = ifM b t (return ())
|
||||
|
||||
-- | Like 'unless', but where the test can be monadic.
|
||||
unlessM :: Monad m => m Bool -> m () -> m ()
|
||||
unlessM ~b ~f = ifM b (return ()) f
|
||||
|
||||
-- | Like @if@, but where the test can be monadic.
|
||||
ifM :: Monad m => m Bool -> m a -> m a -> m a
|
||||
ifM ~b ~t ~f = do
|
||||
b' <- b
|
||||
if b' then t else f
|
||||
|
||||
whileM :: Monad m => m a -> (a -> m Bool) -> m a
|
||||
whileM ~action ~f = do
|
||||
a <- action
|
||||
b' <- f a
|
||||
if b' then whileM action f else pure a
|
||||
|
||||
whileM_ :: Monad m => m a -> (a -> m Bool) -> m ()
|
||||
whileM_ ~action = void . whileM action
|
||||
|
||||
guardM :: (Monad m, Alternative m) => m Bool -> m ()
|
||||
guardM ~f = guard =<< f
|
||||
|
||||
|
||||
handleIO' :: (MonadIO m, MonadCatch m)
|
||||
=> IOErrorType
|
||||
-> (IOException -> m a)
|
||||
-> m a
|
||||
-> m a
|
||||
handleIO' err handler = handleIO
|
||||
(\e -> if err == ioeGetErrorType e then handler e else liftIO $ ioError e)
|
||||
|
||||
|
||||
(??) :: forall e es a m . (Monad m, e :< es) => Maybe a -> e -> Excepts es m a
|
||||
(??) m e = maybe (throwE e) pure m
|
||||
|
||||
|
||||
(!?) :: forall e es a m
|
||||
. (Monad m, e :< es)
|
||||
=> m (Maybe a)
|
||||
-> e
|
||||
-> Excepts es m a
|
||||
(!?) em e = lift em >>= (?? e)
|
||||
|
||||
|
||||
lE :: forall e es a m . (Monad m, e :< es) => Either e a -> Excepts es m a
|
||||
lE = liftE . veitherToExcepts . fromEither
|
||||
|
||||
lE' :: forall e' e es a m
|
||||
. (Monad m, e :< es)
|
||||
=> (e' -> e)
|
||||
-> Either e' a
|
||||
-> Excepts es m a
|
||||
lE' f = liftE . veitherToExcepts . fromEither . first f
|
||||
|
||||
lEM :: forall e es a m . (Monad m, e :< es) => m (Either e a) -> Excepts es m a
|
||||
lEM em = lift em >>= lE
|
||||
|
||||
lEM' :: forall e' e es a m
|
||||
. (Monad m, e :< es)
|
||||
=> (e' -> e)
|
||||
-> m (Either e' a)
|
||||
-> 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
|
||||
|
||||
|
||||
liftIOException' :: ( MonadCatch m
|
||||
, MonadIO m
|
||||
, Monad m
|
||||
, e :< es'
|
||||
, LiftVariant es es'
|
||||
)
|
||||
=> IOErrorType
|
||||
-> e
|
||||
-> Excepts es m a
|
||||
-> Excepts es' m a
|
||||
liftIOException' errType ex =
|
||||
handleIO
|
||||
(\e ->
|
||||
if errType == ioeGetErrorType e then throwE ex else liftIO $ ioError e
|
||||
)
|
||||
. liftE
|
||||
|
||||
|
||||
liftIOException :: (MonadCatch m, MonadIO m, Monad m, e :< es')
|
||||
=> IOErrorType
|
||||
-> e
|
||||
-> m a
|
||||
-> Excepts es' m a
|
||||
liftIOException errType ex =
|
||||
handleIO
|
||||
(\e ->
|
||||
if errType == ioeGetErrorType e then throwE ex else liftIO $ ioError e
|
||||
)
|
||||
. lift
|
||||
|
||||
|
||||
-- | Uses safe-exceptions.
|
||||
hideError :: (MonadIO m, MonadCatch m) => IOErrorType -> m () -> m ()
|
||||
hideError err = handleIO (\e -> if err == ioeGetErrorType e then pure () else liftIO . ioError $ e)
|
||||
|
||||
|
||||
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 liftIO $ ioError e)
|
||||
|
||||
|
||||
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 liftIO $ ioError e)
|
||||
|
||||
|
||||
-- TODO: does this work?
|
||||
hideExcept :: forall e es es' a m
|
||||
. (Monad m, e :< es, LiftVariant (Remove e es) es')
|
||||
=> e
|
||||
-> a
|
||||
-> Excepts es m a
|
||||
-> Excepts es' m a
|
||||
hideExcept _ a =
|
||||
catchLiftLeft ((\_ -> pure a) :: (e -> Excepts es' m a))
|
||||
|
||||
|
||||
hideExcept' :: forall e es es' m
|
||||
. (Monad m, e :< es, LiftVariant (Remove e es) es')
|
||||
=> e
|
||||
-> Excepts es m ()
|
||||
-> Excepts es' m ()
|
||||
hideExcept' _ =
|
||||
catchLiftLeft ((\_ -> pure ()) :: (e -> Excepts es' m ()))
|
||||
|
||||
|
||||
reThrowAll :: forall e es es' a m
|
||||
. (Monad m, e :< es')
|
||||
=> (V es -> e)
|
||||
-> Excepts es m a
|
||||
-> Excepts es' m a
|
||||
reThrowAll f = catchAllE (throwE . f)
|
||||
|
||||
|
||||
reThrowAllIO :: forall e es es' a m
|
||||
. (MonadCatch m, Monad m, MonadIO m, e :< es')
|
||||
=> (V es -> e)
|
||||
-> (IOException -> e)
|
||||
-> Excepts es m a
|
||||
-> Excepts es' m a
|
||||
reThrowAllIO f g = handleIO (throwE . g) . catchAllE (throwE . f)
|
||||
|
||||
|
||||
throwEither :: (Exception a, MonadThrow m) => Either a b -> m b
|
||||
throwEither a = case a of
|
||||
Left e -> throwM e
|
||||
Right r -> pure r
|
||||
|
||||
|
||||
throwEither' :: (Exception a, MonadThrow m) => a -> Either x b -> m b
|
||||
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
|
||||
|
||||
verToS :: Version -> String
|
||||
verToS = T.unpack . prettyVer
|
||||
|
||||
intToText :: Integral a => a -> T.Text
|
||||
intToText = TL.toStrict . B.toLazyText . B.decimal
|
||||
|
||||
|
||||
removeLensFieldLabel :: String -> String
|
||||
removeLensFieldLabel str' =
|
||||
maybe str' T.unpack . T.stripPrefix (T.pack "_") . T.pack $ str'
|
||||
|
||||
|
||||
pvpToVersion :: MonadThrow m => PVP -> Text -> m Version
|
||||
pvpToVersion pvp_ rest =
|
||||
either (\_ -> throwM $ ParseError "Couldn't convert PVP to Version") pure . version . (<> rest) . prettyPVP $ pvp_
|
||||
|
||||
-- | Convert a version to a PVP and unparsable rest.
|
||||
--
|
||||
-- -- prop> \v -> let (Just (pvp', r)) = versionToPVP v in pvpToVersion pvp' r === Just v
|
||||
versionToPVP :: MonadThrow m => Version -> m (PVP, Text)
|
||||
versionToPVP (Version (Just _) _ _ _) = throwM $ ParseError "Unexpected epoch"
|
||||
versionToPVP v = either (\_ -> (, rest v) <$> alternative v) (pure . (, mempty)) . 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)
|
||||
|
||||
rest :: Version -> Text
|
||||
rest (Version _ cs pr me) =
|
||||
let chunks = NE.dropWhile isDigit cs
|
||||
ver = intersperse (T.pack ".") . chunksAsT $ chunks
|
||||
me' = maybe [] (\m -> [T.pack "+",m]) me
|
||||
pr' = foldable [] (T.pack "-" :) $ intersperse (T.pack ".") (chunksAsT pr)
|
||||
prefix = case (ver, pr', me') of
|
||||
(_:_, _, _) -> T.pack "."
|
||||
_ -> T.pack ""
|
||||
in prefix <> mconcat (ver <> pr' <> me')
|
||||
where
|
||||
chunksAsT :: Functor t => t VChunk -> t Text
|
||||
chunksAsT = fmap (foldMap f)
|
||||
where
|
||||
f :: VUnit -> Text
|
||||
f (Digits i) = T.pack $ show i
|
||||
f (Str s) = s
|
||||
|
||||
foldable :: Foldable f => f b -> (f a -> f b) -> f a -> f b
|
||||
foldable d g f | null f = d
|
||||
| otherwise = g f
|
||||
|
||||
|
||||
|
||||
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.
|
||||
decUTF8Safe :: ByteString -> Text
|
||||
decUTF8Safe = E.decodeUtf8With E.lenientDecode
|
||||
|
||||
decUTF8Safe' :: L.ByteString -> Text
|
||||
decUTF8Safe' = TL.toStrict . TLE.decodeUtf8With E.lenientDecode
|
||||
|
||||
|
||||
-- | Escape a version for use in regex
|
||||
escapeVerRex :: Version -> ByteString
|
||||
escapeVerRex = B.pack . go . B.unpack . verToBS
|
||||
where
|
||||
go [] = []
|
||||
go (x : xs) | x == _period = [_backslash, _period] ++ go xs
|
||||
| otherwise = x : go xs
|
||||
|
||||
-- | More permissive version of 'createDirRecursive'. This doesn't
|
||||
-- error when the destination is a symlink to a directory.
|
||||
createDirRecursive' :: FilePath -> IO ()
|
||||
createDirRecursive' p =
|
||||
handleIO (\e -> if isAlreadyExistsError e then isSymlinkDir e else throwIO e)
|
||||
. createDirectoryIfMissing True
|
||||
$ p
|
||||
|
||||
where
|
||||
isSymlinkDir e = do
|
||||
ft <- pathIsSymbolicLink p
|
||||
case ft of
|
||||
True -> do
|
||||
rp <- canonicalizePath p
|
||||
rft <- doesDirectoryExist rp
|
||||
case rft of
|
||||
True -> pure ()
|
||||
_ -> throwIO e
|
||||
_ -> throwIO e
|
||||
|
||||
|
||||
-- | Recursively copy the contents of one directory to another path.
|
||||
--
|
||||
-- This is a rip-off of Cabal library.
|
||||
copyDirectoryRecursive :: FilePath -> FilePath -> (FilePath -> FilePath -> IO ()) -> IO ()
|
||||
copyDirectoryRecursive srcDir destDir doCopy = do
|
||||
srcFiles <- getDirectoryContentsRecursive srcDir
|
||||
copyFilesWith destDir [ (srcDir, f)
|
||||
| f <- srcFiles ]
|
||||
where
|
||||
-- | Common implementation of 'copyFiles', 'installOrdinaryFiles',
|
||||
-- 'installExecutableFiles' and 'installMaybeExecutableFiles'.
|
||||
copyFilesWith :: FilePath -> [(FilePath, FilePath)] -> IO ()
|
||||
copyFilesWith targetDir srcFiles = do
|
||||
|
||||
-- Create parent directories for everything
|
||||
let dirs = map (targetDir </>) . nub . map (takeDirectory . snd) $ srcFiles
|
||||
traverse_ (createDirectoryIfMissing True) dirs
|
||||
|
||||
-- Copy all the files
|
||||
sequence_ [ let src = srcBase </> srcFile
|
||||
dest = targetDir </> srcFile
|
||||
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 [""]
|
||||
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
|
||||
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
|
||||
|
||||
|
||||
-- https://github.com/haskell/directory/issues/110
|
||||
-- https://github.com/haskell/directory/issues/96
|
||||
-- https://www.sqlite.org/src/info/89f1848d7f
|
||||
recyclePathForcibly :: ( MonadIO m
|
||||
, MonadReader env m
|
||||
, HasDirs env
|
||||
, MonadMask m
|
||||
)
|
||||
=> FilePath
|
||||
-> m ()
|
||||
recyclePathForcibly fp
|
||||
| isWindows = do
|
||||
Dirs { recycleDir } <- getDirs
|
||||
tmp <- liftIO $ createTempDirectory recycleDir "recyclePathForcibly"
|
||||
let dest = tmp </> takeFileName fp
|
||||
liftIO (moveFile fp dest)
|
||||
`catch`
|
||||
(\e -> if isPermissionError e {- EXDEV on windows -} then recover (liftIO $ removePathForcibly fp) else throwIO e)
|
||||
`finally`
|
||||
liftIO (handleIO (\_ -> pure ()) $ removePathForcibly tmp)
|
||||
| otherwise = liftIO $ removePathForcibly fp
|
||||
|
||||
|
||||
rmPathForcibly :: ( MonadIO m
|
||||
, MonadMask m
|
||||
)
|
||||
=> FilePath
|
||||
-> m ()
|
||||
rmPathForcibly fp
|
||||
| isWindows = recover (liftIO $ removePathForcibly fp)
|
||||
| otherwise = liftIO $ removePathForcibly fp
|
||||
|
||||
|
||||
rmDirectory :: (MonadIO m, MonadMask m)
|
||||
=> FilePath
|
||||
-> m ()
|
||||
rmDirectory fp
|
||||
| isWindows = recover (liftIO $ removeDirectory fp)
|
||||
| otherwise = liftIO $ removeDirectory fp
|
||||
|
||||
|
||||
-- https://www.sqlite.org/src/info/89f1848d7f
|
||||
-- https://github.com/haskell/directory/issues/96
|
||||
recycleFile :: ( MonadIO m
|
||||
, MonadMask m
|
||||
, MonadReader env m
|
||||
, HasDirs env
|
||||
)
|
||||
=> FilePath
|
||||
-> m ()
|
||||
recycleFile fp
|
||||
| isWindows = do
|
||||
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 (moveFile fp dest)
|
||||
`catch`
|
||||
(\e -> if isPermissionError e {- EXDEV on windows -} then recover (liftIO $ removePathForcibly fp) else throwIO e)
|
||||
`finally`
|
||||
liftIO (handleIO (\_ -> pure ()) $ removePathForcibly tmp)
|
||||
| otherwise = liftIO $ removeFile fp
|
||||
|
||||
|
||||
rmFile :: ( MonadIO m
|
||||
, MonadMask m
|
||||
)
|
||||
=> FilePath
|
||||
-> m ()
|
||||
rmFile fp
|
||||
| isWindows = recover (liftIO $ removeFile fp)
|
||||
| otherwise = liftIO $ removeFile fp
|
||||
|
||||
|
||||
rmDirectoryLink :: (MonadIO m, MonadMask m, MonadReader env m, HasDirs env)
|
||||
=> FilePath
|
||||
-> m ()
|
||||
rmDirectoryLink fp
|
||||
| isWindows = recover (liftIO $ removeDirectoryLink fp)
|
||||
| otherwise = liftIO $ removeDirectoryLink fp
|
||||
|
||||
|
||||
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)
|
||||
|
||||
|
||||
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)
|
||||
|
||||
-- | Gathering monoidal values
|
||||
forFold :: (Foldable t, Applicative m, Monoid b) => t a -> (a -> m b) -> m b
|
||||
forFold = \t -> (`traverseFold` t)
|
||||
|
||||
|
||||
-- | 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 = 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
|
||||
|
||||
20
lib/GHCup/Prelude/Posix.hs
Normal file
@@ -0,0 +1,20 @@
|
||||
module GHCup.Prelude.Posix where
|
||||
|
||||
import System.Directory
|
||||
import System.Posix.Files
|
||||
|
||||
|
||||
isWindows, isNotWindows :: Bool
|
||||
isWindows = False
|
||||
isNotWindows = not isWindows
|
||||
|
||||
|
||||
moveFile :: FilePath -> FilePath -> IO ()
|
||||
moveFile = rename
|
||||
|
||||
|
||||
moveFilePortable :: FilePath -> FilePath -> IO ()
|
||||
moveFilePortable from to = do
|
||||
copyFile from to
|
||||
removeFile from
|
||||
|
||||
17
lib/GHCup/Prelude/Windows.hs
Normal file
@@ -0,0 +1,17 @@
|
||||
module GHCup.Prelude.Windows where
|
||||
|
||||
import qualified System.Win32.File as Win32
|
||||
|
||||
|
||||
isWindows, isNotWindows :: Bool
|
||||
isWindows = True
|
||||
isNotWindows = not isWindows
|
||||
|
||||
|
||||
moveFile :: FilePath -> FilePath -> IO ()
|
||||
moveFile from to = Win32.moveFileEx from (Just to) 0
|
||||
|
||||
|
||||
moveFilePortable :: FilePath -> FilePath -> IO ()
|
||||
moveFilePortable = Win32.moveFile
|
||||
|
||||
57
lib/GHCup/QQ/String.hs
Normal file
@@ -0,0 +1,57 @@
|
||||
{-# LANGUAGE TemplateHaskell #-}
|
||||
|
||||
{-|
|
||||
Module : GHCup.QQ.String
|
||||
Description : String quasi quoters
|
||||
Copyright : (c) Audrey Tang <audreyt@audreyt.org> 2019, Julian Ospald <hasufell@posteo.de> 2020
|
||||
License : LGPL-3.0
|
||||
Maintainer : hasufell@hasufell.de
|
||||
Stability : experimental
|
||||
Portability : portable
|
||||
|
||||
QuasiQuoter for non-interpolated strings, texts and bytestrings.
|
||||
|
||||
The "s" quoter contains a multi-line string with no interpolation at all,
|
||||
except that the leading newline is trimmed and carriage returns stripped.
|
||||
|
||||
@
|
||||
{-\# LANGUAGE QuasiQuotes #-}
|
||||
import Data.Text (Text)
|
||||
import Data.String.QQ
|
||||
foo :: Text -- "String", "ByteString" etc also works
|
||||
foo = [s|
|
||||
Well here is a
|
||||
multi-line string!
|
||||
|]
|
||||
@
|
||||
|
||||
Any instance of the IsString type is permitted.
|
||||
|
||||
(For GHC versions 6, write "[$s||]" instead of "[s||]".)
|
||||
|
||||
-}
|
||||
module GHCup.QQ.String
|
||||
( s
|
||||
)
|
||||
where
|
||||
|
||||
|
||||
import Data.Char
|
||||
import GHC.Exts ( IsString(..) )
|
||||
import Language.Haskell.TH.Quote
|
||||
|
||||
-- | QuasiQuoter for a non-interpolating ASCII IsString literal.
|
||||
-- The pattern portion is undefined.
|
||||
s :: QuasiQuoter
|
||||
s = QuasiQuoter
|
||||
(\s' -> case all isAscii s' of
|
||||
True -> (\a -> [|fromString a|]) . trimLeadingNewline . removeCRs $ s'
|
||||
False -> fail "Not ascii"
|
||||
)
|
||||
(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
|
||||
@@ -1,4 +1,5 @@
|
||||
{-# OPTIONS_GHC -Wno-orphans #-}
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE DeriveDataTypeable #-}
|
||||
{-# LANGUAGE DeriveLift #-}
|
||||
{-# LANGUAGE FlexibleInstances #-}
|
||||
@@ -6,16 +7,26 @@
|
||||
{-# LANGUAGE TemplateHaskell #-}
|
||||
|
||||
|
||||
module GHCup.Utils.Version.QQ where
|
||||
{-|
|
||||
Module : GHCup.QQ.Version
|
||||
Description : Version quasi-quoters
|
||||
Copyright : (c) Julian Ospald, 2020
|
||||
License : LGPL-3.0
|
||||
Maintainer : hasufell@hasufell.de
|
||||
Stability : experimental
|
||||
Portability : portable
|
||||
-}
|
||||
module GHCup.QQ.Version where
|
||||
|
||||
import Data.Data
|
||||
import Data.Text ( Text )
|
||||
import Data.Versions
|
||||
#if !MIN_VERSION_base(4,13,0)
|
||||
import GHC.Base
|
||||
#endif
|
||||
import Language.Haskell.TH
|
||||
import Language.Haskell.TH.Quote ( QuasiQuoter(..) )
|
||||
import Language.Haskell.TH.Syntax ( Exp(..)
|
||||
, Lift
|
||||
import Language.Haskell.TH.Syntax ( Lift
|
||||
, dataToExpQ
|
||||
)
|
||||
import qualified Data.Text as T
|
||||
@@ -31,18 +42,25 @@ deriving instance Data SemVer
|
||||
deriving instance Lift SemVer
|
||||
deriving instance Data Mess
|
||||
deriving instance Lift Mess
|
||||
deriving instance Data MChunk
|
||||
deriving instance Lift MChunk
|
||||
deriving instance Data PVP
|
||||
deriving instance Lift PVP
|
||||
deriving instance Lift (NonEmpty Word)
|
||||
deriving instance Lift VSep
|
||||
deriving instance Data VSep
|
||||
deriving instance Lift VUnit
|
||||
deriving instance Data VUnit
|
||||
instance Lift Text
|
||||
|
||||
#if !MIN_VERSION_base(4,13,0)
|
||||
deriving instance Lift (NonEmpty Word)
|
||||
deriving instance Lift (NonEmpty VChunk)
|
||||
deriving instance Lift (NonEmpty MChunk)
|
||||
deriving instance Lift (NonEmpty VUnit)
|
||||
#endif
|
||||
|
||||
qq :: (Text -> Q Exp) -> QuasiQuoter
|
||||
qq quoteExp' = QuasiQuoter
|
||||
{ quoteExp = (\s -> quoteExp' . T.pack $ s)
|
||||
{ quoteExp = \s -> quoteExp' . T.pack $ s
|
||||
, quotePat = \_ ->
|
||||
fail "illegal QuasiQuote (allowed as expression only, used as a pattern)"
|
||||
, quoteType = \_ ->
|
||||
@@ -86,4 +104,4 @@ liftText :: T.Text -> Q Exp
|
||||
liftText txt = AppE (VarE 'T.pack) <$> TH.lift (T.unpack txt)
|
||||
|
||||
liftDataWithText :: Data a => a -> Q Exp
|
||||
liftDataWithText = dataToExpQ (\a -> liftText <$> cast a)
|
||||
liftDataWithText = dataToExpQ (fmap liftText . cast)
|
||||
69
lib/GHCup/Requirements.hs
Normal file
@@ -0,0 +1,69 @@
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
|
||||
{-|
|
||||
Module : GHCup.Requirements
|
||||
Description : Requirements utilities
|
||||
Copyright : (c) Julian Ospald, 2020
|
||||
License : LGPL-3.0
|
||||
Maintainer : hasufell@hasufell.de
|
||||
Stability : experimental
|
||||
Portability : portable
|
||||
-}
|
||||
module GHCup.Requirements where
|
||||
|
||||
import GHCup.Types
|
||||
import GHCup.Types.JSON ( )
|
||||
import GHCup.Types.Optics
|
||||
import GHCup.Version
|
||||
|
||||
import Control.Applicative
|
||||
import Data.List ( find )
|
||||
import Data.Maybe
|
||||
import Optics
|
||||
import Prelude hiding ( abs
|
||||
, readFile
|
||||
, writeFile
|
||||
)
|
||||
|
||||
import qualified Data.Map.Strict as M
|
||||
import qualified Data.Text as T
|
||||
|
||||
|
||||
-- | Get the requirements. Right now this combines GHC and cabal
|
||||
-- and doesn't do fine-grained distinction. However, the 'ToolRequirements'
|
||||
-- type allows it.
|
||||
getCommonRequirements :: PlatformResult
|
||||
-> ToolRequirements
|
||||
-> Maybe Requirements
|
||||
getCommonRequirements pr tr =
|
||||
with_distro <|> without_distro_ver <|> without_distro
|
||||
where
|
||||
with_distro = distro_preview _platform _distroVersion
|
||||
without_distro_ver = distro_preview _platform (const Nothing)
|
||||
without_distro = distro_preview (set _Linux UnknownLinux . _platform) (const Nothing)
|
||||
|
||||
distro_preview f g =
|
||||
let platformVersionSpec =
|
||||
preview (ix GHC % ix Nothing % ix (f pr)) tr
|
||||
mv' = g pr
|
||||
in fmap snd
|
||||
. find
|
||||
(\(mverRange, _) -> maybe
|
||||
(isNothing mv')
|
||||
(\range -> maybe False (`versionRange` range) mv')
|
||||
mverRange
|
||||
)
|
||||
. M.toList
|
||||
=<< platformVersionSpec
|
||||
|
||||
|
||||
prettyRequirements :: Requirements -> T.Text
|
||||
prettyRequirements Requirements {..} =
|
||||
let d = if not . null $ _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
|
||||