Compare commits
283 Commits
lzma-stati
...
bump-bs-ve
| Author | SHA1 | Date | |
|---|---|---|---|
|
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
|
|||
|
fdf45e0fe6
|
|||
|
1dc9ad7a57
|
|||
|
cc51d7b454
|
|||
|
c439693a8f
|
|||
|
af8c097092
|
|||
|
9639e695e2
|
|||
|
d2a2bde321
|
|||
|
c85ff686b6
|
|||
|
48d3b3bc3e
|
|||
|
94bd01aaca
|
|||
|
|
761b8cc750 | ||
|
3bdc82c99b
|
|||
|
db4e9fa432
|
|||
|
530c25c6a1
|
|||
|
1c2cf98850
|
|||
|
b35dbca22e
|
|||
|
a4a7f73fb7
|
|||
|
fd0ea3d858
|
|||
|
bbbe52f453
|
|||
|
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
|
109
.github/release.yaml
vendored
Normal file
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
109
.github/workflows/release.yaml
vendored
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
name: Create Release
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- 'v*'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
draft_release:
|
||||||
|
name: Draft Release
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Create Release
|
||||||
|
id: create_release
|
||||||
|
uses: actions/create-release@v1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
tag_name: ${{ github.ref }}
|
||||||
|
release_name: Release ${{ github.ref }}
|
||||||
|
body: |
|
||||||
|
Changes in this Release
|
||||||
|
- First Change
|
||||||
|
- Second Change
|
||||||
|
draft: true
|
||||||
|
prerelease: false
|
||||||
|
|
||||||
|
release-mac:
|
||||||
|
name: Create Release
|
||||||
|
needs: draft_release
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
env:
|
||||||
|
MACOSX_DEPLOYMENT_TARGET: 10.13
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os:
|
||||||
|
- macOS-10.15
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- uses: haskell/actions/setup@v1.2
|
||||||
|
with:
|
||||||
|
ghc-version: 8.10.4
|
||||||
|
cabal-version: 3.4.0.0
|
||||||
|
|
||||||
|
- name: create ~/.local/bin
|
||||||
|
run: mkdir -p "$HOME/.local/bin"
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- name: Add ~/.local/bin to PATH
|
||||||
|
run: echo "$HOME/.local/bin" >> $GITHUB_PATH
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- name: Update cabal cache
|
||||||
|
run: cabal update
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- name: Install cabal dependencies
|
||||||
|
run: cabal build --only-dependencies --constraint="zlib +bundled-c-zlib" --constraint="lzma +static" -ftui
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: cabal build --constraint="zlib +bundled-c-zlib" --constraint="lzma +static" -ftui
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- name: Install
|
||||||
|
run: cp "$(cabal list-bin exe:ghcup)" ~/.local/bin/ghcup
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- name: Strip
|
||||||
|
run: strip ~/.local/bin/ghcup
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
run: cabal test --constraint="zlib +bundled-c-zlib" --constraint="lzma +static" all
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- name: Install git
|
||||||
|
run: brew install git
|
||||||
|
|
||||||
|
- name: set HOME
|
||||||
|
run: echo "HOME=$HOME" >> $GITHUB_ENV
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- name: Set ASSET_PATH
|
||||||
|
run: echo "ASSET_PATH=$HOME/.local/bin/ghcup" >> $GITHUB_ENV
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- name: Upload Release Asset
|
||||||
|
id: upload-release-asset
|
||||||
|
uses: actions/upload-release-asset@v1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
upload_url: ${{ needs.draft_release.outputs.upload_url }}
|
||||||
|
asset_path: ${{ env.ASSET_PATH }}
|
||||||
|
asset_name: ghcup-${{ matrix.os }}
|
||||||
|
asset_content_type: application/octet-stream
|
||||||
|
|
||||||
|
- if: always()
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: plan.json
|
||||||
|
path: ./dist-newstyle/cache/plan.json
|
||||||
|
|
||||||
29
.github/workflows/shimgen.yaml
vendored
Normal file
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
|
||||||
|
|
||||||
255
.gitlab-ci.yml
255
.gitlab-ci.yml
@@ -7,7 +7,7 @@ variables:
|
|||||||
GIT_SSL_NO_VERIFY: "1"
|
GIT_SSL_NO_VERIFY: "1"
|
||||||
|
|
||||||
# Commit of ghc/ci-images repository from which to pull Docker images
|
# Commit of ghc/ci-images repository from which to pull Docker images
|
||||||
DOCKER_REV: 1ac7f435c9312f10422a82d304194778378e2a1a
|
DOCKER_REV: 8d0224e6b2a08157649651e69302380b2bd24e11
|
||||||
|
|
||||||
############################################################
|
############################################################
|
||||||
# CI Step
|
# CI Step
|
||||||
@@ -20,6 +20,8 @@ variables:
|
|||||||
variables:
|
variables:
|
||||||
OS: "LINUX"
|
OS: "LINUX"
|
||||||
ARCH: "64"
|
ARCH: "64"
|
||||||
|
CABAL_DIR: "$CI_PROJECT_DIR/cabal"
|
||||||
|
CROSS: ""
|
||||||
|
|
||||||
.alpine:64bit:
|
.alpine:64bit:
|
||||||
image: "alpine:3.12"
|
image: "alpine:3.12"
|
||||||
@@ -28,6 +30,7 @@ variables:
|
|||||||
variables:
|
variables:
|
||||||
OS: "LINUX"
|
OS: "LINUX"
|
||||||
ARCH: "64"
|
ARCH: "64"
|
||||||
|
CABAL_DIR: "$CI_PROJECT_DIR/cabal"
|
||||||
|
|
||||||
.alpine:32bit:
|
.alpine:32bit:
|
||||||
image: "i386/alpine:3.12"
|
image: "i386/alpine:3.12"
|
||||||
@@ -36,22 +39,25 @@ variables:
|
|||||||
variables:
|
variables:
|
||||||
OS: "LINUX"
|
OS: "LINUX"
|
||||||
ARCH: "32"
|
ARCH: "32"
|
||||||
|
CABAL_DIR: "$CI_PROJECT_DIR/cabal"
|
||||||
|
|
||||||
.linux:armv7:
|
.linux:armv7:
|
||||||
image: "arm32v7/fedora"
|
image: "registry.gitlab.haskell.org/ghc/ci-images/armv7-linux-deb10:$DOCKER_REV"
|
||||||
tags:
|
tags:
|
||||||
- armv7-linux
|
- armv7-linux
|
||||||
variables:
|
variables:
|
||||||
OS: "LINUX"
|
OS: "LINUX"
|
||||||
ARCH: "ARM"
|
ARCH: "ARM"
|
||||||
|
CABAL_DIR: "$CI_PROJECT_DIR/cabal"
|
||||||
|
|
||||||
.linux:aarch64:
|
.linux:aarch64:
|
||||||
image: "arm64v8/fedora"
|
image: "registry.gitlab.haskell.org/ghc/ci-images/aarch64-linux-deb10:$DOCKER_REV"
|
||||||
tags:
|
tags:
|
||||||
- aarch64-linux
|
- aarch64-linux
|
||||||
variables:
|
variables:
|
||||||
OS: "LINUX"
|
OS: "LINUX"
|
||||||
ARCH: "ARM64"
|
ARCH: "ARM64"
|
||||||
|
CABAL_DIR: "$CI_PROJECT_DIR/cabal"
|
||||||
|
|
||||||
.darwin:
|
.darwin:
|
||||||
tags:
|
tags:
|
||||||
@@ -59,6 +65,15 @@ variables:
|
|||||||
variables:
|
variables:
|
||||||
OS: "DARWIN"
|
OS: "DARWIN"
|
||||||
ARCH: "64"
|
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"
|
||||||
|
|
||||||
.freebsd:
|
.freebsd:
|
||||||
tags:
|
tags:
|
||||||
@@ -66,28 +81,36 @@ variables:
|
|||||||
variables:
|
variables:
|
||||||
OS: "FREEBSD"
|
OS: "FREEBSD"
|
||||||
ARCH: "64"
|
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"
|
||||||
|
|
||||||
.root_cleanup:
|
.root_cleanup:
|
||||||
after_script:
|
after_script:
|
||||||
- BUILD_DIR=$CI_PROJECT_DIR
|
- bash ./.gitlab/after_script.sh
|
||||||
- echo "Cleaning $BUILD_DIR"
|
|
||||||
- cd $HOME
|
|
||||||
- test -n "$BUILD_DIR"
|
|
||||||
- shopt -s extglob
|
|
||||||
- rm -Rf "$BUILD_DIR"/!(out)
|
|
||||||
- exit 0
|
|
||||||
|
|
||||||
.test_ghcup_version:
|
.test_ghcup_version:
|
||||||
script:
|
script:
|
||||||
- ./.gitlab/script/ghcup_version.sh
|
- bash ./.gitlab/script/ghcup_version.sh
|
||||||
variables:
|
variables:
|
||||||
JSON_VERSION: "0.0.4"
|
JSON_VERSION: "0.0.6"
|
||||||
artifacts:
|
artifacts:
|
||||||
expire_in: 2 week
|
expire_in: 2 week
|
||||||
paths:
|
paths:
|
||||||
- golden
|
- golden
|
||||||
|
- dist-newstyle/cache/
|
||||||
when: on_failure
|
when: on_failure
|
||||||
|
|
||||||
|
# .test_ghcup_scoop:
|
||||||
|
# script:
|
||||||
|
# - cl /O1 scoop-better-shimexe/shim.c
|
||||||
|
|
||||||
.test_ghcup_version:linux:
|
.test_ghcup_version:linux:
|
||||||
extends:
|
extends:
|
||||||
- .test_ghcup_version
|
- .test_ghcup_version
|
||||||
@@ -107,14 +130,14 @@ variables:
|
|||||||
- .test_ghcup_version
|
- .test_ghcup_version
|
||||||
- .linux:armv7
|
- .linux:armv7
|
||||||
before_script:
|
before_script:
|
||||||
- ./.gitlab/before_script/linux/install_deps_manual.sh
|
- ./.gitlab/before_script/linux/install_deps.sh
|
||||||
|
|
||||||
.test_ghcup_version:aarch64:
|
.test_ghcup_version:aarch64:
|
||||||
extends:
|
extends:
|
||||||
- .test_ghcup_version
|
- .test_ghcup_version
|
||||||
- .linux:aarch64
|
- .linux:aarch64
|
||||||
before_script:
|
before_script:
|
||||||
- ./.gitlab/before_script/linux/install_deps_manual.sh
|
- ./.gitlab/before_script/linux/install_deps.sh
|
||||||
|
|
||||||
.test_ghcup_version:darwin:
|
.test_ghcup_version:darwin:
|
||||||
extends:
|
extends:
|
||||||
@@ -124,6 +147,32 @@ variables:
|
|||||||
before_script:
|
before_script:
|
||||||
- ./.gitlab/before_script/darwin/install_deps.sh
|
- ./.gitlab/before_script/darwin/install_deps.sh
|
||||||
|
|
||||||
|
.test_ghcup_version:darwin:aarch64:
|
||||||
|
extends:
|
||||||
|
- .test_ghcup_version
|
||||||
|
- .darwin:aarch64
|
||||||
|
- .root_cleanup
|
||||||
|
script: |
|
||||||
|
set -Eeuo pipefail
|
||||||
|
function runInNixShell() {
|
||||||
|
time nix-shell $CI_PROJECT_DIR/.gitlab/shell.nix \
|
||||||
|
-I nixpkgs=https://github.com/angerman/nixpkgs/archive/75f7281738b.tar.gz \
|
||||||
|
--argstr system "aarch64-darwin" \
|
||||||
|
--pure \
|
||||||
|
--keep CI_PROJECT_DIR \
|
||||||
|
--keep MACOSX_DEPLOYMENT_TARGET \
|
||||||
|
--keep JSON_VERSION \
|
||||||
|
--keep ARTIFACT \
|
||||||
|
--keep OS \
|
||||||
|
--keep ARCH \
|
||||||
|
--keep CABAL_DIR \
|
||||||
|
--keep GHC_VERSION \
|
||||||
|
--keep CABAL_VERSION \
|
||||||
|
--run "$1" 2>&1
|
||||||
|
}
|
||||||
|
runInNixShell ./.gitlab/before_script/darwin/install_deps.sh 2>&1
|
||||||
|
runInNixShell ./.gitlab/script/ghcup_version.sh 2>&1
|
||||||
|
|
||||||
.test_ghcup_version:freebsd:
|
.test_ghcup_version:freebsd:
|
||||||
extends:
|
extends:
|
||||||
- .test_ghcup_version
|
- .test_ghcup_version
|
||||||
@@ -132,17 +181,33 @@ variables:
|
|||||||
before_script:
|
before_script:
|
||||||
- ./.gitlab/before_script/freebsd/install_deps.sh
|
- ./.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:
|
.release_ghcup:
|
||||||
script:
|
script:
|
||||||
- ./.gitlab/script/ghcup_release.sh
|
- bash ./.gitlab/script/ghcup_release.sh
|
||||||
artifacts:
|
artifacts:
|
||||||
expire_in: 2 week
|
expire_in: 2 week
|
||||||
paths:
|
paths:
|
||||||
- out
|
- out
|
||||||
|
- dist-newstyle/cache/
|
||||||
only:
|
only:
|
||||||
- tags
|
- tags
|
||||||
variables:
|
variables:
|
||||||
JSON_VERSION: "0.0.4"
|
JSON_VERSION: "0.0.6"
|
||||||
|
|
||||||
######## stack test ########
|
######## stack test ########
|
||||||
|
|
||||||
@@ -165,10 +230,27 @@ test:linux:bootstrap_script:
|
|||||||
script:
|
script:
|
||||||
- ./.gitlab/script/ghcup_bootstrap.sh
|
- ./.gitlab/script/ghcup_bootstrap.sh
|
||||||
variables:
|
variables:
|
||||||
GHC_VERSION: "8.10.4"
|
GHC_VERSION: "8.10.5"
|
||||||
CABAL_VERSION: "3.4.0.0"
|
CABAL_VERSION: "3.4.0.0"
|
||||||
extends:
|
extends:
|
||||||
- .debian
|
- .debian
|
||||||
|
- .root_cleanup
|
||||||
|
needs: []
|
||||||
|
|
||||||
|
test:windows:bootstrap_powershell_script:
|
||||||
|
stage: test
|
||||||
|
script:
|
||||||
|
- ./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.5"
|
||||||
|
CABAL_VERSION: "3.4.0.0"
|
||||||
|
extends:
|
||||||
|
- .windows
|
||||||
needs: []
|
needs: []
|
||||||
|
|
||||||
######## linux test ########
|
######## linux test ########
|
||||||
@@ -177,7 +259,7 @@ test:linux:recommended:
|
|||||||
stage: test
|
stage: test
|
||||||
extends: .test_ghcup_version:linux
|
extends: .test_ghcup_version:linux
|
||||||
variables:
|
variables:
|
||||||
GHC_VERSION: "8.10.4"
|
GHC_VERSION: "8.10.5"
|
||||||
CABAL_VERSION: "3.4.0.0"
|
CABAL_VERSION: "3.4.0.0"
|
||||||
needs: []
|
needs: []
|
||||||
|
|
||||||
@@ -185,17 +267,55 @@ test:linux:latest:
|
|||||||
stage: test
|
stage: test
|
||||||
extends: .test_ghcup_version:linux
|
extends: .test_ghcup_version:linux
|
||||||
variables:
|
variables:
|
||||||
GHC_VERSION: "8.10.4"
|
GHC_VERSION: "9.0.1"
|
||||||
CABAL_VERSION: "3.4.0.0"
|
CABAL_VERSION: "3.4.0.0"
|
||||||
needs: []
|
needs: []
|
||||||
|
|
||||||
|
test:linux:cross-armv7:
|
||||||
|
stage: test
|
||||||
|
extends:
|
||||||
|
- .test_ghcup_version
|
||||||
|
- .debian
|
||||||
|
variables:
|
||||||
|
GHC_VERSION: "8.10.4"
|
||||||
|
GHC_TARGET_VERSION: "8.10.5"
|
||||||
|
CABAL_VERSION: "3.4.0.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: test
|
||||||
|
extends:
|
||||||
|
- .test_ghcup_version
|
||||||
|
- .debian
|
||||||
|
variables:
|
||||||
|
GHC_VERSION: "8.10.5"
|
||||||
|
GHC_GIT_TAG: "ghc-9.0.1-release"
|
||||||
|
GHC_GIT_VERSION: "9.0.1"
|
||||||
|
CABAL_VERSION: "3.4.0.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 ########
|
######## linux 32bit test ########
|
||||||
|
|
||||||
test:linux:recommended:32bit:
|
test:linux:recommended:32bit:
|
||||||
stage: test
|
stage: test
|
||||||
extends: .test_ghcup_version:linux32
|
extends: .test_ghcup_version:linux32
|
||||||
variables:
|
variables:
|
||||||
GHC_VERSION: "8.10.4"
|
GHC_VERSION: "8.10.5"
|
||||||
CABAL_VERSION: "3.2.0.0"
|
CABAL_VERSION: "3.2.0.0"
|
||||||
needs: []
|
needs: []
|
||||||
|
|
||||||
@@ -207,6 +327,7 @@ test:linux:recommended:armv7:
|
|||||||
variables:
|
variables:
|
||||||
GHC_VERSION: "8.10.4"
|
GHC_VERSION: "8.10.4"
|
||||||
CABAL_VERSION: "3.4.0.0"
|
CABAL_VERSION: "3.4.0.0"
|
||||||
|
CROSS: ""
|
||||||
when: manual
|
when: manual
|
||||||
needs: []
|
needs: []
|
||||||
|
|
||||||
@@ -216,6 +337,7 @@ test:linux:recommended:aarch64:
|
|||||||
variables:
|
variables:
|
||||||
GHC_VERSION: "8.10.4"
|
GHC_VERSION: "8.10.4"
|
||||||
CABAL_VERSION: "3.4.0.0"
|
CABAL_VERSION: "3.4.0.0"
|
||||||
|
CROSS: ""
|
||||||
when: manual
|
when: manual
|
||||||
needs: []
|
needs: []
|
||||||
|
|
||||||
@@ -233,10 +355,19 @@ test:mac:latest:
|
|||||||
stage: test
|
stage: test
|
||||||
extends: .test_ghcup_version:darwin
|
extends: .test_ghcup_version:darwin
|
||||||
variables:
|
variables:
|
||||||
GHC_VERSION: "8.10.4"
|
GHC_VERSION: "9.0.1"
|
||||||
CABAL_VERSION: "3.4.0.0"
|
CABAL_VERSION: "3.4.0.0"
|
||||||
needs: []
|
needs: []
|
||||||
|
|
||||||
|
test:mac:recommended:aarch64:
|
||||||
|
stage: test
|
||||||
|
extends: .test_ghcup_version:darwin:aarch64
|
||||||
|
variables:
|
||||||
|
GHC_VERSION: "8.10.5"
|
||||||
|
CABAL_VERSION: "3.4.0.0"
|
||||||
|
needs: []
|
||||||
|
allow_failure: true
|
||||||
|
|
||||||
|
|
||||||
######## freebsd test ########
|
######## freebsd test ########
|
||||||
|
|
||||||
@@ -250,16 +381,20 @@ test:freebsd:recommended:
|
|||||||
when: manual
|
when: manual
|
||||||
needs: []
|
needs: []
|
||||||
|
|
||||||
test:freebsd:latest:
|
######## windows test ########
|
||||||
|
|
||||||
|
test:windows:recommended:
|
||||||
stage: test
|
stage: test
|
||||||
extends: .test_ghcup_version:freebsd
|
extends: .test_ghcup_version:windows
|
||||||
variables:
|
variables:
|
||||||
GHC_VERSION: "8.10.4"
|
GHC_VERSION: "8.10.5"
|
||||||
CABAL_VERSION: "3.4.0.0"
|
CABAL_VERSION: "3.4.0.0"
|
||||||
allow_failure: true # freebsd runners are unreliable
|
|
||||||
when: manual
|
|
||||||
needs: []
|
needs: []
|
||||||
|
|
||||||
|
# test:windows:scoop:
|
||||||
|
# stage: test
|
||||||
|
# extends: .test_ghcup_scoop:windows
|
||||||
|
# needs: []
|
||||||
|
|
||||||
######## linux release ########
|
######## linux release ########
|
||||||
|
|
||||||
@@ -273,7 +408,7 @@ release:linux:64bit:
|
|||||||
- ./.gitlab/before_script/linux/alpine/install_deps.sh
|
- ./.gitlab/before_script/linux/alpine/install_deps.sh
|
||||||
variables:
|
variables:
|
||||||
ARTIFACT: "x86_64-linux-ghcup"
|
ARTIFACT: "x86_64-linux-ghcup"
|
||||||
GHC_VERSION: "8.10.4"
|
GHC_VERSION: "8.10.5"
|
||||||
CABAL_VERSION: "3.4.0.0"
|
CABAL_VERSION: "3.4.0.0"
|
||||||
|
|
||||||
|
|
||||||
@@ -287,7 +422,7 @@ release:linux:32bit:
|
|||||||
- ./.gitlab/before_script/linux/alpine/install_deps.sh
|
- ./.gitlab/before_script/linux/alpine/install_deps.sh
|
||||||
variables:
|
variables:
|
||||||
ARTIFACT: "i386-linux-ghcup"
|
ARTIFACT: "i386-linux-ghcup"
|
||||||
GHC_VERSION: "8.10.4"
|
GHC_VERSION: "8.10.5"
|
||||||
CABAL_VERSION: "3.2.0.0"
|
CABAL_VERSION: "3.2.0.0"
|
||||||
|
|
||||||
release:linux:armv7:
|
release:linux:armv7:
|
||||||
@@ -297,11 +432,12 @@ release:linux:armv7:
|
|||||||
- .linux:armv7
|
- .linux:armv7
|
||||||
- .release_ghcup
|
- .release_ghcup
|
||||||
before_script:
|
before_script:
|
||||||
- ./.gitlab/before_script/linux/install_deps_manual.sh
|
- ./.gitlab/before_script/linux/install_deps.sh
|
||||||
variables:
|
variables:
|
||||||
ARTIFACT: "armv7-linux-ghcup"
|
ARTIFACT: "armv7-linux-ghcup"
|
||||||
GHC_VERSION: "8.10.4"
|
GHC_VERSION: "8.10.4"
|
||||||
CABAL_VERSION: "3.4.0.0"
|
CABAL_VERSION: "3.4.0.0"
|
||||||
|
CROSS: ""
|
||||||
|
|
||||||
release:linux:aarch64:
|
release:linux:aarch64:
|
||||||
stage: release
|
stage: release
|
||||||
@@ -310,11 +446,12 @@ release:linux:aarch64:
|
|||||||
- .linux:aarch64
|
- .linux:aarch64
|
||||||
- .release_ghcup
|
- .release_ghcup
|
||||||
before_script:
|
before_script:
|
||||||
- ./.gitlab/before_script/linux/install_deps_manual.sh
|
- ./.gitlab/before_script/linux/install_deps.sh
|
||||||
variables:
|
variables:
|
||||||
ARTIFACT: "aarch64-linux-ghcup"
|
ARTIFACT: "aarch64-linux-ghcup"
|
||||||
GHC_VERSION: "8.10.4"
|
GHC_VERSION: "8.10.4"
|
||||||
CABAL_VERSION: "3.4.0.0"
|
CABAL_VERSION: "3.4.0.0"
|
||||||
|
CROSS: ""
|
||||||
|
|
||||||
######## darwin release ########
|
######## darwin release ########
|
||||||
|
|
||||||
@@ -329,16 +466,50 @@ release:darwin:
|
|||||||
- ./.gitlab/before_script/darwin/install_deps.sh
|
- ./.gitlab/before_script/darwin/install_deps.sh
|
||||||
variables:
|
variables:
|
||||||
ARTIFACT: "x86_64-apple-darwin-ghcup"
|
ARTIFACT: "x86_64-apple-darwin-ghcup"
|
||||||
GHC_VERSION: "8.10.4"
|
GHC_VERSION: "8.10.5"
|
||||||
CABAL_VERSION: "3.4.0.0"
|
CABAL_VERSION: "3.4.0.0"
|
||||||
MACOSX_DEPLOYMENT_TARGET: "10.7"
|
MACOSX_DEPLOYMENT_TARGET: "10.7"
|
||||||
|
|
||||||
|
release:darwin:aarch64:
|
||||||
|
stage: release
|
||||||
|
needs: ["test:mac:recommended:aarch64"]
|
||||||
|
extends:
|
||||||
|
- .darwin:aarch64
|
||||||
|
- .release_ghcup
|
||||||
|
- .root_cleanup
|
||||||
|
script: |
|
||||||
|
set -Eeuo pipefail
|
||||||
|
function runInNixShell() {
|
||||||
|
time nix-shell $CI_PROJECT_DIR/.gitlab/shell.nix \
|
||||||
|
-I nixpkgs=https://github.com/angerman/nixpkgs/archive/75f7281738b.tar.gz \
|
||||||
|
--argstr system "aarch64-darwin" \
|
||||||
|
--pure \
|
||||||
|
--keep CI_PROJECT_DIR \
|
||||||
|
--keep MACOSX_DEPLOYMENT_TARGET \
|
||||||
|
--keep JSON_VERSION \
|
||||||
|
--keep ARTIFACT \
|
||||||
|
--keep OS \
|
||||||
|
--keep ARCH \
|
||||||
|
--keep CABAL_DIR \
|
||||||
|
--keep GHC_VERSION \
|
||||||
|
--keep CABAL_VERSION \
|
||||||
|
--run "$1" 2>&1
|
||||||
|
}
|
||||||
|
runInNixShell ./.gitlab/before_script/darwin/install_deps.sh 2>&1
|
||||||
|
runInNixShell ./.gitlab/script/ghcup_release.sh 2>&1
|
||||||
|
variables:
|
||||||
|
ARTIFACT: "aarch64-apple-darwin-ghcup"
|
||||||
|
GHC_VERSION: "8.10.5"
|
||||||
|
CABAL_VERSION: "3.4.0.0"
|
||||||
|
MACOSX_DEPLOYMENT_TARGET: "10.7"
|
||||||
|
allow_failure: true
|
||||||
|
|
||||||
|
|
||||||
######## freebsd release ########
|
######## freebsd release ########
|
||||||
|
|
||||||
release:freebsd:
|
release:freebsd:
|
||||||
stage: release
|
stage: release
|
||||||
needs: ["test:freebsd:recommended", "test:freebsd:latest"]
|
needs: ["test:freebsd:recommended"]
|
||||||
extends:
|
extends:
|
||||||
- .freebsd
|
- .freebsd
|
||||||
- .release_ghcup
|
- .release_ghcup
|
||||||
@@ -347,9 +518,25 @@ release:freebsd:
|
|||||||
- ./.gitlab/before_script/freebsd/install_deps.sh
|
- ./.gitlab/before_script/freebsd/install_deps.sh
|
||||||
variables:
|
variables:
|
||||||
ARTIFACT: "x86_64-portbld-freebsd-ghcup"
|
ARTIFACT: "x86_64-portbld-freebsd-ghcup"
|
||||||
GHC_VERSION: "8.10.4"
|
GHC_VERSION: "8.10.5"
|
||||||
CABAL_VERSION: "3.4.0.0"
|
CABAL_VERSION: "3.4.0.0"
|
||||||
|
allow_failure: true
|
||||||
|
|
||||||
|
######## windows release ########
|
||||||
|
|
||||||
|
release:windows:
|
||||||
|
stage: release
|
||||||
|
needs: ["test:windows:recommended"]
|
||||||
|
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.5"
|
||||||
|
CABAL_VERSION: "3.4.0.0"
|
||||||
|
|
||||||
######## hlint ########
|
######## hlint ########
|
||||||
|
|
||||||
@@ -362,7 +549,7 @@ hlint:
|
|||||||
script:
|
script:
|
||||||
- ./.gitlab/script/hlint.sh
|
- ./.gitlab/script/hlint.sh
|
||||||
variables:
|
variables:
|
||||||
GHC_VERSION: "8.10.4"
|
GHC_VERSION: "8.10.5"
|
||||||
CABAL_VERSION: "3.4.0.0"
|
CABAL_VERSION: "3.4.0.0"
|
||||||
JSON_VERSION: "0.0.4"
|
JSON_VERSION: "0.0.4"
|
||||||
allow_failure: true
|
allow_failure: true
|
||||||
|
|||||||
15
.gitlab/after_script.sh
Normal file
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
|
||||||
@@ -6,12 +6,27 @@ set -eux
|
|||||||
|
|
||||||
mkdir -p "${TMPDIR}"
|
mkdir -p "${TMPDIR}"
|
||||||
|
|
||||||
curl -sSfL https://downloads.haskell.org/~ghcup/x86_64-apple-darwin-ghcup > ./ghcup-bin
|
if [ $ARCH = 'ARM64' ] ; then
|
||||||
chmod +x ghcup-bin
|
curl -sSfL https://downloads.haskell.org/~ghcup/0.1.15.1/aarch64-apple-darwin-ghcup-0.1.15.1 > ./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 upgrade -i -f
|
./ghcup-bin install ${GHC_VERSION}
|
||||||
./ghcup-bin -s file://$(pwd)/ghcup-${JSON_VERSION}.yaml install ${GHC_VERSION}
|
./ghcup-bin set ${GHC_VERSION}
|
||||||
./ghcup-bin -s file://$(pwd)/ghcup-${JSON_VERSION}.yaml set ${GHC_VERSION}
|
./ghcup-bin install-cabal ${CABAL_VERSION}
|
||||||
./ghcup-bin -s file://$(pwd)/ghcup-${JSON_VERSION}.yaml 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
|
exit 0
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ curl -sSfL https://downloads.haskell.org/~ghcup/x86_64-portbld-freebsd-ghcup > .
|
|||||||
chmod +x ghcup-bin
|
chmod +x ghcup-bin
|
||||||
|
|
||||||
./ghcup-bin upgrade -i -f
|
./ghcup-bin upgrade -i -f
|
||||||
./ghcup-bin -s file://$(pwd)/ghcup-${JSON_VERSION}.yaml install ${GHC_VERSION}
|
./ghcup-bin install ${GHC_VERSION}
|
||||||
./ghcup-bin -s file://$(pwd)/ghcup-${JSON_VERSION}.yaml set ${GHC_VERSION}
|
./ghcup-bin set ${GHC_VERSION}
|
||||||
./ghcup-bin -s file://$(pwd)/ghcup-${JSON_VERSION}.yaml install-cabal ${CABAL_VERSION}
|
./ghcup-bin install-cabal ${CABAL_VERSION}
|
||||||
|
|
||||||
exit 0
|
exit 0
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ else
|
|||||||
fi
|
fi
|
||||||
chmod +x ghcup-bin
|
chmod +x ghcup-bin
|
||||||
./ghcup-bin upgrade -i -f
|
./ghcup-bin upgrade -i -f
|
||||||
./ghcup-bin -s file://$(pwd)/ghcup-${JSON_VERSION}.yaml install ${GHC_VERSION}
|
./ghcup-bin install ${GHC_VERSION}
|
||||||
./ghcup-bin -s file://$(pwd)/ghcup-${JSON_VERSION}.yaml install-cabal ${CABAL_VERSION}
|
./ghcup-bin install-cabal ${CABAL_VERSION}
|
||||||
|
|
||||||
# utils
|
# utils
|
||||||
apk add --no-cache \
|
apk add --no-cache \
|
||||||
@@ -41,6 +41,9 @@ apk add --no-cache \
|
|||||||
zlib \
|
zlib \
|
||||||
zlib-dev \
|
zlib-dev \
|
||||||
zlib-static \
|
zlib-static \
|
||||||
|
bzip2 \
|
||||||
|
bzip2-dev \
|
||||||
|
bzip2-static \
|
||||||
gmp \
|
gmp \
|
||||||
gmp-dev \
|
gmp-dev \
|
||||||
openssl-dev \
|
openssl-dev \
|
||||||
|
|||||||
@@ -7,13 +7,67 @@ set -eux
|
|||||||
mkdir -p "${TMPDIR}"
|
mkdir -p "${TMPDIR}"
|
||||||
|
|
||||||
sudo apt-get update -y
|
sudo apt-get update -y
|
||||||
sudo apt-get install -y libnuma-dev zlib1g-dev libgmp-dev libgmp10 libssl-dev liblzma-dev git wget
|
sudo apt-get install -y libnuma-dev zlib1g-dev libgmp-dev libgmp10 libssl-dev liblzma-dev libbz2-dev git wget lsb-release software-properties-common gnupg2 apt-transport-https
|
||||||
|
|
||||||
curl -sSfL https://downloads.haskell.org/~ghcup/x86_64-linux-ghcup > ./ghcup-bin
|
if [ "${CROSS}" = "arm-linux-gnueabihf" ] ; then
|
||||||
chmod +x ghcup-bin
|
sudo apt-get install -y autoconf build-essential gcc-arm-linux-gnueabihf
|
||||||
|
sudo dpkg --add-architecture armhf
|
||||||
|
sudo apt-get update -y
|
||||||
|
sudo apt-get install -y libncurses-dev:armhf
|
||||||
|
fi
|
||||||
|
|
||||||
./ghcup-bin upgrade -i -f
|
case "${ARCH}" in
|
||||||
./ghcup-bin -s file://$(pwd)/ghcup-${JSON_VERSION}.yaml install ${GHC_VERSION}
|
ARM*)
|
||||||
./ghcup-bin -s file://$(pwd)/ghcup-${JSON_VERSION}.yaml set ${GHC_VERSION}
|
case "${ARCH}" in
|
||||||
./ghcup-bin -s file://$(pwd)/ghcup-${JSON_VERSION}.yaml install-cabal ${CABAL_VERSION}
|
"ARM")
|
||||||
|
ghc_url=https://downloads.haskell.org/~ghc/${GHC_VERSION}/ghc-${GHC_VERSION}-armv7-deb10-linux.tar.xz
|
||||||
|
cabal_url=home.smart-cactus.org/~ben/cabal-install-${CABAL_VERSION}-armv7-linux-bootstrapped.tar.xz
|
||||||
|
;;
|
||||||
|
"ARM64")
|
||||||
|
ghc_url=https://downloads.haskell.org/~ghc/${GHC_VERSION}/ghc-${GHC_VERSION}-aarch64-deb10-linux.tar.xz
|
||||||
|
cabal_url=https://downloads.haskell.org/~cabal/cabal-install-${CABAL_VERSION}/cabal-install-${CABAL_VERSION}-aarch64-ubuntu-18.04.tar.xz
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
exit 1 ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
mkdir -p "${GHCUP_INSTALL_BASE_PREFIX}"/.ghcup/bin
|
||||||
|
|
||||||
|
curl -O "${ghc_url}"
|
||||||
|
tar -xf ghc-*.tar.*
|
||||||
|
cd ghc-${GHC_VERSION}
|
||||||
|
./configure --prefix="${GHCUP_INSTALL_BASE_PREFIX}"/.ghcup/ghc/${GHC_VERSION}
|
||||||
|
make install
|
||||||
|
for i in "${GHCUP_INSTALL_BASE_PREFIX}"/.ghcup/ghc/${GHC_VERSION}/bin/*-${GHC_VERSION} ; do
|
||||||
|
ln -s "${i}" "${GHCUP_INSTALL_BASE_PREFIX}"/.ghcup/bin/${i##*/}
|
||||||
|
done
|
||||||
|
for x in "${GHCUP_INSTALL_BASE_PREFIX}"/.ghcup/bin/*-${GHC_VERSION} ; do
|
||||||
|
ln -s ${x##*/} ${x%-${GHC_VERSION}}
|
||||||
|
done
|
||||||
|
cd ..
|
||||||
|
rm -rf ghc-${GHC_VERSION} ghc-*.tar.*
|
||||||
|
unset x i
|
||||||
|
|
||||||
|
mkdir cabal-install
|
||||||
|
cd cabal-install
|
||||||
|
curl -O "${cabal_url}"
|
||||||
|
tar -xf cabal-install-*
|
||||||
|
mv cabal "${GHCUP_INSTALL_BASE_PREFIX}"/.ghcup/bin/cabal
|
||||||
|
cd ..
|
||||||
|
rm -rf cabal-install
|
||||||
|
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
url=https://downloads.haskell.org/~ghcup/x86_64-linux-ghcup
|
||||||
|
|
||||||
|
curl -sSfL "${url}" > ./ghcup-bin
|
||||||
|
chmod +x ghcup-bin
|
||||||
|
|
||||||
|
./ghcup-bin upgrade -i -f
|
||||||
|
./ghcup-bin install ghc ${GHC_VERSION}
|
||||||
|
./ghcup-bin set ghc ${GHC_VERSION}
|
||||||
|
./ghcup-bin install cabal ${CABAL_VERSION}
|
||||||
|
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
|||||||
@@ -1,64 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
set -eux
|
|
||||||
|
|
||||||
. "$( cd "$(dirname "$0")" ; pwd -P )/../../ghcup_env"
|
|
||||||
|
|
||||||
mkdir -p "${TMPDIR}"
|
|
||||||
|
|
||||||
ednf() {
|
|
||||||
case "${ARCH}" in
|
|
||||||
"ARM")
|
|
||||||
sudo dnf -y --forcearch armv7hl "$@"
|
|
||||||
;;
|
|
||||||
"ARM64")
|
|
||||||
sudo dnf -y --forcearch aarch64 "$@"
|
|
||||||
;;
|
|
||||||
*) exit 1 ;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
ednf update
|
|
||||||
ednf install gcc gcc-c++ gmp gmp-devel make ncurses ncurses-devel xz xz-devel perl zlib zlib-devel openssl-devel openssl-libs openssl libffi libffi-devel lbzip2 lbzip2-utils
|
|
||||||
if [ "${ARCH}" = "ARM64" ] ; then
|
|
||||||
ednf install numactl numactl-libs numactl-devel
|
|
||||||
fi
|
|
||||||
ednf install bash wget curl git tar
|
|
||||||
ednf install llvm9.0 llvm9.0-devel llvm9.0-libs llvm9.0-static
|
|
||||||
|
|
||||||
case "${ARCH}" in
|
|
||||||
"ARM")
|
|
||||||
ghc_url=https://downloads.haskell.org/~ghc/${GHC_VERSION}/ghc-${GHC_VERSION}-armv7-deb10-linux.tar.xz
|
|
||||||
cabal_url=home.smart-cactus.org/~ben/cabal-install-${CABAL_VERSION}-armv7-linux-bootstrapped.tar.xz
|
|
||||||
;;
|
|
||||||
"ARM64")
|
|
||||||
ghc_url=https://downloads.haskell.org/~ghc/${GHC_VERSION}/ghc-${GHC_VERSION}-aarch64-deb10-linux.tar.xz
|
|
||||||
cabal_url=https://downloads.haskell.org/~cabal/cabal-install-${CABAL_VERSION}/cabal-install-${CABAL_VERSION}-aarch64-ubuntu-18.04.tar.xz
|
|
||||||
;;
|
|
||||||
*) exit 1 ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
mkdir -p "${GHCUP_INSTALL_BASE_PREFIX}"/.ghcup/bin
|
|
||||||
|
|
||||||
curl -O "${ghc_url}"
|
|
||||||
tar -xf ghc-*.tar.*
|
|
||||||
cd ghc-${GHC_VERSION}
|
|
||||||
./configure --prefix="${GHCUP_INSTALL_BASE_PREFIX}"/.ghcup/ghc/${GHC_VERSION}
|
|
||||||
make install
|
|
||||||
for i in "${GHCUP_INSTALL_BASE_PREFIX}"/.ghcup/ghc/${GHC_VERSION}/bin/*-${GHC_VERSION} ; do
|
|
||||||
ln -s "${i}" "${GHCUP_INSTALL_BASE_PREFIX}"/.ghcup/bin/${i##*/}
|
|
||||||
done
|
|
||||||
for x in "${GHCUP_INSTALL_BASE_PREFIX}"/.ghcup/bin/*-${GHC_VERSION} ; do
|
|
||||||
ln -s ${x##*/} ${x%-${GHC_VERSION}}
|
|
||||||
done
|
|
||||||
cd ..
|
|
||||||
rm -rf ghc-${GHC_VERSION} ghc-*.tar.*
|
|
||||||
unset x i
|
|
||||||
|
|
||||||
mkdir cabal-install
|
|
||||||
cd cabal-install
|
|
||||||
curl -O "${cabal_url}"
|
|
||||||
tar -xf cabal-install-*
|
|
||||||
mv cabal "${GHCUP_INSTALL_BASE_PREFIX}"/.ghcup/bin/cabal
|
|
||||||
cd ..
|
|
||||||
rm -rf cabal-install
|
|
||||||
@@ -7,4 +7,4 @@ set -eux
|
|||||||
mkdir -p "${TMPDIR}"
|
mkdir -p "${TMPDIR}"
|
||||||
|
|
||||||
sudo apt-get update -y
|
sudo apt-get update -y
|
||||||
sudo apt-get install -y libnuma-dev zlib1g-dev libgmp-dev libgmp10 libssl-dev liblzma-dev git wget
|
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
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/0.1.15.1/x86_64-mingw64-ghcup-0.1.15.1.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
|
||||||
@@ -1,3 +1,9 @@
|
|||||||
export GHCUP_INSTALL_BASE_PREFIX="$CI_PROJECT_DIR"
|
if [ "${OS}" = "WINDOWS" ] ; then
|
||||||
export PATH="$CI_PROJECT_DIR/.ghcup/bin:$CI_PROJECT_DIR/.local/bin:$PATH"
|
export GHCUP_INSTALL_BASE_PREFIX="$CI_PROJECT_DIR"
|
||||||
export TMPDIR="$CI_PROJECT_DIR/tmp"
|
export PATH="$GHCUP_INSTALL_BASE_PREFIX/ghcup/bin:$CI_PROJECT_DIR/.local/bin:$PATH"
|
||||||
|
export TMPDIR="$CI_PROJECT_DIR/tmp"
|
||||||
|
else
|
||||||
|
export GHCUP_INSTALL_BASE_PREFIX="$CI_PROJECT_DIR"
|
||||||
|
export PATH="$CI_PROJECT_DIR/.ghcup/bin:$CI_PROJECT_DIR/.local/bin:/opt/llvm/bin:$PATH"
|
||||||
|
export TMPDIR="$CI_PROJECT_DIR/tmp"
|
||||||
|
fi
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ set -eux
|
|||||||
mkdir -p "$CI_PROJECT_DIR"/.local/bin
|
mkdir -p "$CI_PROJECT_DIR"/.local/bin
|
||||||
|
|
||||||
ecabal() {
|
ecabal() {
|
||||||
cabal --store-dir="$(pwd)"/.store "$@"
|
cabal "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
eghcup() {
|
eghcup() {
|
||||||
|
|||||||
52
.gitlab/script/ghcup_cross.sh
Executable file
52
.gitlab/script/ghcup_cross.sh
Executable file
@@ -0,0 +1,52 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -eux
|
||||||
|
|
||||||
|
. "$( cd "$(dirname "$0")" ; pwd -P )/../ghcup_env"
|
||||||
|
|
||||||
|
mkdir -p "$CI_PROJECT_DIR"/.local/bin
|
||||||
|
|
||||||
|
CI_PROJECT_DIR=$(pwd)
|
||||||
|
|
||||||
|
ecabal() {
|
||||||
|
cabal "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
eghcup() {
|
||||||
|
ghcup -v -c -s file://$CI_PROJECT_DIR/ghcup-${JSON_VERSION}.yaml "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
git describe --always
|
||||||
|
|
||||||
|
### build
|
||||||
|
|
||||||
|
ecabal update
|
||||||
|
|
||||||
|
ecabal build -w ghc-${GHC_VERSION}
|
||||||
|
cp "$(ecabal new-exec -w ghc-${GHC_VERSION} --verbose=0 --offline sh -- -c 'command -v ghcup')" "$CI_PROJECT_DIR"/.local/bin/ghcup
|
||||||
|
|
||||||
|
### cleanup
|
||||||
|
|
||||||
|
rm -rf "${GHCUP_INSTALL_BASE_PREFIX}"/.ghcup
|
||||||
|
|
||||||
|
### manual cli based testing
|
||||||
|
|
||||||
|
eghcup --numeric-version
|
||||||
|
|
||||||
|
eghcup install ghc ${GHC_VERSION}
|
||||||
|
eghcup set ghc ${GHC_VERSION}
|
||||||
|
eghcup install cabal ${CABAL_VERSION}
|
||||||
|
|
||||||
|
cabal --version
|
||||||
|
|
||||||
|
eghcup debug-info
|
||||||
|
|
||||||
|
eghcup compile ghc -j $(nproc) -v ${GHC_TARGET_VERSION} -b ${GHC_VERSION} -x ${CROSS} -- --enable-unregisterised
|
||||||
|
eghcup set ghc ${CROSS}-${GHC_TARGET_VERSION}
|
||||||
|
|
||||||
|
[ `$(eghcup whereis ghc ${CROSS}-${GHC_TARGET_VERSION}) --numeric-version` = "${GHC_TARGET_VERSION}" ]
|
||||||
|
|
||||||
|
# nuke
|
||||||
|
eghcup nuke
|
||||||
|
[ ! -e "${GHCUP_INSTALL_BASE_PREFIX}/.ghcup" ]
|
||||||
|
|
||||||
52
.gitlab/script/ghcup_git.sh
Executable file
52
.gitlab/script/ghcup_git.sh
Executable file
@@ -0,0 +1,52 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -eux
|
||||||
|
|
||||||
|
. "$( cd "$(dirname "$0")" ; pwd -P )/../ghcup_env"
|
||||||
|
|
||||||
|
mkdir -p "$CI_PROJECT_DIR"/.local/bin
|
||||||
|
|
||||||
|
CI_PROJECT_DIR=$(pwd)
|
||||||
|
|
||||||
|
ecabal() {
|
||||||
|
cabal "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
eghcup() {
|
||||||
|
ghcup -v -c -s file://$CI_PROJECT_DIR/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" ]
|
||||||
|
|
||||||
@@ -7,7 +7,7 @@ set -eux
|
|||||||
mkdir -p "$CI_PROJECT_DIR"/.local/bin
|
mkdir -p "$CI_PROJECT_DIR"/.local/bin
|
||||||
|
|
||||||
ecabal() {
|
ecabal() {
|
||||||
cabal --store-dir="$(pwd)"/.store "$@"
|
cabal "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
git describe
|
git describe
|
||||||
@@ -15,6 +15,7 @@ git describe
|
|||||||
# build
|
# build
|
||||||
ecabal update
|
ecabal update
|
||||||
|
|
||||||
|
|
||||||
if [ "${OS}" = "LINUX" ] ; then
|
if [ "${OS}" = "LINUX" ] ; then
|
||||||
if [ "${ARCH}" = "32" ] ; then
|
if [ "${ARCH}" = "32" ] ; then
|
||||||
ecabal build -w ghc-${GHC_VERSION} --ghc-options='-split-sections -optl-static' -ftui -ftar
|
ecabal build -w ghc-${GHC_VERSION} --ghc-options='-split-sections -optl-static' -ftui -ftar
|
||||||
@@ -24,18 +25,20 @@ if [ "${OS}" = "LINUX" ] ; then
|
|||||||
ecabal build -w ghc-${GHC_VERSION} -ftui
|
ecabal build -w ghc-${GHC_VERSION} -ftui
|
||||||
fi
|
fi
|
||||||
elif [ "${OS}" = "FREEBSD" ] ; then
|
elif [ "${OS}" = "FREEBSD" ] ; then
|
||||||
ecabal build -w ghc-${GHC_VERSION} --ghc-options='-split-sections' --constraint="zlib +bundled-c-zlib" -ftui
|
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
|
else
|
||||||
ecabal build -w ghc-${GHC_VERSION} --constraint="zlib +bundled-c-zlib" --constraint="lzma +static" -ftui
|
ecabal build -w ghc-${GHC_VERSION} --constraint="zlib +bundled-c-zlib" --constraint="lzma +static" -ftui
|
||||||
fi
|
fi
|
||||||
|
|
||||||
mkdir out
|
mkdir out
|
||||||
cp "$(ecabal new-exec -w ghc-${GHC_VERSION} --verbose=0 --offline sh -- -c 'command -v ghcup')" .
|
binary=$(ecabal new-exec -w ghc-${GHC_VERSION} --verbose=0 --offline sh -- -c 'command -v ghcup')
|
||||||
ver=$(./ghcup --numeric-version)
|
ver=$("${binary}" --numeric-version)
|
||||||
if [ "${OS}" = "DARWIN" ] ; then
|
if [ "${OS}" = "DARWIN" ] ; then
|
||||||
strip ./ghcup
|
strip "${binary}"
|
||||||
else
|
else
|
||||||
strip -s ./ghcup
|
strip -s "${binary}"
|
||||||
fi
|
fi
|
||||||
cp ghcup out/${ARTIFACT}-${ver}
|
cp "${binary}" out/${ARTIFACT}-${ver}
|
||||||
|
|
||||||
|
|||||||
@@ -6,53 +6,76 @@ set -eux
|
|||||||
|
|
||||||
mkdir -p "$CI_PROJECT_DIR"/.local/bin
|
mkdir -p "$CI_PROJECT_DIR"/.local/bin
|
||||||
|
|
||||||
|
CI_PROJECT_DIR=$(pwd)
|
||||||
|
|
||||||
ecabal() {
|
ecabal() {
|
||||||
cabal --store-dir="$(pwd)"/.store "$@"
|
cabal "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
raw_eghcup() {
|
||||||
|
ghcup -v -c "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
eghcup() {
|
eghcup() {
|
||||||
ghcup -v -c -s file://$(pwd)/ghcup-${JSON_VERSION}.yaml "$@"
|
if [ "${OS}" = "WINDOWS" ] ; then
|
||||||
|
ghcup -v -c -s file:/$CI_PROJECT_DIR/ghcup-${JSON_VERSION}.yaml "$@"
|
||||||
|
else
|
||||||
|
ghcup -v -c -s file://$CI_PROJECT_DIR/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
|
git describe --always
|
||||||
|
|
||||||
### build
|
### build
|
||||||
|
|
||||||
ecabal update
|
ecabal update
|
||||||
|
|
||||||
(
|
|
||||||
cd /tmp
|
|
||||||
ecabal install -w ghc-${GHC_VERSION} --installdir="$CI_PROJECT_DIR"/.local/bin hspec-discover
|
|
||||||
)
|
|
||||||
|
|
||||||
if [ "${OS}" = "DARWIN" ] ; then
|
if [ "${OS}" = "DARWIN" ] ; then
|
||||||
ecabal build -w ghc-${GHC_VERSION} -ftui
|
ecabal build -w ghc-${GHC_VERSION} -ftui
|
||||||
ecabal test -w ghc-${GHC_VERSION} -ftui ghcup-test
|
ecabal test -w ghc-${GHC_VERSION} -ftui ghcup-test
|
||||||
|
ecabal haddock -w ghc-${GHC_VERSION} -ftui
|
||||||
elif [ "${OS}" = "LINUX" ] ; then
|
elif [ "${OS}" = "LINUX" ] ; then
|
||||||
if [ "${ARCH}" = "32" ] ; then
|
if [ "${ARCH}" = "32" ] ; then
|
||||||
ecabal build -w ghc-${GHC_VERSION} -finternal-downloader -ftui -ftar
|
ecabal build -w ghc-${GHC_VERSION} -finternal-downloader -ftui -ftar
|
||||||
ecabal test -w ghc-${GHC_VERSION} -finternal-downloader -ftui -ftar ghcup-test
|
ecabal test -w ghc-${GHC_VERSION} -finternal-downloader -ftui -ftar ghcup-test
|
||||||
|
ecabal haddock -w ghc-${GHC_VERSION} -finternal-downloader -ftui -ftar
|
||||||
else
|
else
|
||||||
ecabal build -w ghc-${GHC_VERSION} -finternal-downloader -ftui
|
ecabal build -w ghc-${GHC_VERSION} -finternal-downloader -ftui
|
||||||
ecabal test -w ghc-${GHC_VERSION} -finternal-downloader -ftui ghcup-test
|
ecabal test -w ghc-${GHC_VERSION} -finternal-downloader -ftui ghcup-test
|
||||||
|
ecabal haddock -w ghc-${GHC_VERSION} -finternal-downloader -ftui
|
||||||
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
|
else
|
||||||
ecabal build -w ghc-${GHC_VERSION} -finternal-downloader -ftui
|
ecabal build -w ghc-${GHC_VERSION} -finternal-downloader -ftui
|
||||||
ecabal test -w ghc-${GHC_VERSION} -finternal-downloader -ftui ghcup-test
|
ecabal test -w ghc-${GHC_VERSION} -finternal-downloader -ftui ghcup-test
|
||||||
|
ecabal haddock -w ghc-${GHC_VERSION} -finternal-downloader -ftui
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ecabal haddock -w ghc-${GHC_VERSION} -ftar
|
|
||||||
|
|
||||||
cp "$(ecabal new-exec -w ghc-${GHC_VERSION} --verbose=0 --offline sh -- -c 'command -v ghcup')" .
|
if [ "${OS}" = "WINDOWS" ] ; then
|
||||||
cp "$(ecabal new-exec -w ghc-${GHC_VERSION} --verbose=0 --offline sh -- -c 'command -v ghcup-gen')" .
|
ext=".exe"
|
||||||
|
else
|
||||||
cp ./ghcup "$CI_PROJECT_DIR"/.local/bin/ghcup
|
ext=''
|
||||||
cp ./ghcup-gen "$CI_PROJECT_DIR"/.local/bin/ghcup-gen
|
fi
|
||||||
|
cp "$(ecabal new-exec -w ghc-${GHC_VERSION} --verbose=0 --offline sh -- -c 'command -v ghcup')" "$CI_PROJECT_DIR"/.local/bin/ghcup${ext}
|
||||||
|
cp "$(ecabal new-exec -w ghc-${GHC_VERSION} --verbose=0 --offline sh -- -c 'command -v ghcup-gen')" "$CI_PROJECT_DIR"/.local/bin/ghcup-gen${ext}
|
||||||
|
|
||||||
### cleanup
|
### cleanup
|
||||||
|
|
||||||
rm -rf "${GHCUP_INSTALL_BASE_PREFIX}"/.ghcup
|
rm -rf "${GHCUP_DIR}"
|
||||||
|
|
||||||
|
|
||||||
### manual cli based testing
|
### manual cli based testing
|
||||||
|
|
||||||
@@ -61,59 +84,123 @@ ghcup-gen check -f ghcup-${JSON_VERSION}.yaml
|
|||||||
|
|
||||||
eghcup --numeric-version
|
eghcup --numeric-version
|
||||||
|
|
||||||
eghcup install ${GHC_VERSION}
|
eghcup install ghc ${GHC_VERSION}
|
||||||
eghcup set ${GHC_VERSION}
|
[ `$(eghcup whereis ghc ${GHC_VERSION}) --numeric-version` = "${GHC_VERSION}" ]
|
||||||
eghcup install-cabal ${CABAL_VERSION}
|
eghcup set ghc ${GHC_VERSION}
|
||||||
|
eghcup install cabal ${CABAL_VERSION}
|
||||||
|
[ `$(eghcup whereis cabal ${CABAL_VERSION}) --numeric-version` = "${CABAL_VERSION}" ]
|
||||||
|
|
||||||
cabal --version
|
cabal --version
|
||||||
|
|
||||||
eghcup debug-info
|
eghcup debug-info
|
||||||
|
|
||||||
|
# also test etags
|
||||||
eghcup list
|
eghcup list
|
||||||
eghcup list -t ghc
|
eghcup list -t ghc
|
||||||
eghcup list -t cabal
|
eghcup list -t cabal
|
||||||
|
|
||||||
ghc_ver=$(ghc --numeric-version)
|
ghc_ver=$(ghc --numeric-version)
|
||||||
ghc --version
|
ghc --version
|
||||||
ghci --version
|
ghc-${ghc_ver} --version
|
||||||
ghc-$(ghc --numeric-version) --version
|
if [ "${OS}" != "WINDOWS" ] ; then
|
||||||
ghci-$(ghc --numeric-version) --version
|
ghci --version
|
||||||
|
ghci-${ghc_ver} --version
|
||||||
|
|
||||||
# test installing new ghc doesn't mess with currently set GHC
|
|
||||||
# https://gitlab.haskell.org/haskell/ghcup-hs/issues/7
|
|
||||||
if [ "${OS}" = "LINUX" ] ; then
|
|
||||||
eghcup --downloader=wget install 8.10.3
|
|
||||||
else # test wget a bit
|
|
||||||
eghcup install 8.10.3
|
|
||||||
fi
|
fi
|
||||||
[ "$(ghc --numeric-version)" = "${ghc_ver}" ]
|
|
||||||
eghcup set 8.10.3
|
|
||||||
eghcup set 8.10.3
|
|
||||||
[ "$(ghc --numeric-version)" = "8.10.3" ]
|
|
||||||
eghcup set ${GHC_VERSION}
|
|
||||||
[ "$(ghc --numeric-version)" = "${ghc_ver}" ]
|
|
||||||
eghcup rm 8.10.3
|
|
||||||
[ "$(ghc --numeric-version)" = "${ghc_ver}" ]
|
|
||||||
|
|
||||||
# install hls
|
|
||||||
if [ "${OS}" = "DARWIN" ] ; then
|
if [ "${OS}" = "DARWIN" ] && [ "${ARCH}" = "ARM64" ] ; then
|
||||||
eghcup install hls
|
echo
|
||||||
haskell-language-server-wrapper --version
|
else
|
||||||
elif [ "${OS}" = "LINUX" ] ; then
|
# test installing new ghc doesn't mess with currently set GHC
|
||||||
if [ "${ARCH}" = "64" ] ; then
|
# 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
|
||||||
|
else # test wget a bit
|
||||||
|
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 --offline rm 8.10.3
|
||||||
|
[ "$(ghc --numeric-version)" = "${ghc_ver}" ]
|
||||||
|
|
||||||
|
if [ "${OS}" = "DARWIN" ] ; then
|
||||||
eghcup install hls
|
eghcup install hls
|
||||||
haskell-language-server-wrapper --version
|
$(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 install stack
|
||||||
|
stack --version
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# check that lazy loading works for 'whereis'
|
||||||
|
cp "$CI_PROJECT_DIR/ghcup-${JSON_VERSION}.yaml" "$CI_PROJECT_DIR/ghcup-${JSON_VERSION}.yaml.bak"
|
||||||
|
echo '**' > "$CI_PROJECT_DIR/ghcup-${JSON_VERSION}.yaml"
|
||||||
|
eghcup whereis ghc $(ghc --numeric-version)
|
||||||
|
mv -f "$CI_PROJECT_DIR/ghcup-${JSON_VERSION}.yaml.bak" "$CI_PROJECT_DIR/ghcup-${JSON_VERSION}.yaml"
|
||||||
|
|
||||||
eghcup rm $(ghc --numeric-version)
|
eghcup rm $(ghc --numeric-version)
|
||||||
|
|
||||||
# https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/116
|
# https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/116
|
||||||
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
|
if [ "${OS}" = "LINUX" ] ; then
|
||||||
eghcup rm cabal 3.4.0.0-rc4
|
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}" ]
|
||||||
|
|
||||||
|
|
||||||
eghcup upgrade
|
eghcup upgrade
|
||||||
eghcup upgrade -f
|
eghcup upgrade -f
|
||||||
|
|
||||||
|
|
||||||
|
# nuke
|
||||||
|
eghcup nuke
|
||||||
|
[ ! -e "${GHCUP_DIR}" ]
|
||||||
|
|||||||
89
.gitlab/shell.nix
Normal file
89
.gitlab/shell.nix
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
{ system ? "aarch64-darwin"
|
||||||
|
#, nixpkgs ? fetchTarball https://github.com/angerman/nixpkgs/archive/257cb120334.tar.gz #apple-silicon.tar.gz
|
||||||
|
, pkgs ? import <nixpkgs> { inherit system; }
|
||||||
|
, compiler ? if system == "aarch64-darwin" then "ghc8103Binary" else "ghc8103"
|
||||||
|
}: pkgs.mkShell {
|
||||||
|
# this prevents nix from trying to write the env-vars file.
|
||||||
|
# we can't really, as NIX_BUILD_TOP/env-vars is not set.
|
||||||
|
noDumpEnvVars=1;
|
||||||
|
|
||||||
|
# stop polluting LDFLAGS with -liconv
|
||||||
|
dontAddExtraLibs = true;
|
||||||
|
|
||||||
|
# we need to inject ncurses into --with-curses-libraries.
|
||||||
|
# the real fix is to teach terminfo to use libcurses on macOS.
|
||||||
|
# CONFIGURE_ARGS = "--with-intree-gmp --with-curses-libraries=${pkgs.ncurses.out}/lib";
|
||||||
|
CONFIGURE_ARGS = "--with-intree-gmp --with-curses-libraries=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib --with-iconv-includes=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include --with-iconv-libraries=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib SH=/bin/bash";
|
||||||
|
|
||||||
|
# magic speedup pony :facepalm:
|
||||||
|
#
|
||||||
|
# nix has the ugly habbit of duplicating ld flags more than necessary. This
|
||||||
|
# somewhat consolidates this.
|
||||||
|
shellHook = ''
|
||||||
|
export NIX_LDFLAGS=$(for a in $NIX_LDFLAGS; do echo $a; done |sort|uniq|xargs)
|
||||||
|
export NIX_LDFLAGS_FOR_TARGET=$(for a in $NIX_LDFLAGS_FOR_TARGET; do echo $a; done |sort|uniq|xargs)
|
||||||
|
export NIX_LDFLAGS_FOR_TARGET=$(comm -3 <(for l in $NIX_LDFLAGS_FOR_TARGET; do echo $l; done) <(for l in $NIX_LDFLAGS; do echo $l; done))
|
||||||
|
|
||||||
|
|
||||||
|
# Impurity hack for GHC releases.
|
||||||
|
#################################
|
||||||
|
# We don't want binary releases to depend on nix, thus we'll need to make sure we don't leak in references.
|
||||||
|
# GHC externally depends only on iconv and curses. However we can't force a specific curses library for
|
||||||
|
# the terminfo package, as such we'll need to make sure we only look in the system path for the curses library
|
||||||
|
# and not pick up the tinfo from the nix provided ncurses package.
|
||||||
|
#
|
||||||
|
# We also need to force us to use the systems COREFOUNDATION, not the one that nix builds. Again this is impure,
|
||||||
|
# but it will allow us to have proper binary distributions.
|
||||||
|
#
|
||||||
|
# do not use nixpkgs provided core foundation
|
||||||
|
export NIX_COREFOUNDATION_RPATH=/System/Library/Frameworks
|
||||||
|
# drop curses from the LDFLAGS, we really want the system ones, not the nix ones.
|
||||||
|
export NIX_LDFLAGS=$(for lib in $NIX_LDFLAGS; do case "$lib" in *curses*);; *) echo -n "$lib ";; esac; done;)
|
||||||
|
export NIX_CFLAGS_COMPILE+=" -Wno-nullability-completeness -Wno-availability -Wno-expansion-to-defined -Wno-builtin-requires-header -Wno-unused-command-line-argument"
|
||||||
|
|
||||||
|
# unconditionally add the MacOSX.sdk and TargetConditional.h
|
||||||
|
export NIX_CFLAGS_COMPILE+=" -isystem /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include"
|
||||||
|
|
||||||
|
'';
|
||||||
|
|
||||||
|
nativeBuildInputs = (with pkgs; [
|
||||||
|
# This needs to come *before* ghc,
|
||||||
|
# otherwise we migth end up with the clang from
|
||||||
|
# the bootstrap GHC in PATH with higher priority.
|
||||||
|
clang_11
|
||||||
|
llvm_11
|
||||||
|
|
||||||
|
haskell.compiler.${compiler}
|
||||||
|
haskell.packages.${compiler}.cabal-install
|
||||||
|
haskell.packages.${compiler}.alex
|
||||||
|
haskell.packages.${compiler}.happy # _1_19_12 is needed for older GHCs.
|
||||||
|
|
||||||
|
automake
|
||||||
|
autoconf
|
||||||
|
m4
|
||||||
|
|
||||||
|
gmp
|
||||||
|
zlib.out
|
||||||
|
zlib.dev
|
||||||
|
glibcLocales
|
||||||
|
# locale doesn't build yet :-/
|
||||||
|
# locale
|
||||||
|
|
||||||
|
git
|
||||||
|
|
||||||
|
python3
|
||||||
|
# python3Full
|
||||||
|
# python3Packages.sphinx
|
||||||
|
perl
|
||||||
|
|
||||||
|
which
|
||||||
|
wget
|
||||||
|
curl
|
||||||
|
file
|
||||||
|
|
||||||
|
xz
|
||||||
|
xlibs.lndir
|
||||||
|
|
||||||
|
cacert ])
|
||||||
|
++ (with pkgs.darwin.apple_sdk.frameworks; [ Foundation Security ]);
|
||||||
|
}
|
||||||
16
.travis.yml
16
.travis.yml
@@ -1,10 +1,5 @@
|
|||||||
jobs:
|
jobs:
|
||||||
include:
|
include:
|
||||||
- os: osx
|
|
||||||
osx_image: xcode8
|
|
||||||
language: generic
|
|
||||||
env: ARTIFACT=x86_64-apple-darwin-10.11-ghcup
|
|
||||||
|
|
||||||
- os: osx
|
- os: osx
|
||||||
osx_image: xcode10.1
|
osx_image: xcode10.1
|
||||||
language: generic
|
language: generic
|
||||||
@@ -15,23 +10,16 @@ jobs:
|
|||||||
language: generic
|
language: generic
|
||||||
env: ARTIFACT=x86_64-apple-darwin-10.14-ghcup
|
env: ARTIFACT=x86_64-apple-darwin-10.14-ghcup
|
||||||
|
|
||||||
allow_failures:
|
|
||||||
- os: osx
|
|
||||||
osx_image: xcode8
|
|
||||||
language: generic
|
|
||||||
env: ARTIFACT=x86_64-apple-darwin-10.11-ghcup
|
|
||||||
|
|
||||||
|
|
||||||
script: ".travis/build.sh"
|
script: ".travis/build.sh"
|
||||||
|
|
||||||
deploy:
|
deploy:
|
||||||
provider: releases
|
provider: releases
|
||||||
api_key:
|
api_key:
|
||||||
secure: GQESg4TcYf3PQJRRaZV/kWS0hsF+OFnH2+EcwpgnIcfx4+aogMyprdh745KtBXe1FlFN1luKHksFjqceqhcg/xcNyeCJiSnLWMn4D/i4WUperEHseRBi5yZZCB1AvOjIlHrE4DS3a8pyEm1GV3G7CKY5Fu8jBjof2SnyENfd7fofhjtNHWmeFS+jBn8HRDf1YaSRYxzTw6uHLrPLsybfgQZVl7babMu/38Ghin0f5pz5OlNokzDxaubIYQHOZ7st7YndHJtBWWql/KualBWbMILy88dUVQBnbqQLP2P8d1ME8ILUjJVqz33HiRU0JzlEJyWfbvEjcJ6iD8M6n4nXTaxfu3i2UhhGsQ6SSBNKssMP4tji8nkNpMqG59wLQ/zhcetEm71fKkgJNrIMNllkqlWSo5K74IqqP9kiLg/qm8ipOJjui0gPk8tZXKcV+ztX1d1OVCapoLfiDM5l/0LLQXaTOXOV1x3e5LLQ/w2doNiH3eh5CV4II9dRu7owpaiiMBHMssmT0pH99jEeF6giHLKtt3y7l2GWoRLPdhsZZ54gxsaBxZt9GuypmkbNcr97CEnAVaWij5v0CF3w4rAWqy/tAxQpIDJOIOQBgmwG5WrBAKyKrFvEpBL5a8BPcRWJDvqKC83QeWpvPrEVdgJevC6ZN1MKzrb2SiPOwC2Kerc=
|
secure: "hT2od8Iy04tdFVuonPSWv0NX5hZDmv4al8Q0GbIWmviUetROuM7c6/MCHUcgyiw6H2L3pmH4F24GBYWpKBT3ZMbxrKXhZOZ3KPLXzlnuRlm1qymKqqwsJs3466bMftaiBr16rx1VpAuditN4A32oSmTFcQAJc84Bxn2WZ4t8hk9muS8YPyLhqg3/NxT6ob8dzNp9eS2cA0WODMb/fMzaMruRtepSK8JvuXb/SnTvaDcl9plmPzEa+eW54jwVsDps8ZpQMQlTtGIjYHIwTQ36/iLH4LoAvD7OEnB7qf753LOzmI/bvlB75xYGsLxe1qgpzPMjuG3AK0jb2KGSZCzyAyrbBFSQMIyC1gNKMtab3CohnA9WdQqAT1xrzPzA9zNw516G5Fn/z+t9Ek1f6L2OYO2hJfweNhWh+ChAIsOags2QBpqc0qjkwUS4wqxCWBdyVfgPTUoGelvjCfjQgypgIyLEHFvXt9rlj+kd97FY7nG3vxZrsvWTKKKT551OqUYX5zWTyvGR71jKyNst/p93Pg3DkRy31gHrGnG9zfNgN5tWxJqDd/suR/BAFTp0VtkFb8fR3ct7WMVeJXtE2+bKqxO5Fnocs1VjEm8pKPk7glnp0muu08kaO0h54wiSOCbk1RvO1KZtHue4wKWrHcI18dwW2WtzoBQ4P1lOSkS81UY="
|
||||||
file: $ARTIFACT
|
file: $ARTIFACT
|
||||||
on:
|
on:
|
||||||
repo: haskell/ghcup-hs
|
repo: hasufell/ghcup-hs
|
||||||
tags: true
|
tags: true
|
||||||
skip_cleanup: true
|
skip_cleanup: true
|
||||||
draft: true
|
draft: true
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,12 @@ ghcup set 8.10.4
|
|||||||
## install ghcup
|
## install ghcup
|
||||||
|
|
||||||
cabal update
|
cabal update
|
||||||
|
|
||||||
|
(
|
||||||
|
cd /tmp
|
||||||
|
cabal install --installdir="$HOME"/.ghcup/bin hspec-discover
|
||||||
|
)
|
||||||
|
|
||||||
cabal build --constraint="zlib +static" --constraint="lzma +static" -ftui
|
cabal build --constraint="zlib +static" --constraint="lzma +static" -ftui
|
||||||
cp "$(cabal new-exec --verbose=0 --offline sh -- -c 'command -v ghcup')" .
|
cp "$(cabal new-exec --verbose=0 --offline sh -- -c 'command -v ghcup')" .
|
||||||
strip ./ghcup
|
strip ./ghcup
|
||||||
|
|||||||
46
CHANGELOG.md
46
CHANGELOG.md
@@ -1,5 +1,51 @@
|
|||||||
# Revision history for ghcup
|
# Revision history for ghcup
|
||||||
|
|
||||||
|
## 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
|
## 0.1.14 -- 2021-03-07
|
||||||
|
|
||||||
* Major bugfix: fix handling of stray versions wrt [#116](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/116)
|
* Major bugfix: fix handling of stray versions wrt [#116](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/116)
|
||||||
|
|||||||
@@ -6,10 +6,6 @@
|
|||||||
|
|
||||||
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.
|
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 filepath or directory
|
|
||||||
|
|
||||||
Filepath and directory have two fundamental problems: 1. they use String as filepath (see [AFPP](https://gitlab.haskell.org/ghc/ghc/-/wikis/proposal/abstract-file-path) as to why this is wrong) and 2. they try very hard to be cross-platform at the expense of low-level correctness. Instead, we use the [hpath](https://github.com/hasufell/hpath) libraries for file and filepath related stuff, which also gives us stronger filepath types.
|
|
||||||
|
|
||||||
### No use of haskell-TLS
|
### No use of haskell-TLS
|
||||||
|
|
||||||
I consider haskell-TLS an interesting experiment, but not a battle-tested and peer-reviewed crypto implementation. There is little to no research about what the intricacies of using haskell for low-level crypto are and how vulnerable such binaries are. Instead, we use either curl the binary (for FreeBSD and mac) or http-io-streams, which works with OpenSSL bindings.
|
I consider haskell-TLS an interesting experiment, but not a battle-tested and peer-reviewed crypto implementation. There is little to no research about what the intricacies of using haskell for low-level crypto are and how vulnerable such binaries are. Instead, we use either curl the binary (for FreeBSD and mac) or http-io-streams, which works with OpenSSL bindings.
|
||||||
@@ -73,3 +69,7 @@ yaml files: `ghcup-<yaml-ver>.yaml`.
|
|||||||
Most of the `Version` parameters to functions had to be replaced with
|
Most of the `Version` parameters to functions had to be replaced with
|
||||||
that and ensured the logic is consistent for cross and non-cross
|
that and ensured the logic is consistent for cross and non-cross
|
||||||
installs.
|
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.
|
||||||
|
|||||||
166
README.md
166
README.md
@@ -1,11 +1,9 @@
|
|||||||
`ghcup` makes it easy to install specific versions of `ghc` on GNU/Linux,
|
`ghcup` makes it easy to install specific versions of `ghc` on GNU/Linux,
|
||||||
macOS (aka Darwin) and FreeBSD and can also bootstrap a fresh Haskell developer environment from scratch.
|
macOS (aka Darwin), FreeBSD and Windows and can also bootstrap a fresh Haskell developer environment from scratch.
|
||||||
It follows the unix UNIX philosophy of [do one thing and do it well](https://en.wikipedia.org/wiki/Unix_philosophy#Do_One_Thing_and_Do_It_Well).
|
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).
|
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).
|
||||||
|
|
||||||
*Ubuntu users may prefer [hvr's ppa](https://launchpad.net/~hvr/+archive/ubuntu/ghc).*
|
|
||||||
|
|
||||||
## Table of Contents
|
## Table of Contents
|
||||||
|
|
||||||
* [Installation](#installation)
|
* [Installation](#installation)
|
||||||
@@ -20,6 +18,7 @@ Similar in scope to [rustup](https://github.com/rust-lang-nursery/rustup.rs), [p
|
|||||||
* [XDG support](#xdg-support)
|
* [XDG support](#xdg-support)
|
||||||
* [Env variables](#env-variables)
|
* [Env variables](#env-variables)
|
||||||
* [Installing custom bindists](#installing-custom-bindists)
|
* [Installing custom bindists](#installing-custom-bindists)
|
||||||
|
* [Tips and tricks](#tips-and-tricks)
|
||||||
* [Design goals](#design-goals)
|
* [Design goals](#design-goals)
|
||||||
* [How](#how)
|
* [How](#how)
|
||||||
* [Known users](#known-users)
|
* [Known users](#known-users)
|
||||||
@@ -79,7 +78,7 @@ ghcup install cabal
|
|||||||
ghcup upgrade
|
ghcup upgrade
|
||||||
```
|
```
|
||||||
|
|
||||||
Generally this is meant to be used with [`cabal-install`](https://hackage.haskell.org/package/cabal-install), which
|
GHCup works very well with [`cabal-install`](https://hackage.haskell.org/package/cabal-install), which
|
||||||
handles your haskell packages and can demand that [a specific version](https://cabal.readthedocs.io/en/latest/nix-local-build.html#cfg-flag---with-compiler) of `ghc` is available, which `ghcup` can do.
|
handles your haskell packages and can demand that [a specific version](https://cabal.readthedocs.io/en/latest/nix-local-build.html#cfg-flag---with-compiler) of `ghc` is available, which `ghcup` can do.
|
||||||
|
|
||||||
### Configuration
|
### Configuration
|
||||||
@@ -87,7 +86,7 @@ handles your haskell packages and can demand that [a specific version](https://c
|
|||||||
A configuration file can be put in `~/.ghcup/config.yaml`. The default config file
|
A configuration file can be put in `~/.ghcup/config.yaml`. The default config file
|
||||||
explaining all possible configurations can be found in this repo: [config.yaml](./config.yaml).
|
explaining all possible configurations can be found in this repo: [config.yaml](./config.yaml).
|
||||||
|
|
||||||
Partial configuration is fine. Command line options always overwrite the config file settings.
|
Partial configuration is fine. Command line options always override the config file settings.
|
||||||
|
|
||||||
### Manpages
|
### Manpages
|
||||||
|
|
||||||
@@ -125,6 +124,9 @@ Then you can control the locations via XDG environment variables as such:
|
|||||||
* `XDG_BIN_HOME`: binaries end up here (default: `~/.local/bin`)
|
* `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`)
|
* `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
|
### Env variables
|
||||||
|
|
||||||
This is the complete list of env variables that change GHCup behavior:
|
This is the complete list of env variables that change GHCup behavior:
|
||||||
@@ -134,6 +136,7 @@ This is the complete list of env variables that change GHCup behavior:
|
|||||||
* `GHCUP_INSTALL_BASE_PREFIX`: the base of ghcup (default: `$HOME`)
|
* `GHCUP_INSTALL_BASE_PREFIX`: the base of ghcup (default: `$HOME`)
|
||||||
* `GHCUP_CURL_OPTS`: additional options that can be passed to curl
|
* `GHCUP_CURL_OPTS`: additional options that can be passed to curl
|
||||||
* `GHCUP_WGET_OPTS`: additional options that can be passed to wget
|
* `GHCUP_WGET_OPTS`: additional options that can be passed to wget
|
||||||
|
* `GHCUP_SKIP_UPDATE_CHECK`: Skip the (possibly annoying) update check when you run a command
|
||||||
* `CC`/`LD` etc.: full environment is passed to the build system when compiling GHC via GHCup
|
* `CC`/`LD` etc.: full environment is passed to the build system when compiling GHC via GHCup
|
||||||
|
|
||||||
### Installing custom bindists
|
### Installing custom bindists
|
||||||
@@ -152,6 +155,53 @@ 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
|
GHCup always needs to know which version the bindist corresponds to (this is not automatically
|
||||||
detected).
|
detected).
|
||||||
|
|
||||||
|
### 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.
|
||||||
|
|
||||||
## Design goals
|
## Design goals
|
||||||
|
|
||||||
1. simplicity
|
1. simplicity
|
||||||
@@ -228,16 +278,110 @@ 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)
|
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.
|
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
|
## FAQ
|
||||||
|
|
||||||
1. Why reimplement stack?
|
### 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.
|
GHCup is not a reimplementation of stack. The only common part is automatic installation of GHC,
|
||||||
|
but even that differs in scope and design.
|
||||||
|
|
||||||
2. Why not support windows?
|
### Why should I use ghcup over stack?
|
||||||
|
|
||||||
Consider using [Chocolatey](https://chocolatey.org/search?q=ghc) or [ghcups](https://github.com/kakkun61/ghcups).
|
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.
|
||||||
|
|
||||||
3. Why the haskell reimplementation?
|
### Why should I let ghcup manage stack?
|
||||||
|
|
||||||
Why not?
|
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?
|
||||||
|
|
||||||
|
Oddly, this question has been asked a couple of times. For the curious, here are a few reasons:
|
||||||
|
|
||||||
|
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. Even if they did, it doesn't seem it would have satisfied their needs
|
||||||
|
- it didn't support cabal installation, which was the main motivation behind GHCup back then
|
||||||
|
- 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
|
||||||
|
- 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.
|
||||||
|
3. GHCup is built around unix principles and supposed to be simple.
|
||||||
|
|
||||||
|
### 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.
|
||||||
|
|
||||||
|
How bad do we need this?
|
||||||
|
|
||||||
|
### 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.
|
||||||
|
|
||||||
|
### Is GHCup affiliated with the Haskell Foundation?
|
||||||
|
|
||||||
|
There has been some collaboration: Windows and Stack support were mainly requested by the Haskell Foundation
|
||||||
|
and those seemed interesting features to add.
|
||||||
|
|
||||||
|
Other than that, GHCup is dedicated only to its users and is supported by haskell.org through hosting and CI
|
||||||
|
infrastructure.
|
||||||
|
|||||||
@@ -69,13 +69,15 @@ tarballFilterP = option readm $
|
|||||||
long "tarball-filter" <> short 'u' <> metavar "<tool>-<version>" <> value def
|
long "tarball-filter" <> short 'u' <> metavar "<tool>-<version>" <> value def
|
||||||
<> help "Only check certain tarballs (format: <tool>-<version>)"
|
<> help "Only check certain tarballs (format: <tool>-<version>)"
|
||||||
where
|
where
|
||||||
def = TarballFilter Nothing (makeRegex ("" :: String))
|
def = TarballFilter (Right Nothing) (makeRegex ("" :: String))
|
||||||
readm = do
|
readm = do
|
||||||
s <- str
|
s <- str
|
||||||
case span (/= '-') s of
|
case span (/= '-') s of
|
||||||
(_, []) -> fail "invalid format, missing '-' after the tool name"
|
(_, []) -> fail "invalid format, missing '-' after the tool name"
|
||||||
(t, v) | [tool] <- [ tool | tool <- [minBound..maxBound], low (show tool) == low t ] ->
|
(t, v) | [tool] <- [ tool | tool <- [minBound..maxBound], low (show tool) == low t ] ->
|
||||||
pure (TarballFilter $ Just tool) <*> makeRegexOptsM compIgnoreCase execBlank (drop 1 v)
|
pure (TarballFilter $ Right $ Just tool) <*> makeRegexOptsM compIgnoreCase execBlank (drop 1 v)
|
||||||
|
(t, v) | [tool] <- [ tool | tool <- [minBound..maxBound], low (show tool) == low t ] ->
|
||||||
|
pure (TarballFilter $ Left tool) <*> makeRegexOptsM compIgnoreCase execBlank (drop 1 v)
|
||||||
_ -> fail "invalid tool"
|
_ -> fail "invalid tool"
|
||||||
low = fmap toLower
|
low = fmap toLower
|
||||||
|
|
||||||
@@ -105,26 +107,21 @@ main :: IO ()
|
|||||||
main = do
|
main = do
|
||||||
_ <- customExecParser (prefs showHelpOnError) (info (opts <**> helper) idm)
|
_ <- customExecParser (prefs showHelpOnError) (info (opts <**> helper) idm)
|
||||||
>>= \Options {..} -> case optCommand of
|
>>= \Options {..} -> case optCommand of
|
||||||
ValidateYAML vopts -> case vopts of
|
ValidateYAML vopts -> withValidateYamlOpts vopts validate
|
||||||
ValidateYAMLOpts { vInput = Nothing } ->
|
ValidateTarballs vopts tarballFilter -> withValidateYamlOpts vopts (validateTarballs tarballFilter)
|
||||||
B.getContents >>= valAndExit validate
|
|
||||||
ValidateYAMLOpts { vInput = Just StdInput } ->
|
|
||||||
B.getContents >>= valAndExit validate
|
|
||||||
ValidateYAMLOpts { vInput = Just (FileInput file) } ->
|
|
||||||
B.readFile file >>= valAndExit validate
|
|
||||||
ValidateTarballs vopts tarballFilter -> case vopts of
|
|
||||||
ValidateYAMLOpts { vInput = Nothing } ->
|
|
||||||
B.getContents >>= valAndExit (validateTarballs tarballFilter)
|
|
||||||
ValidateYAMLOpts { vInput = Just StdInput } ->
|
|
||||||
B.getContents >>= valAndExit (validateTarballs tarballFilter)
|
|
||||||
ValidateYAMLOpts { vInput = Just (FileInput file) } ->
|
|
||||||
B.readFile file >>= valAndExit (validateTarballs tarballFilter)
|
|
||||||
pure ()
|
pure ()
|
||||||
|
|
||||||
where
|
where
|
||||||
|
withValidateYamlOpts vopts f = case vopts of
|
||||||
|
ValidateYAMLOpts { vInput = Nothing } ->
|
||||||
|
B.getContents >>= valAndExit f
|
||||||
|
ValidateYAMLOpts { vInput = Just StdInput } ->
|
||||||
|
B.getContents >>= valAndExit f
|
||||||
|
ValidateYAMLOpts { vInput = Just (FileInput file) } ->
|
||||||
|
B.readFile file >>= valAndExit f
|
||||||
valAndExit f contents = do
|
valAndExit f contents = do
|
||||||
(GHCupInfo _ av) <- case Y.decodeEither' contents of
|
(GHCupInfo _ av gt) <- case Y.decodeEither' contents of
|
||||||
Right r -> pure r
|
Right r -> pure r
|
||||||
Left e -> die (color Red $ show e)
|
Left e -> die (color Red $ show e)
|
||||||
myLoggerT (LoggerConfig True (B.hPut stdout) (\_ -> pure ())) (f av)
|
myLoggerT (LoggerConfig True (B.hPut stdout) (\_ -> pure ())) (f av gt)
|
||||||
>>= exitWith
|
>>= exitWith
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ module Validate where
|
|||||||
import GHCup
|
import GHCup
|
||||||
import GHCup.Download
|
import GHCup.Download
|
||||||
import GHCup.Errors
|
import GHCup.Errors
|
||||||
import GHCup.Types
|
import GHCup.Platform
|
||||||
|
import GHCup.Types hiding ( LeanAppState (..) )
|
||||||
import GHCup.Types.Optics
|
import GHCup.Types.Optics
|
||||||
import GHCup.Utils
|
import GHCup.Utils
|
||||||
import GHCup.Utils.Logger
|
import GHCup.Utils.Logger
|
||||||
@@ -22,6 +23,7 @@ import qualified Codec.Archive.Tar as Tar
|
|||||||
#else
|
#else
|
||||||
import Codec.Archive
|
import Codec.Archive
|
||||||
#endif
|
#endif
|
||||||
|
import Control.Applicative
|
||||||
import Control.Exception.Safe
|
import Control.Exception.Safe
|
||||||
import Control.Monad
|
import Control.Monad
|
||||||
import Control.Monad.IO.Class
|
import Control.Monad.IO.Class
|
||||||
@@ -37,12 +39,11 @@ import Data.IORef
|
|||||||
import Data.List
|
import Data.List
|
||||||
import Data.String.Interpolate
|
import Data.String.Interpolate
|
||||||
import Data.Versions
|
import Data.Versions
|
||||||
import HPath ( toFilePath )
|
|
||||||
import Haskus.Utils.Variant.Excepts
|
import Haskus.Utils.Variant.Excepts
|
||||||
import Optics
|
import Optics
|
||||||
|
import System.FilePath
|
||||||
import System.Exit
|
import System.Exit
|
||||||
import System.IO
|
import System.IO
|
||||||
import System.Posix.FilePath
|
|
||||||
import Text.ParserCombinators.ReadP
|
import Text.ParserCombinators.ReadP
|
||||||
import Text.PrettyPrint.HughesPJClass ( prettyShow )
|
import Text.PrettyPrint.HughesPJClass ( prettyShow )
|
||||||
import Text.Regex.Posix
|
import Text.Regex.Posix
|
||||||
@@ -67,8 +68,9 @@ addError = do
|
|||||||
|
|
||||||
validate :: (Monad m, MonadLogger m, MonadThrow m, MonadIO m, MonadUnliftIO m)
|
validate :: (Monad m, MonadLogger m, MonadThrow m, MonadIO m, MonadUnliftIO m)
|
||||||
=> GHCupDownloads
|
=> GHCupDownloads
|
||||||
|
-> M.Map GlobalTool DownloadInfo
|
||||||
-> m ExitCode
|
-> m ExitCode
|
||||||
validate dls = do
|
validate dls _ = do
|
||||||
ref <- liftIO $ newIORef 0
|
ref <- liftIO $ newIORef 0
|
||||||
|
|
||||||
-- verify binary downloads --
|
-- verify binary downloads --
|
||||||
@@ -106,6 +108,10 @@ validate dls = do
|
|||||||
addError
|
addError
|
||||||
when ((notElem FreeBSD pspecs) && arch == A_64) $ lift $ $(logWarn)
|
when ((notElem FreeBSD pspecs) && arch == A_64) $ lift $ $(logWarn)
|
||||||
[i|FreeBSD missing for #{t} #{v'} #{arch'}|]
|
[i|FreeBSD missing for #{t} #{v'} #{arch'}|]
|
||||||
|
when (notElem Windows pspecs && arch == A_64) $ do
|
||||||
|
lift $ $(logError)
|
||||||
|
[i|Windows missing for for #{t} #{v'} #{arch'}|]
|
||||||
|
addError
|
||||||
|
|
||||||
-- alpine needs to be set explicitly, because
|
-- alpine needs to be set explicitly, because
|
||||||
-- we cannot assume that "Linux UnknownLinux" runs on Alpine
|
-- we cannot assume that "Linux UnknownLinux" runs on Alpine
|
||||||
@@ -120,7 +126,7 @@ validate dls = do
|
|||||||
_ -> lift $ $(logWarn) [i|Linux Alpine missing for #{t} #{v'} #{arch'}|]
|
_ -> lift $ $(logWarn) [i|Linux Alpine missing for #{t} #{v'} #{arch'}|]
|
||||||
|
|
||||||
checkUniqueTags tool = do
|
checkUniqueTags tool = do
|
||||||
let allTags = join $ M.elems $ availableToolVersions dls tool
|
let allTags = join $ fmap _viTags $ M.elems $ availableToolVersions dls tool
|
||||||
let nonUnique =
|
let nonUnique =
|
||||||
fmap fst
|
fmap fst
|
||||||
. filter (\(_, b) -> not b)
|
. filter (\(_, b) -> not b)
|
||||||
@@ -158,7 +164,7 @@ validate dls = do
|
|||||||
|
|
||||||
-- a tool must have at least one of each mandatory tags
|
-- a tool must have at least one of each mandatory tags
|
||||||
checkMandatoryTags tool = do
|
checkMandatoryTags tool = do
|
||||||
let allTags = join $ M.elems $ availableToolVersions dls tool
|
let allTags = join $ fmap _viTags $ M.elems $ availableToolVersions dls tool
|
||||||
forM_ [Latest, Recommended] $ \t -> case elem t allTags of
|
forM_ [Latest, Recommended] $ \t -> case elem t allTags of
|
||||||
False -> do
|
False -> do
|
||||||
lift $ $(logError) [i|Tag #{t} missing from #{tool}|]
|
lift $ $(logError) [i|Tag #{t} missing from #{tool}|]
|
||||||
@@ -168,7 +174,7 @@ validate dls = do
|
|||||||
-- all GHC versions must have a base tag
|
-- all GHC versions must have a base tag
|
||||||
checkGHCHasBaseVersion = do
|
checkGHCHasBaseVersion = do
|
||||||
let allTags = M.toList $ availableToolVersions dls GHC
|
let allTags = M.toList $ availableToolVersions dls GHC
|
||||||
forM allTags $ \(ver, tags) -> case any isBase tags of
|
forM allTags $ \(ver, _viTags -> tags) -> case any isBase tags of
|
||||||
False -> do
|
False -> do
|
||||||
lift $ $(logError) [i|Base tag missing from GHC ver #{ver}|]
|
lift $ $(logError) [i|Base tag missing from GHC ver #{ver}|]
|
||||||
addError
|
addError
|
||||||
@@ -178,7 +184,7 @@ validate dls = do
|
|||||||
isBase _ = False
|
isBase _ = False
|
||||||
|
|
||||||
data TarballFilter = TarballFilter
|
data TarballFilter = TarballFilter
|
||||||
{ tfTool :: Maybe Tool
|
{ tfTool :: Either GlobalTool (Maybe Tool)
|
||||||
, tfVersion :: Regex
|
, tfVersion :: Regex
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,21 +194,23 @@ validateTarballs :: ( Monad m
|
|||||||
, MonadIO m
|
, MonadIO m
|
||||||
, MonadUnliftIO m
|
, MonadUnliftIO m
|
||||||
, MonadMask m
|
, MonadMask m
|
||||||
|
, Alternative m
|
||||||
|
, MonadFail m
|
||||||
)
|
)
|
||||||
=> TarballFilter
|
=> TarballFilter
|
||||||
-> GHCupDownloads
|
-> GHCupDownloads
|
||||||
|
-> M.Map GlobalTool DownloadInfo
|
||||||
-> m ExitCode
|
-> m ExitCode
|
||||||
validateTarballs (TarballFilter tool versionRegex) dls = do
|
validateTarballs (TarballFilter etool versionRegex) dls gt = do
|
||||||
ref <- liftIO $ newIORef 0
|
ref <- liftIO $ newIORef 0
|
||||||
|
|
||||||
flip runReaderT ref $ do
|
flip runReaderT ref $ do
|
||||||
-- download/verify all tarballs
|
-- download/verify all tarballs
|
||||||
let dlis = nubOrd $ dls ^.. each
|
let dlis = either (const []) (\tool -> nubOrd $ dls ^.. each %& indices (maybe (const True) (==) tool) %> each %& indices (matchTest versionRegex . T.unpack . prettyVer) % (viSourceDL % _Just `summing` viArch % each % each % each)) etool
|
||||||
%& indices (maybe (const True) (==) tool) %> each
|
let gdlis = nubOrd $ gt ^.. each
|
||||||
%& indices (matchTest versionRegex . T.unpack . prettyVer)
|
let allDls = either (const gdlis) (const dlis) etool
|
||||||
% (viSourceDL % _Just `summing` viArch % each % each % each)
|
when (null allDls) $ $(logError) [i|no tarballs selected by filter|] *> addError
|
||||||
when (null dlis) $ $(logError) [i|no tarballs selected by filter|] *> addError
|
forM_ allDls downloadAll
|
||||||
forM_ dlis downloadAll
|
|
||||||
|
|
||||||
-- exit
|
-- exit
|
||||||
e <- liftIO $ readIORef ref
|
e <- liftIO $ readIORef ref
|
||||||
@@ -218,12 +226,22 @@ validateTarballs (TarballFilter tool versionRegex) dls = do
|
|||||||
, rawOutter = \_ -> pure ()
|
, rawOutter = \_ -> pure ()
|
||||||
}
|
}
|
||||||
downloadAll dli = do
|
downloadAll dli = do
|
||||||
dirs <- liftIO getDirs
|
dirs <- liftIO getAllDirs
|
||||||
let settings = AppState (Settings True False Never Curl False GHCupURL) dirs defaultKeyBindings
|
|
||||||
|
pfreq <- (
|
||||||
|
runLogger . runE @'[NoCompatiblePlatform, NoCompatibleArch, DistroNotFound] . liftE $ platformRequest
|
||||||
|
) >>= \case
|
||||||
|
VRight r -> pure r
|
||||||
|
VLeft e -> do
|
||||||
|
lift $ runLogger
|
||||||
|
($(logError) $ T.pack $ prettyShow e)
|
||||||
|
liftIO $ exitWith (ExitFailure 2)
|
||||||
|
|
||||||
|
let appstate = AppState (Settings True False Never Curl False GHCupURL False) dirs defaultKeyBindings (GHCupInfo mempty mempty mempty) pfreq
|
||||||
|
|
||||||
r <-
|
r <-
|
||||||
runLogger
|
runLogger
|
||||||
. flip runReaderT settings
|
. flip runReaderT appstate
|
||||||
. runResourceT
|
. runResourceT
|
||||||
. runE @'[DigestError
|
. runE @'[DigestError
|
||||||
, DownloadFailed
|
, DownloadFailed
|
||||||
@@ -235,15 +253,25 @@ validateTarballs (TarballFilter tool versionRegex) dls = do
|
|||||||
#endif
|
#endif
|
||||||
]
|
]
|
||||||
$ do
|
$ do
|
||||||
p <- liftE $ downloadCached dli Nothing
|
case etool of
|
||||||
fmap (head . splitDirectories . head)
|
Right (Just GHCup) -> do
|
||||||
. liftE
|
tmpUnpack <- lift mkGhcupTmpDir
|
||||||
. getArchiveFiles
|
_ <- liftE $ download (_dlUri dli) (Just (_dlHash dli)) tmpUnpack Nothing False
|
||||||
$ p
|
pure Nothing
|
||||||
|
Right _ -> do
|
||||||
|
p <- liftE $ downloadCached dli Nothing
|
||||||
|
fmap (Just . head . splitDirectories . head)
|
||||||
|
. liftE
|
||||||
|
. getArchiveFiles
|
||||||
|
$ p
|
||||||
|
Left ShimGen -> do
|
||||||
|
tmpUnpack <- lift mkGhcupTmpDir
|
||||||
|
_ <- liftE $ download (_dlUri dli) (Just (_dlHash dli)) tmpUnpack Nothing False
|
||||||
|
pure Nothing
|
||||||
case r of
|
case r of
|
||||||
VRight basePath -> do
|
VRight (Just basePath) -> do
|
||||||
case _dlSubdir dli of
|
case _dlSubdir dli of
|
||||||
Just (RealDir (toFilePath -> prel)) -> do
|
Just (RealDir prel) -> do
|
||||||
lift $ $(logInfo)
|
lift $ $(logInfo)
|
||||||
[i|verifying subdir: #{prel}|]
|
[i|verifying subdir: #{prel}|]
|
||||||
when (basePath /= prel) $ do
|
when (basePath /= prel) $ do
|
||||||
@@ -262,7 +290,8 @@ validateTarballs (TarballFilter tool versionRegex) dls = do
|
|||||||
[i|Subdir doesn't match: expected regex "#{regexString}", got "#{basePath}"|]
|
[i|Subdir doesn't match: expected regex "#{regexString}", got "#{basePath}"|]
|
||||||
addError
|
addError
|
||||||
Nothing -> pure ()
|
Nothing -> pure ()
|
||||||
|
VRight Nothing -> pure ()
|
||||||
VLeft e -> do
|
VLeft e -> do
|
||||||
lift $ $(logError)
|
lift $ $(logError)
|
||||||
[i|Could not download (or verify hash) of #{dli}, Error was: #{e}|]
|
[i|Could not download (or verify hash) of #{dli}, Error was: #{prettyShow e}|]
|
||||||
addError
|
addError
|
||||||
|
|||||||
@@ -6,14 +6,16 @@
|
|||||||
{-# LANGUAGE TemplateHaskell #-}
|
{-# LANGUAGE TemplateHaskell #-}
|
||||||
{-# LANGUAGE TypeApplications #-}
|
{-# LANGUAGE TypeApplications #-}
|
||||||
{-# LANGUAGE ViewPatterns #-}
|
{-# LANGUAGE ViewPatterns #-}
|
||||||
|
{-# LANGUAGE RankNTypes #-}
|
||||||
|
|
||||||
module BrickMain where
|
module BrickMain where
|
||||||
|
|
||||||
import GHCup
|
import GHCup
|
||||||
import GHCup.Download
|
import GHCup.Download
|
||||||
import GHCup.Errors
|
import GHCup.Errors
|
||||||
import GHCup.Types
|
import GHCup.Types hiding ( LeanAppState(..) )
|
||||||
import GHCup.Utils
|
import GHCup.Utils
|
||||||
|
import GHCup.Utils.Prelude ( decUTF8Safe )
|
||||||
import GHCup.Utils.File
|
import GHCup.Utils.File
|
||||||
import GHCup.Utils.Logger
|
import GHCup.Utils.Logger
|
||||||
|
|
||||||
@@ -31,6 +33,7 @@ import Codec.Archive
|
|||||||
import Control.Exception.Safe
|
import Control.Exception.Safe
|
||||||
import Control.Monad.Logger
|
import Control.Monad.Logger
|
||||||
import Control.Monad.Reader
|
import Control.Monad.Reader
|
||||||
|
import Control.Monad.Trans.Except
|
||||||
import Control.Monad.Trans.Resource
|
import Control.Monad.Trans.Resource
|
||||||
import Data.Bool
|
import Data.Bool
|
||||||
import Data.Functor
|
import Data.Functor
|
||||||
@@ -50,23 +53,23 @@ import System.IO.Unsafe
|
|||||||
import Text.PrettyPrint.HughesPJClass ( prettyShow )
|
import Text.PrettyPrint.HughesPJClass ( prettyShow )
|
||||||
import URI.ByteString
|
import URI.ByteString
|
||||||
|
|
||||||
import qualified GHCup.Types as GT
|
|
||||||
|
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import qualified Graphics.Vty as Vty
|
import qualified Graphics.Vty as Vty
|
||||||
import qualified Data.Vector as V
|
import qualified Data.Vector as V
|
||||||
|
|
||||||
|
|
||||||
|
hiddenTools :: [Tool]
|
||||||
|
hiddenTools = []
|
||||||
|
|
||||||
|
|
||||||
data BrickData = BrickData
|
data BrickData = BrickData
|
||||||
{ lr :: [ListResult]
|
{ lr :: [ListResult]
|
||||||
, dls :: GHCupDownloads
|
|
||||||
, pfreq :: PlatformRequest
|
|
||||||
}
|
}
|
||||||
deriving Show
|
deriving Show
|
||||||
|
|
||||||
data BrickSettings = BrickSettings
|
data BrickSettings = BrickSettings
|
||||||
{ showAll :: Bool
|
{ showAllVersions :: Bool
|
||||||
|
, showAllTools :: Bool
|
||||||
}
|
}
|
||||||
deriving Show
|
deriving Show
|
||||||
|
|
||||||
@@ -95,19 +98,24 @@ keyHandlers KeyBindings {..} =
|
|||||||
[ (bQuit, const "Quit" , halt)
|
[ (bQuit, const "Quit" , halt)
|
||||||
, (bInstall, const "Install" , withIOAction install')
|
, (bInstall, const "Install" , withIOAction install')
|
||||||
, (bUninstall, const "Uninstall", withIOAction del')
|
, (bUninstall, const "Uninstall", withIOAction del')
|
||||||
, (bSet, const "Set" , withIOAction set')
|
, (bSet, const "Set" , withIOAction ((liftIO .) . set'))
|
||||||
, (bChangelog, const "ChangeLog", withIOAction changelog')
|
, (bChangelog, const "ChangeLog", withIOAction changelog')
|
||||||
, ( bShowAll
|
, ( bShowAllVersions
|
||||||
, \BrickSettings {..} ->
|
, \BrickSettings {..} ->
|
||||||
if showAll then "Hide old versions" else "Show all versions"
|
if showAllVersions then "Don't show all versions" else "Show all versions"
|
||||||
, hideShowHandler
|
, 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, .. })
|
, (bUp, const "Up", \BrickState {..} -> continue BrickState{ appState = moveCursor 1 appState Up, .. })
|
||||||
, (bDown, const "Down", \BrickState {..} -> continue BrickState{ appState = moveCursor 1 appState Down, .. })
|
, (bDown, const "Down", \BrickState {..} -> continue BrickState{ appState = moveCursor 1 appState Down, .. })
|
||||||
]
|
]
|
||||||
where
|
where
|
||||||
hideShowHandler BrickState{..} =
|
hideShowHandler f p BrickState{..} =
|
||||||
let newAppSettings = appSettings { showAll = not . showAll $ appSettings }
|
let newAppSettings = appSettings { showAllVersions = f appSettings , showAllTools = p appSettings }
|
||||||
newInternalState = constructList appData newAppSettings (Just appState)
|
newInternalState = constructList appData newAppSettings (Just appState)
|
||||||
in continue (BrickState appData newAppSettings newInternalState appKeys)
|
in continue (BrickState appData newAppSettings newInternalState appKeys)
|
||||||
|
|
||||||
@@ -161,7 +169,7 @@ ui dimAttrs BrickState{ appSettings = as@BrickSettings{}, ..}
|
|||||||
| elem Latest lTag && not lInstalled =
|
| elem Latest lTag && not lInstalled =
|
||||||
withAttr "hooray"
|
withAttr "hooray"
|
||||||
| otherwise = id
|
| otherwise = id
|
||||||
active = if b then forceAttr "active" else id
|
active = if b then putCursor "GHCup" (Location (0,0)) . forceAttr "active" else id
|
||||||
in hooray $ active $ dim
|
in hooray $ active $ dim
|
||||||
( marks
|
( marks
|
||||||
<+> padLeft (Pad 2)
|
<+> padLeft (Pad 2)
|
||||||
@@ -194,6 +202,7 @@ ui dimAttrs BrickState{ appSettings = as@BrickSettings{}, ..}
|
|||||||
printTool GHC = str "GHC"
|
printTool GHC = str "GHC"
|
||||||
printTool GHCup = str "GHCup"
|
printTool GHCup = str "GHCup"
|
||||||
printTool HLS = str "HLS"
|
printTool HLS = str "HLS"
|
||||||
|
printTool Stack = str "Stack"
|
||||||
|
|
||||||
printNotes ListResult {..} =
|
printNotes ListResult {..} =
|
||||||
(if hlsPowered then [withAttr "hls-powered" $ str "hls-powered"] else mempty
|
(if hlsPowered then [withAttr "hls-powered" $ str "hls-powered"] else mempty
|
||||||
@@ -248,7 +257,7 @@ app attrs dimAttrs =
|
|||||||
, appHandleEvent = eventHandler
|
, appHandleEvent = eventHandler
|
||||||
, appStartEvent = return
|
, appStartEvent = return
|
||||||
, appAttrMap = const attrs
|
, appAttrMap = const attrs
|
||||||
, appChooseCursor = neverShowCursor
|
, appChooseCursor = showFirstCursor
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultAttributes :: Bool -> AttrMap
|
defaultAttributes :: Bool -> AttrMap
|
||||||
@@ -316,21 +325,25 @@ moveCursor steps ais@BrickInternalState{..} direction =
|
|||||||
|
|
||||||
-- | Suspend the current UI and run an IO action in terminal. If the
|
-- | 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.
|
-- IO action returns a Left value, then it's thrown as userError.
|
||||||
withIOAction :: (BrickState -> (Int, ListResult) -> IO (Either String a))
|
withIOAction :: (BrickState
|
||||||
|
-> (Int, ListResult)
|
||||||
|
-> ReaderT AppState IO (Either String a))
|
||||||
-> BrickState
|
-> BrickState
|
||||||
-> EventM n (Next BrickState)
|
-> EventM n (Next BrickState)
|
||||||
withIOAction action as = case listSelectedElement' (appState as) of
|
withIOAction action as = case listSelectedElement' (appState as) of
|
||||||
Nothing -> continue as
|
Nothing -> continue as
|
||||||
Just (ix, e) -> suspendAndResume $ do
|
Just (ix, e) -> do
|
||||||
action as (ix, e) >>= \case
|
suspendAndResume $ do
|
||||||
Left err -> putStrLn ("Error: " <> err)
|
settings <- readIORef settings'
|
||||||
Right _ -> putStrLn "Success"
|
flip runReaderT settings $ action as (ix, e) >>= \case
|
||||||
getAppData Nothing (pfreq . appData $ as) >>= \case
|
Left err -> liftIO $ putStrLn ("Error: " <> err)
|
||||||
Right data' -> do
|
Right _ -> liftIO $ putStrLn "Success"
|
||||||
putStrLn "Press enter to continue"
|
getAppData Nothing >>= \case
|
||||||
_ <- getLine
|
Right data' -> do
|
||||||
pure (updateList data' as)
|
putStrLn "Press enter to continue"
|
||||||
Left err -> throwIO $ userError err
|
_ <- getLine
|
||||||
|
pure (updateList data' as)
|
||||||
|
Left err -> throwIO $ userError err
|
||||||
|
|
||||||
|
|
||||||
-- | Update app data and list internal state based on new evidence.
|
-- | Update app data and list internal state based on new evidence.
|
||||||
@@ -351,7 +364,9 @@ constructList :: BrickData
|
|||||||
-> Maybe BrickInternalState
|
-> Maybe BrickInternalState
|
||||||
-> BrickInternalState
|
-> BrickInternalState
|
||||||
constructList appD appSettings =
|
constructList appD appSettings =
|
||||||
replaceLR (filterVisible (showAll appSettings)) (lr appD)
|
replaceLR (filterVisible (showAllVersions appSettings)
|
||||||
|
(showAllTools appSettings))
|
||||||
|
(lr appD)
|
||||||
|
|
||||||
listSelectedElement' :: BrickInternalState -> Maybe (Int, ListResult)
|
listSelectedElement' :: BrickInternalState -> Maybe (Int, ListResult)
|
||||||
listSelectedElement' BrickInternalState{..} = fmap (ix, ) $ clr !? ix
|
listSelectedElement' BrickInternalState{..} = fmap (ix, ) $ clr !? ix
|
||||||
@@ -384,21 +399,32 @@ replaceLR filterF lr s =
|
|||||||
lTool e1 == lTool e2 && lVer e1 == lVer e2 && lCross e1 == lCross e2
|
lTool e1 == lTool e2 && lVer e1 == lVer e2 && lCross e1 == lCross e2
|
||||||
|
|
||||||
|
|
||||||
filterVisible :: Bool -> ListResult -> Bool
|
filterVisible :: Bool -> Bool -> ListResult -> Bool
|
||||||
filterVisible showAll e | lInstalled e = True
|
filterVisible v t e | lInstalled e = True
|
||||||
| showAll = True
|
| v
|
||||||
| otherwise = not (elem Old (lTag e))
|
, not t
|
||||||
|
, not (elem (lTool e) hiddenTools) = True
|
||||||
|
| not v
|
||||||
|
, t
|
||||||
|
, not (elem Old (lTag e)) = True
|
||||||
|
| v
|
||||||
|
, t = True
|
||||||
|
| otherwise = not (elem Old (lTag e)) &&
|
||||||
|
not (elem (lTool e) hiddenTools)
|
||||||
|
|
||||||
|
|
||||||
install' :: BrickState -> (Int, ListResult) -> IO (Either String ())
|
install' :: (MonadReader AppState m, MonadIO m, MonadThrow m, MonadFail m, MonadMask m, MonadUnliftIO m)
|
||||||
install' BrickState { appData = BrickData {..} } (_, ListResult {..}) = do
|
=> BrickState
|
||||||
settings <- readIORef settings'
|
-> (Int, ListResult)
|
||||||
l <- readIORef logger'
|
-> m (Either String ())
|
||||||
|
install' _ (_, ListResult {..}) = do
|
||||||
|
AppState { ghcupInfo = GHCupInfo { _ghcupDownloads = dls }} <- ask
|
||||||
|
|
||||||
|
l <- liftIO $ readIORef logger'
|
||||||
let runLogger = myLoggerT l
|
let runLogger = myLoggerT l
|
||||||
|
|
||||||
let run =
|
let run =
|
||||||
runLogger
|
runLogger
|
||||||
. flip runReaderT settings
|
|
||||||
. runResourceT
|
. runResourceT
|
||||||
. runE
|
. runE
|
||||||
@'[ AlreadyInstalled
|
@'[ AlreadyInstalled
|
||||||
@@ -422,21 +448,24 @@ install' BrickState { appData = BrickData {..} } (_, ListResult {..}) = do
|
|||||||
case lTool of
|
case lTool of
|
||||||
GHC -> do
|
GHC -> do
|
||||||
let vi = getVersionInfo lVer GHC dls
|
let vi = getVersionInfo lVer GHC dls
|
||||||
liftE $ installGHCBin dls lVer pfreq $> vi
|
liftE $ installGHCBin lVer $> vi
|
||||||
Cabal -> do
|
Cabal -> do
|
||||||
let vi = getVersionInfo lVer Cabal dls
|
let vi = getVersionInfo lVer Cabal dls
|
||||||
liftE $ installCabalBin dls lVer pfreq $> vi
|
liftE $ installCabalBin lVer $> vi
|
||||||
GHCup -> do
|
GHCup -> do
|
||||||
let vi = snd <$> getLatest dls GHCup
|
let vi = snd <$> getLatest dls GHCup
|
||||||
liftE $ upgradeGHCup dls Nothing False pfreq $> vi
|
liftE $ upgradeGHCup Nothing False $> vi
|
||||||
HLS -> do
|
HLS -> do
|
||||||
let vi = getVersionInfo lVer HLS dls
|
let vi = getVersionInfo lVer HLS dls
|
||||||
liftE $ installHLSBin dls lVer pfreq $> vi
|
liftE $ installHLSBin lVer $> vi
|
||||||
|
Stack -> do
|
||||||
|
let vi = getVersionInfo lVer Stack dls
|
||||||
|
liftE $ installStackBin lVer $> vi
|
||||||
)
|
)
|
||||||
>>= \case
|
>>= \case
|
||||||
VRight vi -> do
|
VRight vi -> do
|
||||||
forM_ (_viPostInstall =<< vi) $ \msg ->
|
forM_ (_viPostInstall =<< vi) $ \msg ->
|
||||||
runLogger $ $(logInfo) msg
|
myLoggerT l $ $(logInfo) msg
|
||||||
pure $ Right ()
|
pure $ Right ()
|
||||||
VLeft (V (AlreadyInstalled _ _)) -> pure $ Right ()
|
VLeft (V (AlreadyInstalled _ _)) -> pure $ Right ()
|
||||||
VLeft (V NoUpdate) -> pure $ Right ()
|
VLeft (V NoUpdate) -> pure $ Right ()
|
||||||
@@ -460,6 +489,7 @@ set' _ (_, ListResult {..}) = do
|
|||||||
GHC -> liftE $ setGHC (GHCTargetVersion lCross lVer) SetGHCOnly $> ()
|
GHC -> liftE $ setGHC (GHCTargetVersion lCross lVer) SetGHCOnly $> ()
|
||||||
Cabal -> liftE $ setCabal lVer $> ()
|
Cabal -> liftE $ setCabal lVer $> ()
|
||||||
HLS -> liftE $ setHLS lVer $> ()
|
HLS -> liftE $ setHLS lVer $> ()
|
||||||
|
Stack -> liftE $ setStack lVer $> ()
|
||||||
GHCup -> pure ()
|
GHCup -> pure ()
|
||||||
)
|
)
|
||||||
>>= \case
|
>>= \case
|
||||||
@@ -467,13 +497,16 @@ set' _ (_, ListResult {..}) = do
|
|||||||
VLeft e -> pure $ Left (prettyShow e)
|
VLeft e -> pure $ Left (prettyShow e)
|
||||||
|
|
||||||
|
|
||||||
del' :: BrickState -> (Int, ListResult) -> IO (Either String ())
|
del' :: (MonadReader AppState m, MonadIO m, MonadFail m, MonadMask m, MonadUnliftIO m)
|
||||||
del' BrickState { appData = BrickData {..} } (_, ListResult {..}) = do
|
=> BrickState
|
||||||
settings <- readIORef settings'
|
-> (Int, ListResult)
|
||||||
l <- readIORef logger'
|
-> m (Either String ())
|
||||||
let runLogger = myLoggerT l
|
del' _ (_, ListResult {..}) = do
|
||||||
|
AppState { ghcupInfo = GHCupInfo { _ghcupDownloads = dls }} <- ask
|
||||||
|
|
||||||
let run = runLogger . flip runReaderT settings . runE @'[NotInstalled]
|
l <- liftIO $ readIORef logger'
|
||||||
|
let runLogger = myLoggerT l
|
||||||
|
let run = myLoggerT l . runE @'[NotInstalled]
|
||||||
|
|
||||||
run (do
|
run (do
|
||||||
let vi = getVersionInfo lVer lTool dls
|
let vi = getVersionInfo lVer lTool dls
|
||||||
@@ -481,6 +514,7 @@ del' BrickState { appData = BrickData {..} } (_, ListResult {..}) = do
|
|||||||
GHC -> liftE $ rmGHCVer (GHCTargetVersion lCross lVer) $> vi
|
GHC -> liftE $ rmGHCVer (GHCTargetVersion lCross lVer) $> vi
|
||||||
Cabal -> liftE $ rmCabalVer lVer $> vi
|
Cabal -> liftE $ rmCabalVer lVer $> vi
|
||||||
HLS -> liftE $ rmHLSVer lVer $> vi
|
HLS -> liftE $ rmHLSVer lVer $> vi
|
||||||
|
Stack -> liftE $ rmStackVer lVer $> vi
|
||||||
GHCup -> pure Nothing
|
GHCup -> pure Nothing
|
||||||
)
|
)
|
||||||
>>= \case
|
>>= \case
|
||||||
@@ -491,8 +525,12 @@ del' BrickState { appData = BrickData {..} } (_, ListResult {..}) = do
|
|||||||
VLeft e -> pure $ Left (prettyShow e)
|
VLeft e -> pure $ Left (prettyShow e)
|
||||||
|
|
||||||
|
|
||||||
changelog' :: BrickState -> (Int, ListResult) -> IO (Either String ())
|
changelog' :: (MonadReader AppState m, MonadIO m)
|
||||||
changelog' BrickState { appData = BrickData {..} } (_, ListResult {..}) = do
|
=> BrickState
|
||||||
|
-> (Int, ListResult)
|
||||||
|
-> m (Either String ())
|
||||||
|
changelog' _ (_, ListResult {..}) = do
|
||||||
|
AppState { pfreq, ghcupInfo = GHCupInfo { _ghcupDownloads = dls }} <- ask
|
||||||
case getChangeLog dls lTool (Left lVer) of
|
case getChangeLog dls lTool (Left lVer) of
|
||||||
Nothing -> pure $ Left
|
Nothing -> pure $ Left
|
||||||
[i|Could not find ChangeLog for #{lTool}, version #{prettyVer lVer}|]
|
[i|Could not find ChangeLog for #{lTool}, version #{prettyVer lVer}|]
|
||||||
@@ -501,7 +539,8 @@ changelog' BrickState { appData = BrickData {..} } (_, ListResult {..}) = do
|
|||||||
Darwin -> "open"
|
Darwin -> "open"
|
||||||
Linux _ -> "xdg-open"
|
Linux _ -> "xdg-open"
|
||||||
FreeBSD -> "xdg-open"
|
FreeBSD -> "xdg-open"
|
||||||
exec cmd True [serializeURIRef' uri] Nothing Nothing >>= \case
|
Windows -> "start"
|
||||||
|
exec cmd [T.unpack $ decUTF8Safe $ serializeURIRef' uri] Nothing Nothing >>= \case
|
||||||
Right _ -> pure $ Right ()
|
Right _ -> pure $ Right ()
|
||||||
Left e -> pure $ Left $ prettyShow e
|
Left e -> pure $ Left $ prettyShow e
|
||||||
|
|
||||||
@@ -509,17 +548,20 @@ changelog' BrickState { appData = BrickData {..} } (_, ListResult {..}) = do
|
|||||||
settings' :: IORef AppState
|
settings' :: IORef AppState
|
||||||
{-# NOINLINE settings' #-}
|
{-# NOINLINE settings' #-}
|
||||||
settings' = unsafePerformIO $ do
|
settings' = unsafePerformIO $ do
|
||||||
dirs <- getDirs
|
dirs <- getAllDirs
|
||||||
newIORef $ AppState (Settings { cache = True
|
newIORef $ AppState (Settings { cache = True
|
||||||
, noVerify = False
|
, noVerify = False
|
||||||
, keepDirs = Never
|
, keepDirs = Never
|
||||||
, downloader = Curl
|
, downloader = Curl
|
||||||
, verbose = False
|
, verbose = False
|
||||||
, urlSource = GHCupURL
|
, urlSource = GHCupURL
|
||||||
|
, noNetwork = False
|
||||||
, ..
|
, ..
|
||||||
})
|
})
|
||||||
dirs
|
dirs
|
||||||
defaultKeyBindings
|
defaultKeyBindings
|
||||||
|
(GHCupInfo mempty mempty mempty)
|
||||||
|
(PlatformRequest A_64 Darwin Nothing)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -535,10 +577,8 @@ logger' = unsafePerformIO
|
|||||||
|
|
||||||
brickMain :: AppState
|
brickMain :: AppState
|
||||||
-> LoggerConfig
|
-> LoggerConfig
|
||||||
-> GHCupDownloads
|
|
||||||
-> PlatformRequest
|
|
||||||
-> IO ()
|
-> IO ()
|
||||||
brickMain s l av pfreq' = do
|
brickMain s l = do
|
||||||
writeIORef settings' s
|
writeIORef settings' s
|
||||||
-- logger interpreter
|
-- logger interpreter
|
||||||
writeIORef logger' l
|
writeIORef logger' l
|
||||||
@@ -546,7 +586,7 @@ brickMain s l av pfreq' = do
|
|||||||
|
|
||||||
no_color <- isJust <$> lookupEnv "NO_COLOR"
|
no_color <- isJust <$> lookupEnv "NO_COLOR"
|
||||||
|
|
||||||
eAppData <- getAppData (Just av) pfreq'
|
eAppData <- getAppData (Just $ ghcupInfo s)
|
||||||
case eAppData of
|
case eAppData of
|
||||||
Right ad ->
|
Right ad ->
|
||||||
defaultMain
|
defaultMain
|
||||||
@@ -554,7 +594,7 @@ brickMain s l av pfreq' = do
|
|||||||
(BrickState ad
|
(BrickState ad
|
||||||
defaultAppSettings
|
defaultAppSettings
|
||||||
(constructList ad defaultAppSettings Nothing)
|
(constructList ad defaultAppSettings Nothing)
|
||||||
(keyBindings s)
|
(keyBindings (s :: AppState))
|
||||||
|
|
||||||
)
|
)
|
||||||
$> ()
|
$> ()
|
||||||
@@ -564,11 +604,11 @@ brickMain s l av pfreq' = do
|
|||||||
|
|
||||||
|
|
||||||
defaultAppSettings :: BrickSettings
|
defaultAppSettings :: BrickSettings
|
||||||
defaultAppSettings = BrickSettings { showAll = False }
|
defaultAppSettings = BrickSettings { showAllVersions = False, showAllTools = False }
|
||||||
|
|
||||||
|
|
||||||
getDownloads' :: IO (Either String GHCupDownloads)
|
getGHCupInfo :: IO (Either String GHCupInfo)
|
||||||
getDownloads' = do
|
getGHCupInfo = do
|
||||||
settings <- readIORef settings'
|
settings <- readIORef settings'
|
||||||
l <- readIORef logger'
|
l <- readIORef logger'
|
||||||
let runLogger = myLoggerT l
|
let runLogger = myLoggerT l
|
||||||
@@ -577,29 +617,25 @@ getDownloads' = do
|
|||||||
runLogger
|
runLogger
|
||||||
. flip runReaderT settings
|
. flip runReaderT settings
|
||||||
. runE @'[JSONError , DownloadFailed , FileDoesNotExistError]
|
. runE @'[JSONError , DownloadFailed , FileDoesNotExistError]
|
||||||
$ fmap _ghcupDownloads
|
|
||||||
$ liftE
|
$ liftE
|
||||||
$ getDownloadsF (urlSource . GT.settings $ settings)
|
$ getDownloadsF
|
||||||
|
|
||||||
case r of
|
case r of
|
||||||
VRight a -> pure $ Right a
|
VRight a -> pure $ Right a
|
||||||
VLeft e -> pure $ Left (prettyShow e)
|
VLeft e -> pure $ Left (prettyShow e)
|
||||||
|
|
||||||
|
|
||||||
getAppData :: Maybe GHCupDownloads
|
getAppData :: Maybe GHCupInfo
|
||||||
-> PlatformRequest
|
|
||||||
-> IO (Either String BrickData)
|
-> IO (Either String BrickData)
|
||||||
getAppData mg pfreq' = do
|
getAppData mgi = runExceptT $ do
|
||||||
settings <- readIORef settings'
|
l <- liftIO $ readIORef logger'
|
||||||
l <- readIORef logger'
|
|
||||||
let runLogger = myLoggerT l
|
let runLogger = myLoggerT l
|
||||||
|
|
||||||
r <- maybe getDownloads' (pure . Right) mg
|
r <- ExceptT $ maybe getGHCupInfo (pure . Right) mgi
|
||||||
|
liftIO $ modifyIORef settings' (\s -> s { ghcupInfo = r })
|
||||||
|
settings <- liftIO $ readIORef settings'
|
||||||
|
|
||||||
runLogger . flip runReaderT settings $ do
|
runLogger . flip runReaderT settings $ do
|
||||||
case r of
|
lV <- listVersions Nothing Nothing
|
||||||
Right dls -> do
|
pure $ BrickData (reverse lV)
|
||||||
lV <- listVersions dls Nothing Nothing pfreq'
|
|
||||||
pure $ Right $ BrickData (reverse lV) dls pfreq'
|
|
||||||
Left e -> pure $ Left [i|#{e}|]
|
|
||||||
|
|
||||||
|
|||||||
1224
app/ghcup/Main.hs
1224
app/ghcup/Main.hs
File diff suppressed because it is too large
Load Diff
@@ -5,8 +5,12 @@
|
|||||||
# * BOOTSTRAP_HASKELL_NO_UPGRADE - any nonzero value to not trigger the upgrade
|
# * BOOTSTRAP_HASKELL_NO_UPGRADE - any nonzero value to not trigger the upgrade
|
||||||
# * GHCUP_USE_XDG_DIRS - any nonzero value to respect The XDG Base Directory Specification
|
# * GHCUP_USE_XDG_DIRS - any nonzero value to respect The XDG Base Directory Specification
|
||||||
# * BOOTSTRAP_HASKELL_VERBOSE - any nonzero value for more verbose installation
|
# * BOOTSTRAP_HASKELL_VERBOSE - any nonzero value for more verbose installation
|
||||||
# * BOOTSTRAP_HASKELL_GHC_VERSION
|
# * BOOTSTRAP_HASKELL_GHC_VERSION - the ghc version to install
|
||||||
# * BOOTSTRAP_HASKELL_CABAL_VERSION
|
# * BOOTSTRAP_HASKELL_CABAL_VERSION - the cabal version to install
|
||||||
|
# * BOOTSTRAP_HASKELL_INSTALL_STACK - whether to install latest stack
|
||||||
|
# * BOOTSTRAP_HASKELL_INSTALL_HLS - whether to install latest hls
|
||||||
|
# * BOOTSTRAP_HASKELL_ADJUST_BASHRC - whether to adjust PATH in bashrc (prepend)
|
||||||
|
# * BOOTSTRAP_HASKELL_ADJUST_CABAL_CONFIG - whether to adjust mingw paths in cabal.config on windows
|
||||||
|
|
||||||
# License: LGPL-3.0
|
# License: LGPL-3.0
|
||||||
|
|
||||||
@@ -14,26 +18,76 @@
|
|||||||
# safety subshell to avoid executing anything in case this script is not downloaded properly
|
# safety subshell to avoid executing anything in case this script is not downloaded properly
|
||||||
(
|
(
|
||||||
|
|
||||||
: "${GHCUP_INSTALL_BASE_PREFIX:=$HOME}"
|
plat="$(uname -s)"
|
||||||
|
arch=$(uname -m)
|
||||||
|
ghver="0.1.16.1"
|
||||||
|
base_url="https://downloads.haskell.org/~ghcup"
|
||||||
|
|
||||||
export GHCUP_USE_XDG_DIRS
|
export GHCUP_SKIP_UPDATE_CHECK=yes
|
||||||
|
|
||||||
if [ -n "${GHCUP_USE_XDG_DIRS}" ] ; then
|
case "${plat}" in
|
||||||
GHCUP_DIR=${XDG_DATA_HOME:=$HOME/.local/share}/ghcup
|
MSYS*|MINGW*)
|
||||||
GHCUP_BIN=${XDG_BIN_HOME:=$HOME/.local/bin}
|
: "${GHCUP_INSTALL_BASE_PREFIX:=/c}"
|
||||||
else
|
GHCUP_DIR=$(cygpath -u "${GHCUP_INSTALL_BASE_PREFIX}/ghcup")
|
||||||
GHCUP_DIR=${GHCUP_INSTALL_BASE_PREFIX}/.ghcup
|
GHCUP_BIN=$(cygpath -u "${GHCUP_INSTALL_BASE_PREFIX}/ghcup/bin")
|
||||||
GHCUP_BIN=${GHCUP_INSTALL_BASE_PREFIX}/.ghcup/bin
|
: "${GHCUP_MSYS2:=${GHCUP_DIR}/msys64}"
|
||||||
fi
|
;;
|
||||||
|
*)
|
||||||
|
: "${GHCUP_INSTALL_BASE_PREFIX:=$HOME}"
|
||||||
|
export GHCUP_USE_XDG_DIRS
|
||||||
|
|
||||||
|
if [ -n "${GHCUP_USE_XDG_DIRS}" ] ; then
|
||||||
|
GHCUP_DIR=${XDG_DATA_HOME:=$HOME/.local/share}/ghcup
|
||||||
|
GHCUP_BIN=${XDG_BIN_HOME:=$HOME/.local/bin}
|
||||||
|
else
|
||||||
|
GHCUP_DIR=${GHCUP_INSTALL_BASE_PREFIX}/.ghcup
|
||||||
|
GHCUP_BIN=${GHCUP_INSTALL_BASE_PREFIX}/.ghcup/bin
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
: "${BOOTSTRAP_HASKELL_GHC_VERSION:=recommended}"
|
: "${BOOTSTRAP_HASKELL_GHC_VERSION:=recommended}"
|
||||||
: "${BOOTSTRAP_HASKELL_CABAL_VERSION:=recommended}"
|
: "${BOOTSTRAP_HASKELL_CABAL_VERSION:=recommended}"
|
||||||
|
|
||||||
|
|
||||||
die() {
|
die() {
|
||||||
(>&2 printf "\\033[0;31m%s\\033[0m\\n" "$1")
|
(>&2 printf "\\033[0;31m%s\\033[0m\\n" "$1")
|
||||||
exit 2
|
exit 2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
warn() {
|
||||||
|
case "${plat}" in
|
||||||
|
MSYS*|MINGW*)
|
||||||
|
echo -e "\\033[0;35m$1\\033[0m"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
printf "\\033[0;35m%s\\033[0m\\n" "$1"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
yellow() {
|
||||||
|
case "${plat}" in
|
||||||
|
MSYS*|MINGW*)
|
||||||
|
echo -e "\\033[0;33m$1\\033[0m"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
printf "\\033[0;33m%s\\033[0m\\n" "$1"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
green() {
|
||||||
|
case "${plat}" in
|
||||||
|
MSYS*|MINGW*)
|
||||||
|
echo -e "\\033[0;32m$1\\033[0m"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
printf "\\033[0;32m%s\\033[0m\\n" "$1"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
edo() {
|
edo() {
|
||||||
"$@" || die "\"$*\" failed!"
|
"$@" || die "\"$*\" failed!"
|
||||||
}
|
}
|
||||||
@@ -43,196 +97,155 @@ eghcup() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_eghcup() {
|
_eghcup() {
|
||||||
|
if [ -n "${BOOTSTRAP_HASKELL_YAML}" ] ; then
|
||||||
|
args="-s ${BOOTSTRAP_HASKELL_YAML}"
|
||||||
|
fi
|
||||||
if [ -z "${BOOTSTRAP_HASKELL_VERBOSE}" ] ; then
|
if [ -z "${BOOTSTRAP_HASKELL_VERBOSE}" ] ; then
|
||||||
ghcup "$@"
|
"${GHCUP_BIN}/ghcup" ${args} "$@"
|
||||||
else
|
else
|
||||||
ghcup --verbose "$@"
|
"${GHCUP_BIN}/ghcup" ${args} --verbose "$@"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
_done() {
|
_done() {
|
||||||
echo
|
echo
|
||||||
echo "All done!"
|
echo "==============================================================================="
|
||||||
echo
|
case "${plat}" in
|
||||||
echo "To start a simple repl, run:"
|
MSYS*|MINGW*)
|
||||||
echo " ghci"
|
green
|
||||||
echo
|
green "All done!"
|
||||||
echo "To start a new haskell project in the current directory, run:"
|
green
|
||||||
echo " cabal init --interactive"
|
green "In a new powershell or cmd.exe session, now you can..."
|
||||||
echo
|
green
|
||||||
echo "To install other GHC versions, run:"
|
green "Start a simple repl via:"
|
||||||
echo " ghcup tui"
|
green " ghci"
|
||||||
|
green
|
||||||
|
green "Start a new haskell project in the current directory via:"
|
||||||
|
green " cabal init --interactive"
|
||||||
|
green
|
||||||
|
green "Install other GHC versions and tools via:"
|
||||||
|
green " ghcup list"
|
||||||
|
green " ghcup install <tool> <version>"
|
||||||
|
green
|
||||||
|
green "To install system libraries and update msys2/mingw64,"
|
||||||
|
green "open the \"Mingw haskell shell\""
|
||||||
|
green "and the \"Mingw package management docs\""
|
||||||
|
green "desktop shortcuts."
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
green
|
||||||
|
green "All done!"
|
||||||
|
green
|
||||||
|
green "To start a simple repl, run:"
|
||||||
|
green " ghci"
|
||||||
|
green
|
||||||
|
green "To start a new haskell project in the current directory, run:"
|
||||||
|
green " cabal init --interactive"
|
||||||
|
green
|
||||||
|
green "To install other GHC versions and tools, run:"
|
||||||
|
green " ghcup tui"
|
||||||
|
;;
|
||||||
|
|
||||||
|
esac
|
||||||
|
|
||||||
|
|
||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
|
|
||||||
download_ghcup() {
|
download_ghcup() {
|
||||||
_plat="$(uname -s)"
|
|
||||||
_arch=$(uname -m)
|
|
||||||
_ghver="0.1.14"
|
|
||||||
_base_url="https://downloads.haskell.org/~ghcup"
|
|
||||||
|
|
||||||
case "${_plat}" in
|
case "${plat}" in
|
||||||
"linux"|"Linux")
|
"linux"|"Linux")
|
||||||
case "${_arch}" in
|
case "${arch}" in
|
||||||
x86_64|amd64)
|
x86_64|amd64)
|
||||||
# we could be in a 32bit docker container, in which
|
# we could be in a 32bit docker container, in which
|
||||||
# case uname doesn't give us what we want
|
# case uname doesn't give us what we want
|
||||||
if [ "$(getconf LONG_BIT)" = "32" ] ; then
|
if [ "$(getconf LONG_BIT)" = "32" ] ; then
|
||||||
_url=${_base_url}/${_ghver}/i386-linux-ghcup-${_ghver}
|
_url=${base_url}/${ghver}/i386-linux-ghcup-${ghver}
|
||||||
elif [ "$(getconf LONG_BIT)" = "64" ] ; then
|
elif [ "$(getconf LONG_BIT)" = "64" ] ; then
|
||||||
_url=${_base_url}/${_ghver}/x86_64-linux-ghcup-${_ghver}
|
_url=${base_url}/${ghver}/x86_64-linux-ghcup-${ghver}
|
||||||
else
|
else
|
||||||
die "Unknown long bit size: $(getconf LONG_BIT)"
|
die "Unknown long bit size: $(getconf LONG_BIT)"
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
i*86)
|
i*86)
|
||||||
_url=${_base_url}/${_ghver}/i386-linux-ghcup-${_ghver}
|
_url=${base_url}/${ghver}/i386-linux-ghcup-${ghver}
|
||||||
;;
|
;;
|
||||||
armv7*)
|
armv7*)
|
||||||
_url=${_base_url}/${_ghver}/armv7-linux-ghcup-${_ghver}
|
_url=${base_url}/${ghver}/armv7-linux-ghcup-${ghver}
|
||||||
;;
|
;;
|
||||||
aarch64|arm64|armv8l)
|
aarch64|arm64|armv8l)
|
||||||
_url=${_base_url}/${_ghver}/aarch64-linux-ghcup-${_ghver}
|
_url=${base_url}/${ghver}/aarch64-linux-ghcup-${ghver}
|
||||||
;;
|
;;
|
||||||
*) die "Unknown architecture: ${_arch}"
|
*) die "Unknown architecture: ${arch}"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
;;
|
;;
|
||||||
"FreeBSD"|"freebsd")
|
"FreeBSD"|"freebsd")
|
||||||
case "${_arch}" in
|
case "${arch}" in
|
||||||
x86_64|amd64)
|
x86_64|amd64)
|
||||||
;;
|
;;
|
||||||
i*86)
|
i*86)
|
||||||
die "i386 currently not supported!"
|
die "i386 currently not supported!"
|
||||||
;;
|
;;
|
||||||
*) die "Unknown architecture: ${_arch}"
|
*) die "Unknown architecture: ${arch}"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
_url=${_base_url}/${_ghver}/x86_64-portbld-freebsd-ghcup-${_ghver}
|
_url=${base_url}/${ghver}/x86_64-portbld-freebsd-ghcup-${ghver}
|
||||||
;;
|
;;
|
||||||
"Darwin"|"darwin")
|
"Darwin"|"darwin")
|
||||||
case "${_arch}" in
|
case "${arch}" in
|
||||||
x86_64|amd64)
|
x86_64|amd64)
|
||||||
|
_url=${base_url}/${ghver}/x86_64-apple-darwin-ghcup-${ghver}
|
||||||
|
;;
|
||||||
|
aarch64|arm64|armv8l)
|
||||||
|
_url=${base_url}/${ghver}/aarch64-apple-darwin-ghcup-${ghver}
|
||||||
;;
|
;;
|
||||||
i*86)
|
i*86)
|
||||||
die "i386 currently not supported!"
|
die "i386 currently not supported!"
|
||||||
;;
|
;;
|
||||||
*) die "Unknown architecture: ${_arch}"
|
*) die "Unknown architecture: ${arch}"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
_url=${_base_url}/${_ghver}/x86_64-apple-darwin-ghcup-${_ghver} ;;
|
;;
|
||||||
*) die "Unknown platform: ${_plat}"
|
MSYS*|MINGW*)
|
||||||
|
case "${arch}" in
|
||||||
|
x86_64|amd64)
|
||||||
|
_url=${base_url}/${ghver}/x86_64-mingw64-ghcup-${ghver}.exe
|
||||||
|
;;
|
||||||
|
*) die "Unknown architecture: ${arch}"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
*) die "Unknown platform: ${plat}"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
case "${plat}" in
|
||||||
|
MSYS*|MINGW*)
|
||||||
|
edo curl -Lf "${_url}" > "${GHCUP_BIN}"/ghcup.exe
|
||||||
|
edo chmod +x "${GHCUP_BIN}"/ghcup.exe
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
edo curl -Lf "${_url}" > "${GHCUP_BIN}"/ghcup
|
||||||
|
edo chmod +x "${GHCUP_BIN}"/ghcup
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
edo curl -Lf "${_url}" > "${GHCUP_BIN}"/ghcup
|
edo mkdir -p "${GHCUP_DIR}"
|
||||||
|
|
||||||
edo chmod +x "${GHCUP_BIN}"/ghcup
|
# we may overwrite this in adjust_bashrc
|
||||||
|
|
||||||
edo mkdir -p "${GHCUP_DIR}"
|
|
||||||
cat <<-EOF > "${GHCUP_DIR}"/env || die "Failed to create env file"
|
cat <<-EOF > "${GHCUP_DIR}"/env || die "Failed to create env file"
|
||||||
export PATH="\$HOME/.cabal/bin:${GHCUP_BIN}:\$PATH"
|
export PATH="\$HOME/.cabal/bin:${GHCUP_BIN}:\$PATH"
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# shellcheck disable=SC1090
|
# shellcheck disable=SC1090
|
||||||
edo . "${GHCUP_DIR}"/env
|
edo . "${GHCUP_DIR}"/env
|
||||||
eghcup upgrade
|
eghcup upgrade
|
||||||
|
|
||||||
unset _plat _arch _url _ghver _base_url
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Figures out the users login shell and sets
|
||||||
echo
|
# GHCUP_PROFILE_FILE and MY_SHELL variables.
|
||||||
echo "Welcome to Haskell!"
|
find_shell() {
|
||||||
echo
|
|
||||||
echo "This script will download and install the following binaries:"
|
|
||||||
echo " * ghcup - The Haskell toolchain installer"
|
|
||||||
echo " (for managing GHC/cabal versions)"
|
|
||||||
echo " * ghc - The Glasgow Haskell Compiler"
|
|
||||||
echo " * cabal - The Cabal build tool"
|
|
||||||
echo
|
|
||||||
if [ -z "${GHCUP_USE_XDG_DIRS}" ] ; then
|
|
||||||
echo "ghcup installs only into the following directory,"
|
|
||||||
echo "which can be removed anytime:"
|
|
||||||
echo " $GHCUP_INSTALL_BASE_PREFIX/.ghcup"
|
|
||||||
else
|
|
||||||
echo "ghcup installs into XDG directories as long as"
|
|
||||||
echo "'GHCUP_USE_XDG_DIRS' is set."
|
|
||||||
fi
|
|
||||||
echo
|
|
||||||
|
|
||||||
if [ -z "${BOOTSTRAP_HASKELL_NONINTERACTIVE}" ] ; then
|
|
||||||
printf "\\033[0;35m%s\\033[0m\\n" "Press ENTER to proceed or ctrl-c to abort."
|
|
||||||
printf "\\033[0;35m%s\\033[0m\\n" "Note that this script can be re-run at any given time."
|
|
||||||
echo
|
|
||||||
# Wait for user input to continue.
|
|
||||||
# shellcheck disable=SC2034
|
|
||||||
read -r answer </dev/tty
|
|
||||||
fi
|
|
||||||
|
|
||||||
edo mkdir -p "${GHCUP_BIN}"
|
|
||||||
|
|
||||||
if command -V "ghcup" >/dev/null 2>&1 ; then
|
|
||||||
if [ -z "${BOOTSTRAP_HASKELL_NO_UPGRADE}" ] ; then
|
|
||||||
_eghcup upgrade || download_ghcup
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
download_ghcup
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo
|
|
||||||
echo "$(ghcup tool-requirements)"
|
|
||||||
echo
|
|
||||||
|
|
||||||
if [ -z "${BOOTSTRAP_HASKELL_NONINTERACTIVE}" ] ; then
|
|
||||||
printf "\\033[0;35m%s\\033[0m\\n" "Press ENTER to proceed or ctrl-c to abort."
|
|
||||||
printf "\\033[0;35m%s\\033[0m\\n" "Installation may take a while."
|
|
||||||
echo
|
|
||||||
|
|
||||||
# Wait for user input to continue.
|
|
||||||
# shellcheck disable=SC2034
|
|
||||||
read -r answer </dev/tty
|
|
||||||
fi
|
|
||||||
|
|
||||||
eghcup --cache install ghc "${BOOTSTRAP_HASKELL_GHC_VERSION}"
|
|
||||||
|
|
||||||
eghcup set ghc "${BOOTSTRAP_HASKELL_GHC_VERSION}"
|
|
||||||
eghcup --cache install cabal "${BOOTSTRAP_HASKELL_CABAL_VERSION}"
|
|
||||||
|
|
||||||
edo cabal new-update
|
|
||||||
|
|
||||||
printf "\\033[0;35m%s\\033[0m\\n" ""
|
|
||||||
printf "\\033[0;35m%s\\033[0m\\n" "Installation done!"
|
|
||||||
printf "\\033[0;35m%s\\033[0m\\n" ""
|
|
||||||
|
|
||||||
|
|
||||||
if [ -z "${BOOTSTRAP_HASKELL_NONINTERACTIVE}" ] ; then
|
|
||||||
printf "\\033[0;35m%s\\033[0m\\n" "Do you want to install haskell-language-server (HLS) now?"
|
|
||||||
printf "\\033[0;35m%s\\033[0m\\n" "HLS is a language-server that provides IDE-like functionality"
|
|
||||||
printf "\\033[0;35m%s\\033[0m\\n" "and can integrate with different editors, such as Vim, Emacs, VS Code, Atom, ..."
|
|
||||||
printf "\\033[0;35m%s\\033[0m\\n" "Also see https://github.com/haskell/haskell-language-server/blob/master/README.md"
|
|
||||||
printf "\\033[0;35m%s\\033[0m\\n" ""
|
|
||||||
printf "\\033[0;35m%s\\033[0m\\n" "Answer with YES or NO and press ENTER."
|
|
||||||
printf "\\033[0;35m%s\\033[0m\\n" ""
|
|
||||||
|
|
||||||
while true; do
|
|
||||||
read -r hls_answer </dev/tty
|
|
||||||
|
|
||||||
case $hls_answer in
|
|
||||||
[Yy]*)
|
|
||||||
eghcup --cache install hls
|
|
||||||
break ;;
|
|
||||||
[Nn]*)
|
|
||||||
break ;;
|
|
||||||
*)
|
|
||||||
echo "Please type YES or NO and press enter.";;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
echo "In order to run ghc and cabal, you need to adjust your PATH variable."
|
|
||||||
echo "You may want to source '$GHCUP_DIR/env' in your shell"
|
|
||||||
echo "configuration to do so (e.g. ~/.bashrc)."
|
|
||||||
|
|
||||||
case $SHELL in
|
case $SHELL in
|
||||||
*/zsh) # login shell is zsh
|
*/zsh) # login shell is zsh
|
||||||
GHCUP_PROFILE_FILE="$HOME/.zshrc"
|
GHCUP_PROFILE_FILE="$HOME/.zshrc"
|
||||||
@@ -248,67 +261,392 @@ if [ -z "${BOOTSTRAP_HASKELL_NONINTERACTIVE}" ] ; then
|
|||||||
GHCUP_PROFILE_FILE="$HOME/.zshrc"
|
GHCUP_PROFILE_FILE="$HOME/.zshrc"
|
||||||
MY_SHELL="zsh"
|
MY_SHELL="zsh"
|
||||||
else
|
else
|
||||||
_done
|
return
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
*/fish) # login shell is fish
|
*/fish) # login shell is fish
|
||||||
GHCUP_PROFILE_FILE="$HOME/.config/fish/config.fish"
|
GHCUP_PROFILE_FILE="$HOME/.config/fish/config.fish"
|
||||||
MY_SHELL="fish" ;;
|
MY_SHELL="fish" ;;
|
||||||
*) _done ;;
|
*) return ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# Ask user if they want to adjust the bashrc.
|
||||||
|
ask_bashrc() {
|
||||||
|
if [ -n "${BOOTSTRAP_HASKELL_ADJUST_BASHRC}" ] ; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
if [ -z "${BOOTSTRAP_HASKELL_NONINTERACTIVE}" ] ; then
|
||||||
|
echo "-------------------------------------------------------------------------------"
|
||||||
|
|
||||||
|
warn ""
|
||||||
|
warn "Detected ${MY_SHELL} shell on your system..."
|
||||||
|
warn "Do you want ghcup to automatically add the required PATH variable to \"${GHCUP_PROFILE_FILE}\"?"
|
||||||
|
warn ""
|
||||||
|
warn "[P] Yes, prepend [A] Yes, append [N] No [?] Help (default is \"P\")."
|
||||||
|
warn ""
|
||||||
|
|
||||||
|
read -r bashrc_answer </dev/tty
|
||||||
|
else
|
||||||
|
# On windows .bashrc isn't an important user config, so we adjust it
|
||||||
|
# always. On other platforms, let's be a bit more conservative.
|
||||||
|
case "${plat}" in
|
||||||
|
MSYS*|MINGW*)
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
case $bashrc_answer in
|
||||||
|
[Pp]* | "")
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
[Aa]*)
|
||||||
|
return 2
|
||||||
|
;;
|
||||||
|
[Nn]*)
|
||||||
|
return 0;;
|
||||||
|
*)
|
||||||
|
echo "Possible choices are:"
|
||||||
|
echo
|
||||||
|
echo "P - Yes, prepend to PATH, taking precedence (default)"
|
||||||
|
echo "A - Yes, append to PATH"
|
||||||
|
echo "N - No, don't mess with my configuration"
|
||||||
|
echo
|
||||||
|
echo "Please make your choice and press ENTER."
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
unset bashrc_answer
|
||||||
|
}
|
||||||
|
|
||||||
|
# Needs 'find_shell' to be called beforehand.
|
||||||
|
adjust_bashrc() {
|
||||||
|
case $1 in
|
||||||
|
1)
|
||||||
|
cat <<-EOF > "${GHCUP_DIR}"/env || die "Failed to create env file"
|
||||||
|
export PATH="\$HOME/.cabal/bin:${GHCUP_BIN}:\$PATH"
|
||||||
|
EOF
|
||||||
|
;;
|
||||||
|
2)
|
||||||
|
cat <<-EOF > "${GHCUP_DIR}"/env || die "Failed to create env file"
|
||||||
|
export PATH="\$PATH:\$HOME/.cabal/bin:${GHCUP_BIN}"
|
||||||
|
EOF
|
||||||
|
;;
|
||||||
|
*) ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
case $1 in
|
||||||
|
1 | 2)
|
||||||
|
case $MY_SHELL in
|
||||||
|
"")
|
||||||
|
warn_path "Couldn't figure out login shell!"
|
||||||
|
return
|
||||||
|
;;
|
||||||
|
fish)
|
||||||
|
mkdir -p "${GHCUP_PROFILE_FILE%/*}"
|
||||||
|
sed -i -e '/# ghcup-env$/ s/^#*/#/' "${GHCUP_PROFILE_FILE}"
|
||||||
|
case $1 in
|
||||||
|
1)
|
||||||
|
echo "set -q GHCUP_INSTALL_BASE_PREFIX[1]; or set GHCUP_INSTALL_BASE_PREFIX \$HOME ; set -gx PATH \$HOME/.cabal/bin $GHCUP_BIN \$PATH # ghcup-env" >> "${GHCUP_PROFILE_FILE}"
|
||||||
|
;;
|
||||||
|
2)
|
||||||
|
echo "set -q GHCUP_INSTALL_BASE_PREFIX[1]; or set GHCUP_INSTALL_BASE_PREFIX \$HOME ; set -gx PATH \$HOME/.cabal/bin \$PATH $GHCUP_BIN # ghcup-env" >> "${GHCUP_PROFILE_FILE}"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
break ;;
|
||||||
|
bash)
|
||||||
|
sed -i -e '/# ghcup-env$/ s/^#*/#/' "${GHCUP_PROFILE_FILE}"
|
||||||
|
echo "[ -f \"${GHCUP_DIR}/env\" ] && source \"${GHCUP_DIR}/env\" # ghcup-env" >> "${GHCUP_PROFILE_FILE}"
|
||||||
|
case "${plat}" in
|
||||||
|
"Darwin"|"darwin")
|
||||||
|
if ! grep -q "ghcup-env" "${HOME}/.bash_profile" ; then
|
||||||
|
echo "[[ -f ~/.bashrc ]] && source ~/.bashrc # ghcup-env" >> "${HOME}/.bash_profile"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
break ;;
|
||||||
|
|
||||||
printf "\\033[0;35m%s\\033[0m\\n" ""
|
zsh)
|
||||||
printf "\\033[0;35m%s\\033[0m\\n" "Detected ${MY_SHELL} shell on your system..."
|
sed -i -e '/# ghcup-env$/ s/^#*/#/' "${GHCUP_PROFILE_FILE}"
|
||||||
printf "\\033[0;35m%s\\033[0m\\n" "If you want ghcup to automatically add the required PATH variable to \"${GHCUP_PROFILE_FILE}\""
|
echo "[ -f \"${GHCUP_DIR}/env\" ] && source \"${GHCUP_DIR}/env\" # ghcup-env" >> "${GHCUP_PROFILE_FILE}"
|
||||||
printf "\\033[0;35m%s\\033[0m\\n" "answer with YES, otherwise with NO and press ENTER."
|
break ;;
|
||||||
printf "\\033[0;35m%s\\033[0m\\n" ""
|
esac
|
||||||
|
echo
|
||||||
|
echo "==============================================================================="
|
||||||
|
echo
|
||||||
|
warn "OK! ${GHCUP_PROFILE_FILE} has been modified. Restart your terminal for the changes to take effect,"
|
||||||
|
warn "or type \"source ${GHCUP_DIR}/env\" to apply them in your current terminal session."
|
||||||
|
return
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
warn_path
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
while true; do
|
warn_path() {
|
||||||
read -r next_answer </dev/tty
|
echo
|
||||||
|
echo "==============================================================================="
|
||||||
|
echo
|
||||||
|
[ -n "$1" ] && warn "$1"
|
||||||
|
yellow "In order to run ghc and cabal, you need to adjust your PATH variable."
|
||||||
|
yellow "To do so, you may want run 'source $GHCUP_DIR/env' in your current terminal"
|
||||||
|
yellow "session as well as your shell configuration (e.g. ~/.bashrc)."
|
||||||
|
|
||||||
case $next_answer in
|
}
|
||||||
[Yy]*)
|
|
||||||
case $MY_SHELL in
|
adjust_cabal_config() {
|
||||||
"") break ;;
|
edo cabal user-config -a "extra-prog-path: $(cygpath -w "$GHCUP_BIN"), $(cygpath -w "$HOME"/AppData/Roaming/cabal/bin), $(cygpath -w "$GHCUP_MSYS2"/usr/bin), $(cygpath -w "$GHCUP_MSYS2"/mingw64/bin)" -a "extra-include-dirs: $(cygpath -w "$GHCUP_MSYS2"/mingw64/include)" -a "extra-lib-dirs: $(cygpath -w "$GHCUP_MSYS2"/mingw64/lib)" -f init
|
||||||
fish)
|
}
|
||||||
if ! grep -q "ghcup-env" "${GHCUP_PROFILE_FILE}" ; then
|
|
||||||
mkdir -p "${GHCUP_PROFILE_FILE%/*}"
|
ask_cabal_config_init() {
|
||||||
echo "# ghcup-env" >> "${GHCUP_PROFILE_FILE}"
|
case "${plat}" in
|
||||||
echo "set -q GHCUP_INSTALL_BASE_PREFIX[1]; or set GHCUP_INSTALL_BASE_PREFIX \$HOME" >> "${GHCUP_PROFILE_FILE}"
|
MSYS*|MINGW*)
|
||||||
echo "test -f $GHCUP_DIR/env ; and set -gx PATH \$HOME/.cabal/bin $GHCUP_BIN \$PATH" >> "${GHCUP_PROFILE_FILE}"
|
if [ -n "${BOOTSTRAP_HASKELL_ADJUST_CABAL_CONFIG}" ] ; then
|
||||||
fi
|
return 1
|
||||||
break ;;
|
fi
|
||||||
bash)
|
|
||||||
if ! grep -q "ghcup-env" "${GHCUP_PROFILE_FILE}" ; then
|
if [ -z "${BOOTSTRAP_HASKELL_NONINTERACTIVE}" ] ; then
|
||||||
echo "[ -f \"${GHCUP_DIR}/env\" ] && source \"${GHCUP_DIR}/env\" # ghcup-env" >> "${GHCUP_PROFILE_FILE}"
|
echo "-------------------------------------------------------------------------------"
|
||||||
fi
|
warn "Create an initial cabal.config including relevant msys2 paths (recommended)?"
|
||||||
case "$(uname -s)" in
|
warn "[Y] Yes [N] No [?] Help (default is \"Y\")."
|
||||||
"Darwin"|"darwin")
|
echo
|
||||||
if ! grep -q "ghcup-env" "${HOME}/.bash_profile" ; then
|
while true; do
|
||||||
echo "[[ -f ~/.bashrc ]] && source ~/.bashrc # ghcup-env" >> "${HOME}/.bash_profile"
|
read -r mingw_answer </dev/tty
|
||||||
fi
|
|
||||||
|
case $mingw_answer in
|
||||||
|
[Yy]* | "")
|
||||||
|
return 1 ;;
|
||||||
|
[Nn]*)
|
||||||
|
return 0 ;;
|
||||||
|
*)
|
||||||
|
echo "Possible choices are:"
|
||||||
|
echo
|
||||||
|
echo "Y - Yes, create a cabal.config with pre-set paths to msys2/mingw64 (default)"
|
||||||
|
echo "N - No, leave the current/default cabal config untouched"
|
||||||
|
echo
|
||||||
|
echo "Please make your choice and press ENTER."
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
break ;;
|
done
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
zsh)
|
unset mingw_answer
|
||||||
if ! grep -q "ghcup-env" "${GHCUP_PROFILE_FILE}" ; then
|
|
||||||
echo "[ -f \"${GHCUP_DIR}/env\" ] && source \"${GHCUP_DIR}/env\" # ghcup-env" >> "${GHCUP_PROFILE_FILE}"
|
return 0
|
||||||
fi
|
}
|
||||||
break ;;
|
|
||||||
esac
|
do_cabal_config_init() {
|
||||||
printf "\\033[0;35m%s\\033[0m\\n" "OK! ${GHCUP_PROFILE_FILE} has been modified. Restart your terminal for the changes to take effect,"
|
case "${plat}" in
|
||||||
printf "\\033[0;35m%s\\033[0m\\n" "or type \"source ${GHCUP_DIR}/env\" to apply them in your current terminal session."
|
MSYS*|MINGW*)
|
||||||
_done
|
case $1 in
|
||||||
;;
|
1)
|
||||||
[Nn]*)
|
adjust_cabal_config
|
||||||
_done ;;
|
;;
|
||||||
*)
|
0)
|
||||||
echo "Please type YES or NO and press enter.";;
|
echo "Make sure that your global cabal.config references the correct mingw64 paths (extra-prog-path, extra-include-dirs and extra-lib-dirs)."
|
||||||
esac
|
echo "And set the environment variable GHCUP_MSYS2 to the root path of your msys2 installation."
|
||||||
done
|
sleep 5
|
||||||
|
return ;;
|
||||||
|
*) ;;
|
||||||
|
esac
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
ask_hls() {
|
||||||
|
if [ -n "${BOOTSTRAP_HASKELL_INSTALL_HLS}" ] ; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "${BOOTSTRAP_HASKELL_NONINTERACTIVE}" ] ; then
|
||||||
|
echo "-------------------------------------------------------------------------------"
|
||||||
|
|
||||||
|
warn "Do you want to install haskell-language-server (HLS)?"
|
||||||
|
warn "HLS is a language-server that provides IDE-like functionality"
|
||||||
|
warn "and can integrate with different editors, such as Vim, Emacs, VS Code, Atom, ..."
|
||||||
|
warn "Also see https://github.com/haskell/haskell-language-server/blob/master/README.md"
|
||||||
|
warn ""
|
||||||
|
warn "[Y] Yes [N] No [?] Help (default is \"N\")."
|
||||||
|
warn ""
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
read -r hls_answer </dev/tty
|
||||||
|
|
||||||
|
case $hls_answer in
|
||||||
|
[Yy]*)
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
[Nn]* | "")
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Possible choices are:"
|
||||||
|
echo
|
||||||
|
echo "Y - Yes, install the haskell-langauge-server"
|
||||||
|
echo "N - No, don't install anything more (default)"
|
||||||
|
echo
|
||||||
|
echo "Please make your choice and press ENTER."
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
else
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
unset hls_answer
|
||||||
|
}
|
||||||
|
|
||||||
|
ask_stack() {
|
||||||
|
if [ -n "${BOOTSTRAP_HASKELL_INSTALL_STACK}" ] ; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "${BOOTSTRAP_HASKELL_NONINTERACTIVE}" ] ; then
|
||||||
|
echo "-------------------------------------------------------------------------------"
|
||||||
|
|
||||||
|
warn "Do you want to install stack?"
|
||||||
|
warn "Stack is a haskell build tool similar to cabal that is used by some projects."
|
||||||
|
warn "Also see https://docs.haskellstack.org/"
|
||||||
|
warn ""
|
||||||
|
warn "[Y] Yes [N] No [?] Help (default is \"N\")."
|
||||||
|
warn ""
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
read -r stack_answer </dev/tty
|
||||||
|
|
||||||
|
case $stack_answer in
|
||||||
|
[Yy]*)
|
||||||
|
return 1 ;;
|
||||||
|
[Nn]* | "")
|
||||||
|
return 0 ;;
|
||||||
|
*)
|
||||||
|
echo "Possible choices are:"
|
||||||
|
echo
|
||||||
|
echo "Y - Yes, install stack"
|
||||||
|
echo "N - No, don't install anything more (default)"
|
||||||
|
echo
|
||||||
|
echo "Please make your choice and press ENTER."
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
else
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
unset stack_answer
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
find_shell
|
||||||
|
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "Welcome to Haskell!"
|
||||||
|
echo
|
||||||
|
echo "This script will download and install the following binaries:"
|
||||||
|
echo " * ghcup - The Haskell toolchain installer"
|
||||||
|
echo " * ghc - The Glasgow Haskell Compiler"
|
||||||
|
echo " * cabal - The Cabal build tool for managing Haskell software"
|
||||||
|
echo " * stack - (optional) A cross-platform program for developing Haskell projects"
|
||||||
|
echo " * hls - (optional) A language server for developers to integrate with their editor/IDE"
|
||||||
|
echo
|
||||||
|
if [ -z "${GHCUP_USE_XDG_DIRS}" ] ; then
|
||||||
|
echo "ghcup installs only into the following directory,"
|
||||||
|
echo "which can be removed anytime:"
|
||||||
|
case "${plat}" in
|
||||||
|
MSYS*|MINGW*)
|
||||||
|
echo " $(cygpath -w "$GHCUP_DIR")"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo " $GHCUP_DIR"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
else
|
||||||
|
echo "ghcup installs into XDG directories as long as"
|
||||||
|
echo "'GHCUP_USE_XDG_DIRS' is set."
|
||||||
fi
|
fi
|
||||||
|
echo
|
||||||
|
|
||||||
|
if [ -z "${BOOTSTRAP_HASKELL_NONINTERACTIVE}" ] ; then
|
||||||
|
warn "Press ENTER to proceed or ctrl-c to abort."
|
||||||
|
warn "Note that this script can be re-run at any given time."
|
||||||
|
# Wait for user input to continue.
|
||||||
|
# shellcheck disable=SC2034
|
||||||
|
read -r answer </dev/tty
|
||||||
|
fi
|
||||||
|
|
||||||
|
ask_bashrc
|
||||||
|
ask_bashrc_answer=$?
|
||||||
|
ask_cabal_config_init
|
||||||
|
ask_cabal_config_init_answer=$?
|
||||||
|
ask_hls
|
||||||
|
ask_hls_answer=$?
|
||||||
|
ask_stack
|
||||||
|
ask_stack_answer=$?
|
||||||
|
|
||||||
|
edo mkdir -p "${GHCUP_BIN}"
|
||||||
|
|
||||||
|
if command -V "ghcup" >/dev/null 2>&1 ; then
|
||||||
|
if [ -z "${BOOTSTRAP_HASKELL_NO_UPGRADE}" ] ; then
|
||||||
|
_eghcup upgrade || download_ghcup
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
download_ghcup
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "$(if [ -n "${BOOTSTRAP_HASKELL_YAML}" ] ; then ghcup -s "${BOOTSTRAP_HASKELL_YAML}" tool-requirements ; else ghcup tool-requirements ; fi)"
|
||||||
|
echo
|
||||||
|
|
||||||
|
if [ -z "${BOOTSTRAP_HASKELL_NONINTERACTIVE}" ] ; then
|
||||||
|
warn "Press ENTER to proceed or ctrl-c to abort."
|
||||||
|
warn "Installation may take a while."
|
||||||
|
echo
|
||||||
|
|
||||||
|
# Wait for user input to continue.
|
||||||
|
# shellcheck disable=SC2034
|
||||||
|
read -r answer </dev/tty
|
||||||
|
fi
|
||||||
|
|
||||||
|
eghcup --cache install ghc "${BOOTSTRAP_HASKELL_GHC_VERSION}"
|
||||||
|
|
||||||
|
eghcup set ghc "${BOOTSTRAP_HASKELL_GHC_VERSION}"
|
||||||
|
eghcup --cache install cabal "${BOOTSTRAP_HASKELL_CABAL_VERSION}"
|
||||||
|
|
||||||
|
do_cabal_config_init $ask_cabal_config_init_answer
|
||||||
|
|
||||||
|
edo cabal new-update
|
||||||
|
|
||||||
|
case $ask_hls_answer in
|
||||||
|
1)
|
||||||
|
_eghcup --cache install hls || warn "HLS installation failed, continuing anyway"
|
||||||
|
;;
|
||||||
|
*) ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
case $ask_stack_answer in
|
||||||
|
1)
|
||||||
|
_eghcup --cache install stack || warn "Stack installation failed, continuing anyway"
|
||||||
|
;;
|
||||||
|
*) ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
|
||||||
|
adjust_bashrc $ask_bashrc_answer
|
||||||
|
|
||||||
|
|
||||||
|
_done
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# vim: tabstop=4 shiftwidth=4 expandtab
|
# vim: tabstop=4 shiftwidth=4 expandtab
|
||||||
|
|||||||
548
bootstrap-haskell.ps1
Normal file
548
bootstrap-haskell.ps1
Normal file
@@ -0,0 +1,548 @@
|
|||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Script to bootstrap a Haskell environment
|
||||||
|
|
||||||
|
.DESCRIPTION
|
||||||
|
This is the windows GHCup installer, installing:
|
||||||
|
|
||||||
|
* ghcup - The Haskell toolchain installer"
|
||||||
|
* ghc - The Glasgow Haskell Compiler"
|
||||||
|
* msys2 - Unix-style toolchain needed for dependencies and tools
|
||||||
|
* cabal - The Cabal build tool for managing Haskell software"
|
||||||
|
* stack - (optional) A cross-platform program for developing Haskell projects"
|
||||||
|
* hls - (optional) A language server for developers to integrate with their editor/IDE"
|
||||||
|
#>
|
||||||
|
param (
|
||||||
|
# Run an interactive installation
|
||||||
|
[switch]$Interactive,
|
||||||
|
# Specify the install root (default: 'C:\')
|
||||||
|
[string]$InstallDir,
|
||||||
|
# Instead of installing a new MSys2, use an existing installation
|
||||||
|
[string]$ExistingMsys2Dir,
|
||||||
|
# Specify the cabal root directory (default: '$InstallDir\cabal')
|
||||||
|
[string]$CabalDir,
|
||||||
|
# Overwrite (or rather backup) a previous install
|
||||||
|
[switch]$Overwrite,
|
||||||
|
# Specify the bootstrap url (default: 'https://www.haskell.org/ghcup/sh/bootstrap-haskell')
|
||||||
|
[string]$BootstrapUrl,
|
||||||
|
# Run the final bootstrap script via 'bash' instead of a full newly spawned msys2 shell
|
||||||
|
[switch]$InBash,
|
||||||
|
# Whether to install stack as well
|
||||||
|
[switch]$InstallStack,
|
||||||
|
# Whether to install hls as well
|
||||||
|
[switch]$InstallHLS,
|
||||||
|
# Skip adjusting cabal.config with mingw paths
|
||||||
|
[switch]$NoAdjustCabalConfig
|
||||||
|
)
|
||||||
|
|
||||||
|
$Silent = !$Interactive
|
||||||
|
|
||||||
|
function Print-Msg {
|
||||||
|
param ( [Parameter(Mandatory=$true, HelpMessage='String to output')][string]$msg, [string]$color = "Green" )
|
||||||
|
Write-Host ('{0}' -f $msg) -ForegroundColor $color
|
||||||
|
}
|
||||||
|
|
||||||
|
function Create-Shortcut {
|
||||||
|
param ( [Parameter(Mandatory=$true,HelpMessage='Target path')][string]$SourceExe, [Parameter(Mandatory=$true,HelpMessage='Arguments to the path/exe')][AllowEmptyString()]$ArgumentsToSourceExe, [Parameter(Mandatory=$true,HelpMessage='The destination of the desktop link')][string]$DestinationPath )
|
||||||
|
$WshShell = New-Object -comObject WScript.Shell
|
||||||
|
$Shortcut = $WshShell.CreateShortcut($DestinationPath)
|
||||||
|
$Shortcut.TargetPath = $SourceExe
|
||||||
|
if($ArgumentsToSourceExe) {
|
||||||
|
$Shortcut.Arguments = $ArgumentsToSourceExe
|
||||||
|
}
|
||||||
|
$Shortcut.Save()
|
||||||
|
}
|
||||||
|
|
||||||
|
function Add-EnvPath {
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory=$true,HelpMessage='The Path to add to Users environment')]
|
||||||
|
[string] $Path,
|
||||||
|
|
||||||
|
[ValidateSet('Machine', 'User', 'Session')]
|
||||||
|
[string] $Container = 'Session'
|
||||||
|
)
|
||||||
|
|
||||||
|
if ($Container -eq 'Session') {
|
||||||
|
$envPaths = [Collections.Generic.List[String]]($env:Path -split ([IO.Path]::PathSeparator))
|
||||||
|
if ($envPaths -notcontains $Path) {
|
||||||
|
$envPaths.Add($Path)
|
||||||
|
$env:PATH = $envPaths -join ([IO.Path]::PathSeparator)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
[Microsoft.Win32.RegistryHive]$hive, $keyPath = switch ($Container) {
|
||||||
|
'Machine' { 'LocalMachine', 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment' }
|
||||||
|
'User' { 'CurrentUser', 'Environment' }
|
||||||
|
}
|
||||||
|
|
||||||
|
$hiveKey = $envKey = $null
|
||||||
|
try {
|
||||||
|
$hiveKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($hive, '')
|
||||||
|
$envKey = $hiveKey.OpenSubKey($keyPath, $true)
|
||||||
|
$rawPath = $envKey.GetValue('PATH', '', 'DoNotExpandEnvironmentNames')
|
||||||
|
|
||||||
|
$envPaths = [Collections.Generic.List[String]]($rawPath -split ([IO.Path]::PathSeparator))
|
||||||
|
if ($envPaths -notcontains $Path) {
|
||||||
|
$envPaths.Add($Path)
|
||||||
|
$envKey.SetValue('PATH', ($envPaths -join ([IO.Path]::PathSeparator)), 'ExpandString')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
if ($envKey) { $envKey.Close() }
|
||||||
|
if ($hiveKey) { $hiveKey.Close() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
filter Get-FileSize {
|
||||||
|
'{0:N2} {1}' -f $(
|
||||||
|
if ($_ -lt 1kb) { $_, 'Bytes' }
|
||||||
|
elseif ($_ -lt 1mb) { ($_/1kb), 'KB' }
|
||||||
|
elseif ($_ -lt 1gb) { ($_/1mb), 'MB' }
|
||||||
|
elseif ($_ -lt 1tb) { ($_/1gb), 'GB' }
|
||||||
|
elseif ($_ -lt 1pb) { ($_/1tb), 'TB' }
|
||||||
|
else { ($_/1pb), 'PB' }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-FileWCSynchronous{
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[string]$url,
|
||||||
|
[string]$destinationFolder="$env:USERPROFILE\Downloads",
|
||||||
|
[switch]$includeStats
|
||||||
|
)
|
||||||
|
$wc = New-Object -TypeName Net.WebClient
|
||||||
|
$wc.UseDefaultCredentials = $true
|
||||||
|
$destination = Join-Path -Path $destinationFolder -ChildPath ($url | Split-Path -Leaf)
|
||||||
|
$start = Get-Date
|
||||||
|
$wc.DownloadFile($url, $destination)
|
||||||
|
$elapsed = ((Get-Date) - $start).ToString('hh\:mm\:ss')
|
||||||
|
$totalSize = (Get-Item -Path $destination).Length | Get-FileSize
|
||||||
|
if ($includeStats.IsPresent){
|
||||||
|
[PSCustomObject]@{Name=$MyInvocation.MyCommand;TotalSize=$totalSize;Time=$elapsed}
|
||||||
|
}
|
||||||
|
Get-Item -Path $destination | Unblock-File
|
||||||
|
}
|
||||||
|
|
||||||
|
function Test-AbsolutePath {
|
||||||
|
Param (
|
||||||
|
[Parameter(Mandatory=$True)]
|
||||||
|
[ValidateScript({[System.IO.Path]::IsPathRooted($_)})]
|
||||||
|
[String]$Path
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function Exec
|
||||||
|
{
|
||||||
|
[CmdletBinding()]
|
||||||
|
param(
|
||||||
|
[Parameter(Position = 0, Mandatory = 1)][string]$cmd,
|
||||||
|
[Parameter()][string]$errorMessage,
|
||||||
|
[parameter(ValueFromRemainingArguments = $true)]
|
||||||
|
[string[]]$Passthrough
|
||||||
|
)
|
||||||
|
& $cmd @Passthrough
|
||||||
|
if ($lastexitcode -ne 0) {
|
||||||
|
if (!($errorMessage)) {
|
||||||
|
throw ('Exec: Error executing command {0} with arguments ''{1}''' -f $cmd, "$Passthrough")
|
||||||
|
} else {
|
||||||
|
throw ('Exec: ' + $errorMessage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$ErrorActionPreference = 'Stop'
|
||||||
|
|
||||||
|
$GhcupBasePrefixEnv = [System.Environment]::GetEnvironmentVariable('GHCUP_INSTALL_BASE_PREFIX', 'user')
|
||||||
|
|
||||||
|
if ($GhcupBasePrefixEnv) {
|
||||||
|
$defaultGhcupBasePrefix = $GhcupBasePrefixEnv
|
||||||
|
} else {
|
||||||
|
$partitions = Get-CimInstance win32_logicaldisk
|
||||||
|
$defaultGhcupBasePrefix = $null
|
||||||
|
foreach ($p in $partitions){
|
||||||
|
try {
|
||||||
|
if ($p."FreeSpace" -lt 5368709120) { # at least 5 GB are needed
|
||||||
|
throw ("Not enough free space on {0}" -f $p."DeviceId")
|
||||||
|
}
|
||||||
|
$null = New-Item -Path ('{0}\' -f $p."DeviceId") -Name "ghcup.test" -ItemType "directory" -Force
|
||||||
|
$defaultGhcupBasePrefix = ('{0}\' -f $p."DeviceId")
|
||||||
|
Remove-Item -LiteralPath ('{0}\ghcup.test' -f $p."DeviceId")
|
||||||
|
break
|
||||||
|
} catch {
|
||||||
|
Print-Msg -color Yellow -msg ("{0} not writable or not enough disk space, trying next device" -f $p."DeviceId")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($defaultGhcupBasePrefix) {
|
||||||
|
Print-Msg -color Green -msg ("Picked {0} as default Install prefix!" -f $defaultGhcupBasePrefix)
|
||||||
|
} else {
|
||||||
|
Print-Msg -color Red -msg "Couldn't find a writable partition with at least 5GB free disk space!"
|
||||||
|
Exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# ask for base install prefix
|
||||||
|
if ($Silent -and !($InstallDir)) {
|
||||||
|
$GhcupBasePrefix = $defaultGhcupBasePrefix
|
||||||
|
} elseif ($InstallDir) {
|
||||||
|
if (!(Test-Path -LiteralPath ('{0}' -f $InstallDir) -IsValid)) {
|
||||||
|
Print-Msg -color Red -msg "Not a valid directory!"
|
||||||
|
Exit 1
|
||||||
|
} elseif (!(Split-Path -IsAbsolute -Path "$InstallDir")) {
|
||||||
|
Print-Msg -color Red -msg "Non-absolute Path specified!"
|
||||||
|
Exit 1
|
||||||
|
} else {
|
||||||
|
$GhcupBasePrefix = $InstallDir
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
while ($true) {
|
||||||
|
Print-Msg -color Magenta -msg ('Where to install to (this should be a short Path, preferably a Drive like ''C:\''){1}Press enter to accept the default [{0}]:' -f $defaultGhcupBasePrefix, "`n")
|
||||||
|
$basePrefixPrompt = Read-Host
|
||||||
|
$GhcupBasePrefix = ($defaultGhcupBasePrefix,$basePrefixPrompt)[[bool]$basePrefixPrompt]
|
||||||
|
if (!($GhcupBasePrefix.EndsWith('\'))) {
|
||||||
|
$GhcupBasePrefix = ('{0}\' -f $GhcupBasePrefix)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!($GhcupBasePrefix)) {
|
||||||
|
Print-Msg -color Red -msg "No directory specified!"
|
||||||
|
} elseif (!(Test-Path -LiteralPath ('{0}' -f $GhcupBasePrefix))) {
|
||||||
|
Print-Msg -color Red -msg "Directory does not exist, need to specify an existing Drive/Directory"
|
||||||
|
} elseif (!(Split-Path -IsAbsolute -Path "$GhcupBasePrefix")) {
|
||||||
|
Print-Msg -color Red -msg "Invalid/Non-absolute Path specified"
|
||||||
|
} else {
|
||||||
|
Break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Print-Msg -msg ('Setting env variable GHCUP_INSTALL_BASE_PREFIX to ''{0}''' -f $GhcupBasePrefix)
|
||||||
|
$null = [Environment]::SetEnvironmentVariable("GHCUP_INSTALL_BASE_PREFIX", $GhcupBasePrefix, [System.EnvironmentVariableTarget]::User)
|
||||||
|
|
||||||
|
|
||||||
|
$GhcupDir = ('{0}\ghcup' -f $GhcupBasePrefix)
|
||||||
|
$MsysDir = ('{0}\msys64' -f $GhcupDir)
|
||||||
|
$Bash = ('{0}\usr\bin\bash' -f $MsysDir)
|
||||||
|
if (!($BootstrapUrl)) {
|
||||||
|
$BootstrapUrl = 'https://www.haskell.org/ghcup/sh/bootstrap-haskell'
|
||||||
|
}
|
||||||
|
$GhcupMsys2 = [System.Environment]::GetEnvironmentVariable('GHCUP_MSYS2', 'user')
|
||||||
|
|
||||||
|
Print-Msg -msg 'Preparing for GHCup installation...'
|
||||||
|
|
||||||
|
# ask what to do in case ghcup is already installed
|
||||||
|
if (Test-Path -LiteralPath ('{0}' -f $GhcupDir)) {
|
||||||
|
Print-Msg -msg ('GHCup already installed at ''{0}''...' -f $GhcupDir)
|
||||||
|
if ($Overwrite) {
|
||||||
|
$decision = 0
|
||||||
|
} elseif (!($Silent)) {
|
||||||
|
$decision = $Host.UI.PromptForChoice('Install GHCup'
|
||||||
|
, 'GHCup is already installed, what do you want to do?'
|
||||||
|
, [System.Management.Automation.Host.ChoiceDescription[]] @('&Reinstall'
|
||||||
|
'&Continue'
|
||||||
|
'&Abort'), 1)
|
||||||
|
} else {
|
||||||
|
$decision = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($decision -eq 0) {
|
||||||
|
$suffix = [IO.Path]::GetRandomFileName()
|
||||||
|
Print-Msg -msg ('Backing up {0} to {0}-{1} ...' -f $GhcupDir, $suffix)
|
||||||
|
Rename-Item -Path ('{0}' -f $GhcupDir) -NewName ('{0}-{1}' -f $GhcupDir, $suffix)
|
||||||
|
} elseif ($decision -eq 1) {
|
||||||
|
Print-Msg -msg 'Continuing installation...'
|
||||||
|
} elseif ($decision -eq 2) {
|
||||||
|
Exit 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$null = New-Item -Path ('{0}' -f $GhcupDir) -ItemType 'directory' -ErrorAction SilentlyContinue
|
||||||
|
$null = New-Item -Path ('{0}' -f $GhcupDir) -Name 'bin' -ItemType 'directory' -ErrorAction SilentlyContinue
|
||||||
|
|
||||||
|
# ask for cabal dir destination
|
||||||
|
if ($CabalDir) {
|
||||||
|
$CabDirEnv = $CabalDir
|
||||||
|
if (!($CabDirEnv)) {
|
||||||
|
Print-Msg -color Red -msg "No directory specified!"
|
||||||
|
Exit 1
|
||||||
|
} elseif (!(Split-Path -IsAbsolute -Path "$CabDirEnv")) {
|
||||||
|
Print-Msg -color Red -msg "Invalid/Non-absolute Path specified"
|
||||||
|
Exit 1
|
||||||
|
}
|
||||||
|
} elseif (!($Silent)) {
|
||||||
|
while ($true) {
|
||||||
|
|
||||||
|
$defaultCabalDir = ('{0}\cabal' -f $GhcupBasePrefix)
|
||||||
|
Print-Msg -color Magenta -msg ('Specify Cabal directory (this is where haskell packages end up){1}Press enter to accept the default [{0}]:' -f $defaultCabalDir, "`n")
|
||||||
|
$CabalDirPrompt = Read-Host
|
||||||
|
$CabDirEnv = ($defaultCabalDir,$CabalDirPrompt)[[bool]$CabalDirPrompt]
|
||||||
|
|
||||||
|
if (!($CabDirEnv)) {
|
||||||
|
Print-Msg -color Red -msg "No directory specified!"
|
||||||
|
} elseif (!(Split-Path -IsAbsolute -Path "$CabDirEnv")) {
|
||||||
|
Print-Msg -color Red -msg "Invalid/Non-absolute Path specified"
|
||||||
|
} else {
|
||||||
|
Break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$CabDirEnv = ('{0}\cabal' -f $GhcupBasePrefix)
|
||||||
|
}
|
||||||
|
|
||||||
|
# ask whether to install HLS
|
||||||
|
if (!($InstallHLS)) {
|
||||||
|
if (!($Silent)) {
|
||||||
|
$HLSdecision = $Host.UI.PromptForChoice('Install HLS'
|
||||||
|
, 'Do you want to install the haskell-language-server (HLS) for development purposes as well?'
|
||||||
|
, [System.Management.Automation.Host.ChoiceDescription[]] @('&Yes'
|
||||||
|
'&No'
|
||||||
|
'&Abort'), 1)
|
||||||
|
|
||||||
|
if ($HLSdecision -eq 0) {
|
||||||
|
$InstallHLS = $true
|
||||||
|
} elseif ($HLSdecision -eq 2) {
|
||||||
|
Exit 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# ask whether to install stack
|
||||||
|
if (!($InstallStack)) {
|
||||||
|
if (!($Silent)) {
|
||||||
|
$StackDecision = $Host.UI.PromptForChoice('Install stack'
|
||||||
|
, 'Do you want to install stack as well?'
|
||||||
|
, [System.Management.Automation.Host.ChoiceDescription[]] @('&Yes'
|
||||||
|
'&No'
|
||||||
|
'&Abort'), 1)
|
||||||
|
|
||||||
|
if ($StackDecision -eq 0) {
|
||||||
|
$InstallStack = $true
|
||||||
|
} elseif ($StackDecision -eq 2) {
|
||||||
|
Exit 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# mingw foo
|
||||||
|
Print-Msg -msg 'First checking for Msys2...'
|
||||||
|
if (!(Test-Path -Path ('{0}' -f $MsysDir))) {
|
||||||
|
if ($Silent) {
|
||||||
|
$msys2Decision = 0
|
||||||
|
} else {
|
||||||
|
$msys2Decision = $Host.UI.PromptForChoice('Install MSys2'
|
||||||
|
, 'Do you want GHCup to install a default MSys2 toolchain (recommended)?'
|
||||||
|
, [System.Management.Automation.Host.ChoiceDescription[]] @('&Yes'
|
||||||
|
'&No'), 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($msys2Decision -eq 0) {
|
||||||
|
Print-Msg -msg ('...Msys2 doesn''t exist, installing into {0}' -f $MsysDir)
|
||||||
|
|
||||||
|
Print-Msg -msg 'Starting installation in 5 seconds, this may take a while...'
|
||||||
|
Start-Sleep -s 5
|
||||||
|
|
||||||
|
# Download the archive
|
||||||
|
Print-Msg -msg 'Downloading Msys2 archive...'
|
||||||
|
$archive = 'msys2-x86_64-latest.sfx.exe'
|
||||||
|
|
||||||
|
if (Get-Command -Name 'curl.exe' -ErrorAction SilentlyContinue) {
|
||||||
|
Exec "curl.exe" '-o' ('{0}\{1}' -f $env:TEMP, $archive) ('https://repo.msys2.org/distrib/{0}' -f $archive)
|
||||||
|
} else {
|
||||||
|
Get-FileWCSynchronous -url ('https://repo.msys2.org/distrib/{0}' -f $archive) -destinationFolder "$env:TEMP" -includeStats
|
||||||
|
}
|
||||||
|
|
||||||
|
Print-Msg -msg 'Extracting Msys2 archive...'
|
||||||
|
$null = & "$env:TEMP\$archive" '-y' ('-o{0}' -f $GhcupDir) # Extract
|
||||||
|
Remove-Item -Path ('{0}/{1}' -f $env:TEMP, $archive)
|
||||||
|
|
||||||
|
Print-Msg -msg 'Processing MSYS2 bash for first time use...'
|
||||||
|
Exec "$Bash" '-lc' 'exit'
|
||||||
|
|
||||||
|
Exec "$env:windir\system32\taskkill.exe" /F /FI `"MODULES eq msys-2.0.dll`"
|
||||||
|
|
||||||
|
Print-Msg -msg 'Upgrading full system...'
|
||||||
|
Exec "$Bash" '-lc' 'pacman --noconfirm -Syuu'
|
||||||
|
|
||||||
|
Print-Msg -msg 'Upgrading full system twice...'
|
||||||
|
Exec "$Bash" '-lc' 'pacman --noconfirm -Syuu'
|
||||||
|
|
||||||
|
Print-Msg -msg 'Installing Dependencies...'
|
||||||
|
Exec "$Bash" '-lc' 'pacman --noconfirm -S --needed curl mingw-w64-x86_64-pkgconf'
|
||||||
|
|
||||||
|
Print-Msg -msg 'Updating SSL root certificate authorities...'
|
||||||
|
Exec "$Bash" '-lc' 'pacman --noconfirm -S ca-certificates'
|
||||||
|
|
||||||
|
Print-Msg -msg 'Setting default home directory...'
|
||||||
|
Exec "$Bash" '-lc' "sed -i -e 's/db_home:.*$/db_home: windows/' /etc/nsswitch.conf"
|
||||||
|
} elseif ($msys2Decision -eq 1) {
|
||||||
|
Print-Msg -color Yellow -msg 'Skipping MSys2 installation.'
|
||||||
|
while ($true) {
|
||||||
|
if ($GhcupMsys2) {
|
||||||
|
$defaultMsys2Dir = $GhcupMsys2
|
||||||
|
Print-Msg -color Magenta -msg ('Input existing MSys2 toolchain directory.{1}Press enter to accept the default [{0}]:' -f $defaultMsys2Dir, "`n")
|
||||||
|
$MsysDirPrompt = Read-Host
|
||||||
|
$MsysDir = ($defaultMsys2Dir,$MsysDirPrompt)[[bool]$MsysDirPrompt]
|
||||||
|
} else {
|
||||||
|
Print-Msg -color Magenta -msg 'Input existing MSys2 toolchain directory:'
|
||||||
|
$MsysDir = Read-Host
|
||||||
|
}
|
||||||
|
if (!($MsysDir)) {
|
||||||
|
Print-Msg -color Red -msg "No directory specified!"
|
||||||
|
} elseif (!(Test-Path -LiteralPath ('{0}' -f $MsysDir))) {
|
||||||
|
Print-Msg -color Red -msg ('MSys2 installation at ''{0}'' could not be found!' -f $MsysDir)
|
||||||
|
} elseif (!(Split-Path -IsAbsolute -Path "$MsysDir")) {
|
||||||
|
Print-Msg -color Red -msg "Invalid/Non-absolute Path specified"
|
||||||
|
} else {
|
||||||
|
Break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Print-Msg -msg ('Setting GHCUP_MSYS2 env var to ''{0}''' -f $MsysDir)
|
||||||
|
$null = [Environment]::SetEnvironmentVariable("GHCUP_MSYS2", $MsysDir, [System.EnvironmentVariableTarget]::User)
|
||||||
|
$Bash = ('{0}\usr\bin\bash' -f $MsysDir)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Print-Msg -msg ('...Msys2 found in {0} ...skipping Msys2 installation.' -f $MsysDir)
|
||||||
|
|
||||||
|
Print-Msg -msg 'Starting installation in 5 seconds, this may take a while...'
|
||||||
|
Start-Sleep -s 5
|
||||||
|
}
|
||||||
|
|
||||||
|
Print-Msg -msg 'Creating shortcuts...'
|
||||||
|
$uninstallShortCut = @'
|
||||||
|
$decision = $Host.UI.PromptForChoice('Uninstall Haskell'
|
||||||
|
, 'Do you want to uninstall all of the haskell toolchain, including GHC, Cabal, Stack and GHCup itself?'
|
||||||
|
, [System.Management.Automation.Host.ChoiceDescription[]] @('&Uninstall'
|
||||||
|
'&Abort'), 0)
|
||||||
|
|
||||||
|
if ($decision -eq 1) {
|
||||||
|
Exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host 'Removing ghcup toolchain' -ForegroundColor Green
|
||||||
|
ghcup nuke
|
||||||
|
|
||||||
|
Write-Host 'Unsetting GHCUP_INSTALL_BASE_PREFIX' -ForegroundColor Green
|
||||||
|
[Environment]::SetEnvironmentVariable('GHCUP_INSTALL_BASE_PREFIX', $null, [System.EnvironmentVariableTarget]::User)
|
||||||
|
|
||||||
|
$ghcupMsys2 = [System.Environment]::GetEnvironmentVariable('GHCUP_MSYS2', 'user')
|
||||||
|
$GhcupBasePrefixEnv = [System.Environment]::GetEnvironmentVariable('GHCUP_INSTALL_BASE_PREFIX', 'user')
|
||||||
|
|
||||||
|
if ($ghcupMsys2) {
|
||||||
|
$msys2Dir = [IO.Path]::GetFullPath($ghcupMsys2)
|
||||||
|
$baseDir = [IO.Path]::GetFullPath('{0}\ghcup' -f $GhcupBasePrefixEnv)
|
||||||
|
|
||||||
|
if ($msys2Dir.StartsWith($baseDir)) {
|
||||||
|
Write-Host 'Unsetting GHCUP_MSYS2' -ForegroundColor Green
|
||||||
|
[Environment]::SetEnvironmentVariable('GHCUP_MSYS2', $null, [System.EnvironmentVariableTarget]::User)
|
||||||
|
} else {
|
||||||
|
Write-Host ('GHCUP_MSYS2 env variable is set to a non-standard location {0}. Environment variable not unset. Uninstall manually.' -f $msys2Dir) -ForegroundColor Magenta
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Write-Host 'Unsetting GHCUP_MSYS2' -ForegroundColor Green
|
||||||
|
[Environment]::SetEnvironmentVariable('GHCUP_MSYS2', $null, [System.EnvironmentVariableTarget]::User)
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host 'Removing ghcup from PATH env var' -ForegroundColor Green
|
||||||
|
$path = [System.Environment]::GetEnvironmentVariable(
|
||||||
|
'PATH',
|
||||||
|
'user'
|
||||||
|
)
|
||||||
|
$path = ($path.Split(';') | Where-Object { $_ -ne ('{0}\bin' -f $baseDir) }) -join ';'
|
||||||
|
[System.Environment]::SetEnvironmentVariable(
|
||||||
|
'PATH',
|
||||||
|
$path,
|
||||||
|
'user'
|
||||||
|
)
|
||||||
|
|
||||||
|
Write-Host 'Removing desktop files' -ForegroundColor Green
|
||||||
|
$DesktopDir = [Environment]::GetFolderPath("Desktop")
|
||||||
|
Remove-Item -LiteralPath ('{0}\Install GHC dev dependencies.lnk' -f $DesktopDir) -Force
|
||||||
|
Remove-Item -LiteralPath ('{0}\Mingw haskell shell.lnk' -f $DesktopDir) -Force
|
||||||
|
Remove-Item -LiteralPath ('{0}\Mingw package management docs.url' -f $DesktopDir) -Force
|
||||||
|
|
||||||
|
Write-Host ('CABAL_DIR env variable is still set to {0} and will be used by cabal regardless of ghcup. You may want to uninstall this manually.' -f [System.Environment]::GetEnvironmentVariable('CABAL_DIR', 'user')) -ForegroundColor Magenta
|
||||||
|
Write-Host 'You may remove this script now.' -ForegroundColor Magenta
|
||||||
|
|
||||||
|
if ($Host.Name -eq "ConsoleHost")
|
||||||
|
{
|
||||||
|
Write-Host "Press any key to continue..."
|
||||||
|
$Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyUp") > $null
|
||||||
|
}
|
||||||
|
'@
|
||||||
|
|
||||||
|
$DesktopDir = [Environment]::GetFolderPath("Desktop")
|
||||||
|
$GhcInstArgs = '-mingw64 -mintty -c "pacman --noconfirm -S --needed base-devel gettext autoconf make libtool automake python p7zip patch unzip"'
|
||||||
|
Create-Shortcut -SourceExe ('{0}\msys2_shell.cmd' -f $MsysDir) -ArgumentsToSourceExe $GhcInstArgs -DestinationPath ('{0}\Install GHC dev dependencies.lnk' -f $DesktopDir)
|
||||||
|
Create-Shortcut -SourceExe ('{0}\msys2_shell.cmd' -f $MsysDir) -ArgumentsToSourceExe '-mingw64' -DestinationPath ('{0}\Mingw haskell shell.lnk' -f $DesktopDir)
|
||||||
|
Create-Shortcut -SourceExe 'https://www.msys2.org/docs/package-management' -ArgumentsToSourceExe '' -DestinationPath ('{0}\Mingw package management docs.url' -f $DesktopDir)
|
||||||
|
$null = New-Item -Path $DesktopDir -Name "Uninstall Haskell.ps1" -ItemType "file" -Force -Value $uninstallShortCut
|
||||||
|
|
||||||
|
Print-Msg -msg ('Adding {0}\bin to Users Path...' -f $GhcupDir)
|
||||||
|
Add-EnvPath -Path ('{0}\bin' -f ([System.IO.Path]::GetFullPath("$GhcupDir"))) -Container 'User'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$CabalDirFull = [System.IO.Path]::GetFullPath("$CabDirEnv")
|
||||||
|
Print-Msg -msg ('Setting CABAL_DIR to ''{0}''' -f $CabalDirFull)
|
||||||
|
$null = [Environment]::SetEnvironmentVariable("CABAL_DIR", $CabalDirFull, [System.EnvironmentVariableTarget]::User)
|
||||||
|
|
||||||
|
Print-Msg -msg 'Starting GHCup installer...'
|
||||||
|
|
||||||
|
$Msys2Shell = ('{0}\msys2_shell.cmd' -f $MsysDir)
|
||||||
|
|
||||||
|
# The bootstrap script is always silent, since we ask relevant questions here
|
||||||
|
$SilentExport = 'export BOOTSTRAP_HASKELL_NONINTERACTIVE=1 ;'
|
||||||
|
|
||||||
|
if ($InstallStack) {
|
||||||
|
$StackInstallExport = 'export BOOTSTRAP_HASKELL_INSTALL_STACK=1 ;'
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($InstallHLS) {
|
||||||
|
$HLSInstallExport = 'export BOOTSTRAP_HASKELL_INSTALL_HLS=1 ;'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!($NoAdjustCabalConfig)) {
|
||||||
|
$AdjustCabalConfigExport = 'export BOOTSTRAP_HASKELL_ADJUST_CABAL_CONFIG=1 ;'
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((Get-Process -ID $PID).ProcessName.StartsWith("bootstrap-haskell") -Or $InBash) {
|
||||||
|
Exec "$Bash" '-lc' ('{4} {6} {7} {8} [ -n ''{1}'' ] && export GHCUP_MSYS2=$(cygpath -m ''{1}'') ; [ -n ''{2}'' ] && export GHCUP_INSTALL_BASE_PREFIX=$(cygpath -m ''{2}/'') ; export PATH=$(cygpath -u ''{3}/bin''):$PATH ; export CABAL_DIR=''{5}'' ; [[ ''{0}'' = https* ]] && curl --proto ''=https'' --tlsv1.2 -sSf {0} | bash || cat $(cygpath -m ''{0}'') | bash' -f $BootstrapUrl, $MsysDir, $GhcupBasePrefix, $GhcupDir, $SilentExport, $CabalDirFull, $StackInstallExport, $HLSInstallExport, $AdjustCabalConfigExport)
|
||||||
|
} else {
|
||||||
|
Exec "$Msys2Shell" '-mingw64' '-mintty' '-c' ('{4} {6} {7} {8} [ -n ''{1}'' ] && export GHCUP_MSYS2=$(cygpath -m ''{1}'') ; [ -n ''{2}'' ] && export GHCUP_INSTALL_BASE_PREFIX=$(cygpath -m ''{2}/'') ; export PATH=$(cygpath -u ''{3}/bin''):$PATH ; export CABAL_DIR=''{5}'' ; trap ''echo Press any key to exit && read -n 1 && exit'' 2 ; [[ ''{0}'' = https* ]] && curl --proto ''=https'' --tlsv1.2 -sSf {0} | bash || cat $(cygpath -m ''{0}'') | bash ; echo ''Press any key to exit'' && read -n 1' -f $BootstrapUrl, $MsysDir, $GhcupBasePrefix, $GhcupDir, $SilentExport, $CabalDirFull, $StackInstallExport, $HLSInstallExport, $AdjustCabalConfigExport)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# SIG # Begin signature block
|
||||||
|
# MIID4QYJKoZIhvcNAQcCoIID0jCCA84CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
|
||||||
|
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
|
||||||
|
# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUVqKek181kF/Jx/P7z176herc
|
||||||
|
# ZyCgggH/MIIB+zCCAWSgAwIBAgIQGOezhGS1A5tHh9VubW0liDANBgkqhkiG9w0B
|
||||||
|
# AQUFADAYMRYwFAYDVQQDDA1KdWxpYW4gT3NwYWxkMB4XDTIxMDUzMDE4Mzk1OVoX
|
||||||
|
# DTI1MDUzMDAwMDAwMFowGDEWMBQGA1UEAwwNSnVsaWFuIE9zcGFsZDCBnzANBgkq
|
||||||
|
# hkiG9w0BAQEFAAOBjQAwgYkCgYEAs76XCXYPM14buR1RkVKhOB8pyM4Df6kPaz75
|
||||||
|
# nkbA0nq1VmMhBfCYFWyYHd7jniqTH0LoAKGGquN1bniREaCP9j2pFWpMIgLpQH3H
|
||||||
|
# +jpsfmxV2BTG8q+Jok88gTXS1FlAk72E85zO/Jhr6Fja1aFYAdibBRsRxcVMTVh7
|
||||||
|
# 4AGLNGUCAwEAAaNGMEQwEwYDVR0lBAwwCgYIKwYBBQUHAwMwHQYDVR0OBBYEFC+R
|
||||||
|
# hdhPo0Ty5HnzHyo1pN35IfZQMA4GA1UdDwEB/wQEAwIHgDANBgkqhkiG9w0BAQUF
|
||||||
|
# AAOBgQAl3IdBVIwbJJDp7BksMYPeM4ivB3UyNvlw8aVxGwAzNgdSaezYIdMFtKXV
|
||||||
|
# CSv5bd4VnFRAPDJW9dhW0h3SkeJUoklUxMjKXhR3qygQhSxPDjIatAuOCffGACba
|
||||||
|
# ZZ7Om40b+pKXc6i/HnlApk9DGbXJ59bFcLGGcZ9QjoUae6Ex1DGCAUwwggFIAgEB
|
||||||
|
# MCwwGDEWMBQGA1UEAwwNSnVsaWFuIE9zcGFsZAIQGOezhGS1A5tHh9VubW0liDAJ
|
||||||
|
# BgUrDgMCGgUAoHgwGAYKKwYBBAGCNwIBDDEKMAigAoAAoQKAADAZBgkqhkiG9w0B
|
||||||
|
# CQMxDAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAj
|
||||||
|
# BgkqhkiG9w0BCQQxFgQUosm9nN1JgajqSBa1cUwxxhLrAsYwDQYJKoZIhvcNAQEB
|
||||||
|
# BQAEgYCnKzfsH1aDjS6xkC/uymjaBowHSnh6nFu2AkjcKu8RgcBZzP5SLBXgU9wm
|
||||||
|
# aED5Ujwyq3Qre+TGVRUqwkEauDhQiX2A008G00fRO6+di6yJRCRn5eaRAbdU3Xww
|
||||||
|
# E5VhEwLBnwzWrvLKtdEclhgUCo5Tq87QMXVdgX4aRmunl4ZE+Q==
|
||||||
|
# SIG # End signature block
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
packages: ./ghcup.cabal
|
|
||||||
|
|
||||||
with-compiler: ghc-8.10.4
|
|
||||||
|
|
||||||
optional-packages: ./3rdparty/*/*.cabal
|
|
||||||
|
|
||||||
optimization: 2
|
|
||||||
|
|
||||||
package streamly
|
|
||||||
ghc-options: -O2 -fspec-constr-recursive=16 -fmax-worker-args=16
|
|
||||||
|
|
||||||
package ghcup
|
|
||||||
ghc-options: -O2 -fspec-constr-recursive=16 -fmax-worker-args=16
|
|
||||||
|
|
||||||
constraints: http-io-streams -brotli
|
|
||||||
|
|
||||||
package libarchive
|
|
||||||
flags: -system-libarchive
|
|
||||||
|
|
||||||
allow-newer: base, ghc-prim, template-haskell
|
|
||||||
33
cabal.ghc8105.project
Normal file
33
cabal.ghc8105.project
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
packages: ./ghcup.cabal
|
||||||
|
|
||||||
|
optional-packages: ./vendored/*/*.cabal
|
||||||
|
|
||||||
|
optimization: 2
|
||||||
|
|
||||||
|
package ghcup
|
||||||
|
tests: True
|
||||||
|
flags: +tui
|
||||||
|
|
||||||
|
source-repository-package
|
||||||
|
type: git
|
||||||
|
location: https://github.com/jtdaugherty/brick.git
|
||||||
|
tag: b3b96cfe66dfd398d338e3feb2b6855e66a35190
|
||||||
|
|
||||||
|
source-repository-package
|
||||||
|
type: git
|
||||||
|
location: https://github.com/Bodigrim/tar
|
||||||
|
tag: ac197ec7ea4838dc2b4e22b9b888b080cedf29cf
|
||||||
|
|
||||||
|
source-repository-package
|
||||||
|
type: git
|
||||||
|
location: https://github.com/bgamari/terminal-size
|
||||||
|
tag: 34ea816bd63f75f800eedac12c6908c6f3736036
|
||||||
|
|
||||||
|
constraints: http-io-streams -brotli
|
||||||
|
|
||||||
|
package libarchive
|
||||||
|
flags: -system-libarchive
|
||||||
|
|
||||||
|
allow-newer: base, ghc-prim, template-haskell, language-c
|
||||||
|
|
||||||
|
with-compiler: ghc-8.10.5
|
||||||
@@ -1,12 +1,11 @@
|
|||||||
active-repositories: hackage.haskell.org:merge
|
active-repositories: hackage.haskell.org:merge
|
||||||
constraints: any.Cabal ==3.2.1.0,
|
constraints: any.Cabal ==3.2.1.0,
|
||||||
any.HUnit ==1.6.2.0,
|
any.HUnit ==1.6.2.0,
|
||||||
any.IfElse ==0.85,
|
any.HsOpenSSL ==0.11.7,
|
||||||
|
HsOpenSSL -fast-bignum -homebrew-openssl -macports-openssl -use-pkg-config,
|
||||||
any.QuickCheck ==2.14.2,
|
any.QuickCheck ==2.14.2,
|
||||||
QuickCheck -old-random +templatehaskell,
|
QuickCheck -old-random +templatehaskell,
|
||||||
any.StateVar ==1.2.1,
|
any.StateVar ==1.2.2,
|
||||||
any.abstract-deque ==0.3,
|
|
||||||
abstract-deque -usecas,
|
|
||||||
any.aeson ==1.5.6.0,
|
any.aeson ==1.5.6.0,
|
||||||
aeson -bytestring-builder -cffi -developer -fast,
|
aeson -bytestring-builder -cffi -developer -fast,
|
||||||
any.aeson-pretty ==0.8.8,
|
any.aeson-pretty ==0.8.8,
|
||||||
@@ -18,31 +17,32 @@ constraints: any.Cabal ==3.2.1.0,
|
|||||||
any.ansi-wl-pprint ==0.6.9,
|
any.ansi-wl-pprint ==0.6.9,
|
||||||
ansi-wl-pprint -example,
|
ansi-wl-pprint -example,
|
||||||
any.array ==0.5.4.0,
|
any.array ==0.5.4.0,
|
||||||
any.ascii-string ==1.0.1.4,
|
|
||||||
any.assoc ==1.0.2,
|
any.assoc ==1.0.2,
|
||||||
any.async ==2.2.3,
|
any.async ==2.2.3,
|
||||||
async -bench,
|
async -bench,
|
||||||
any.atomic-primops ==0.8.4,
|
|
||||||
atomic-primops -debug,
|
|
||||||
any.attoparsec ==0.13.2.5,
|
any.attoparsec ==0.13.2.5,
|
||||||
attoparsec -developer,
|
attoparsec -developer,
|
||||||
any.auto-update ==0.1.6,
|
any.auto-update ==0.1.6,
|
||||||
any.base ==4.14.1.0,
|
any.base ==4.14.2.0,
|
||||||
any.base-compat ==0.11.2,
|
any.base-compat ==0.11.2,
|
||||||
any.base-compat-batteries ==0.11.2,
|
any.base-compat-batteries ==0.11.2,
|
||||||
any.base-orphans ==0.8.4,
|
any.base-orphans ==0.8.4,
|
||||||
any.base16-bytestring ==1.0.1.0,
|
any.base16-bytestring ==1.0.1.0,
|
||||||
any.base64-bytestring ==1.2.0.1,
|
any.base64-bytestring ==1.1.0.0,
|
||||||
any.bifunctors ==5.5.10,
|
any.bifunctors ==5.5.11,
|
||||||
bifunctors +semigroups +tagged,
|
bifunctors +semigroups +tagged,
|
||||||
any.binary ==0.8.8.0,
|
any.binary ==0.8.8.0,
|
||||||
|
any.bindings-DSL ==1.0.25,
|
||||||
any.blaze-builder ==0.4.2.1,
|
any.blaze-builder ==0.4.2.1,
|
||||||
|
any.brick ==0.63,
|
||||||
|
brick -demos,
|
||||||
any.bytestring ==0.10.12.0,
|
any.bytestring ==0.10.12.0,
|
||||||
any.bz2 ==1.0.1.0,
|
any.bz2 ==1.0.1.0,
|
||||||
bz2 -cross +with-bzlib,
|
bz2 -cross +with-bzlib,
|
||||||
any.c2hs ==0.28.7,
|
any.bzlib-conduit ==0.3.0.2,
|
||||||
|
any.c2hs ==0.28.8,
|
||||||
c2hs +base3 -regression,
|
c2hs +base3 -regression,
|
||||||
any.call-stack ==0.3.0,
|
any.call-stack ==0.4.0,
|
||||||
any.case-insensitive ==1.2.1.0,
|
any.case-insensitive ==1.2.1.0,
|
||||||
any.casing ==0.1.4.1,
|
any.casing ==0.1.4.1,
|
||||||
any.cereal ==0.5.8.1,
|
any.cereal ==0.5.8.1,
|
||||||
@@ -54,7 +54,7 @@ constraints: any.Cabal ==3.2.1.0,
|
|||||||
clock -llvm,
|
clock -llvm,
|
||||||
any.cmdargs ==0.10.21,
|
any.cmdargs ==0.10.21,
|
||||||
cmdargs +quotation -testprog,
|
cmdargs +quotation -testprog,
|
||||||
any.colour ==2.3.5,
|
any.colour ==2.3.6,
|
||||||
any.comonad ==5.0.8,
|
any.comonad ==5.0.8,
|
||||||
comonad +containers +distributive +indexed-traversable,
|
comonad +containers +distributive +indexed-traversable,
|
||||||
any.composition-prelude ==3.0.0.2,
|
any.composition-prelude ==3.0.0.2,
|
||||||
@@ -62,16 +62,25 @@ constraints: any.Cabal ==3.2.1.0,
|
|||||||
any.concurrent-output ==1.10.12,
|
any.concurrent-output ==1.10.12,
|
||||||
any.conduit ==1.3.4.1,
|
any.conduit ==1.3.4.1,
|
||||||
any.conduit-extra ==1.3.5,
|
any.conduit-extra ==1.3.5,
|
||||||
any.containers ==0.6.2.1,
|
any.conduit-zstd ==0.0.2.0,
|
||||||
any.contravariant ==1.5.3,
|
any.config-ini ==0.2.4.0,
|
||||||
|
config-ini -enable-doctests,
|
||||||
|
any.containers ==0.6.4.1,
|
||||||
|
any.contravariant ==1.5.4,
|
||||||
contravariant +semigroups +statevar +tagged,
|
contravariant +semigroups +statevar +tagged,
|
||||||
|
any.cpphs ==1.20.9.1,
|
||||||
|
cpphs -old-locale,
|
||||||
|
any.cryptohash-sha1 ==0.11.100.1,
|
||||||
any.cryptohash-sha256 ==0.11.102.0,
|
any.cryptohash-sha256 ==0.11.102.0,
|
||||||
cryptohash-sha256 -exe +use-cbits,
|
cryptohash-sha256 -exe +use-cbits,
|
||||||
|
any.data-clist ==0.1.2.3,
|
||||||
any.data-default-class ==0.1.2.0,
|
any.data-default-class ==0.1.2.0,
|
||||||
any.data-fix ==0.3.1,
|
any.data-fix ==0.3.1,
|
||||||
any.deepseq ==1.4.4.0,
|
any.deepseq ==1.4.4.0,
|
||||||
any.deferred-folds ==0.9.17,
|
any.digest ==0.0.1.3,
|
||||||
|
digest -bytestring-in-base,
|
||||||
any.directory ==1.3.6.0,
|
any.directory ==1.3.6.0,
|
||||||
|
any.disk-free-space ==0.1.0.1,
|
||||||
any.distributive ==0.6.2.1,
|
any.distributive ==0.6.2.1,
|
||||||
distributive +semigroups +tagged,
|
distributive +semigroups +tagged,
|
||||||
any.dlist ==1.0,
|
any.dlist ==1.0,
|
||||||
@@ -79,74 +88,68 @@ constraints: any.Cabal ==3.2.1.0,
|
|||||||
any.easy-file ==0.2.2,
|
any.easy-file ==0.2.2,
|
||||||
any.errors ==2.3.0,
|
any.errors ==2.3.0,
|
||||||
any.exceptions ==0.10.4,
|
any.exceptions ==0.10.4,
|
||||||
any.fast-logger ==3.0.3,
|
any.extra ==1.7.9,
|
||||||
|
any.fast-logger ==3.0.5,
|
||||||
any.filepath ==1.4.2.1,
|
any.filepath ==1.4.2.1,
|
||||||
any.focus ==1.0.2,
|
any.free ==5.1.7,
|
||||||
any.foldl ==1.4.11,
|
|
||||||
any.free ==5.1.6,
|
|
||||||
any.fusion-plugin-types ==0.1.0,
|
|
||||||
any.generic-arbitrary ==0.1.0,
|
any.generic-arbitrary ==0.1.0,
|
||||||
any.generics-sop ==0.5.1.1,
|
any.generics-sop ==0.5.1.1,
|
||||||
any.ghc-boot-th ==8.10.4,
|
any.ghc-boot-th ==8.10.5,
|
||||||
|
any.ghc-byteorder ==4.11.0.0.10,
|
||||||
any.ghc-prim ==0.6.1,
|
any.ghc-prim ==0.6.1,
|
||||||
ghcup -internal-downloader -tar -tui,
|
|
||||||
any.happy ==1.20.0,
|
any.happy ==1.20.0,
|
||||||
any.hashable ==1.3.1.0,
|
any.hashable ==1.3.2.0,
|
||||||
hashable +integer-gmp,
|
hashable +integer-gmp -random-initial-seed,
|
||||||
any.haskell-src-exts ==1.23.1,
|
any.haskell-src-exts ==1.23.1,
|
||||||
any.haskell-src-meta ==0.8.7,
|
any.haskell-src-meta ==0.8.7,
|
||||||
any.haskus-utils-data ==1.4,
|
any.haskus-utils-data ==1.4,
|
||||||
any.haskus-utils-types ==1.5.1,
|
any.haskus-utils-types ==1.5.1,
|
||||||
any.haskus-utils-variant ==3.1,
|
any.haskus-utils-variant ==3.1,
|
||||||
any.heaps ==0.3.6.1,
|
|
||||||
any.hpath ==0.11.0,
|
|
||||||
any.hpath-directory ==0.14.1,
|
|
||||||
any.hpath-filepath ==0.10.4,
|
any.hpath-filepath ==0.10.4,
|
||||||
any.hpath-io ==0.14.1,
|
any.hpath-posix ==0.13.3,
|
||||||
any.hpath-posix ==0.13.2,
|
|
||||||
any.hsc2hs ==0.68.7,
|
any.hsc2hs ==0.68.7,
|
||||||
hsc2hs -in-ghc-tree,
|
hsc2hs -in-ghc-tree,
|
||||||
any.hspec ==2.7.8,
|
any.hspec ==2.7.10,
|
||||||
any.hspec-core ==2.7.8,
|
any.hspec-core ==2.7.10,
|
||||||
any.hspec-discover ==2.7.8,
|
any.hspec-discover ==2.7.10 || ==2.8.2,
|
||||||
any.hspec-expectations ==0.8.2,
|
any.hspec-expectations ==0.8.2,
|
||||||
any.hspec-golden-aeson ==0.7.0.0,
|
any.hspec-golden-aeson ==0.9.0.0,
|
||||||
any.indexed-profunctors ==0.1,
|
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 ==0.1.1,
|
||||||
any.indexed-traversable-instances ==0.1,
|
any.indexed-traversable-instances ==0.1,
|
||||||
any.integer-gmp ==1.0.3.0,
|
any.integer-gmp ==1.0.3.0,
|
||||||
any.integer-logarithms ==1.0.3.1,
|
any.integer-logarithms ==1.0.3.1,
|
||||||
integer-logarithms -check-bounds +integer-gmp,
|
integer-logarithms -check-bounds +integer-gmp,
|
||||||
any.language-c ==0.8.3,
|
any.io-streams ==1.5.2.1,
|
||||||
language-c -allwarnings +iecfpextension +separatesyb +usebytestrings,
|
io-streams +network -nointeractivetests +zlib,
|
||||||
any.libarchive ==3.0.2.1,
|
any.language-c ==0.9.0.1,
|
||||||
|
language-c -allwarnings +iecfpextension +usebytestrings,
|
||||||
|
any.libarchive ==3.0.2.2,
|
||||||
libarchive -cross -low-memory -system-libarchive,
|
libarchive -cross -low-memory -system-libarchive,
|
||||||
any.libyaml ==0.1.2,
|
any.libyaml ==0.1.2,
|
||||||
libyaml -no-unicode -system-libyaml,
|
libyaml -no-unicode -system-libyaml,
|
||||||
any.lifted-base ==0.2.3.12,
|
any.lifted-base ==0.2.3.12,
|
||||||
any.list-t ==1.0.4,
|
any.lzma-static ==5.2.5.4,
|
||||||
any.lockfree-queue ==0.2.3.1,
|
|
||||||
lzma -static,
|
|
||||||
any.math-functions ==0.3.4.1,
|
|
||||||
math-functions +system-erf +system-expm1,
|
|
||||||
any.megaparsec ==9.0.1,
|
any.megaparsec ==9.0.1,
|
||||||
megaparsec -dev,
|
megaparsec -dev,
|
||||||
any.microlens ==0.4.12.0,
|
any.microlens ==0.4.12.0,
|
||||||
any.microlens-mtl ==0.2.0.1,
|
any.microlens-mtl ==0.2.0.1,
|
||||||
any.microlens-th ==0.4.3.9,
|
any.microlens-th ==0.4.3.10,
|
||||||
any.mmorph ==1.1.5,
|
any.monad-control ==1.0.3,
|
||||||
any.monad-control ==1.0.2.3,
|
|
||||||
any.monad-logger ==0.3.36,
|
any.monad-logger ==0.3.36,
|
||||||
monad-logger +template_haskell,
|
monad-logger +template_haskell,
|
||||||
any.monad-loops ==0.4.3,
|
any.monad-loops ==0.4.3,
|
||||||
monad-loops +base4,
|
monad-loops +base4,
|
||||||
any.mono-traversable ==1.0.15.1,
|
any.mono-traversable ==1.0.15.1,
|
||||||
any.mtl ==2.2.2,
|
any.mtl ==2.2.2,
|
||||||
any.mwc-random ==0.15.0.1,
|
any.network ==3.1.2.2,
|
||||||
any.network ==3.1.2.1,
|
|
||||||
network -devel,
|
network -devel,
|
||||||
|
any.network-uri ==2.6.4.1,
|
||||||
any.old-locale ==1.0.0.7,
|
any.old-locale ==1.0.0.7,
|
||||||
any.old-time ==1.1.0.3,
|
any.old-time ==1.1.0.3,
|
||||||
|
any.openssl-streams ==1.2.3.0,
|
||||||
any.optics ==0.4,
|
any.optics ==0.4,
|
||||||
any.optics-core ==0.4,
|
any.optics-core ==0.4,
|
||||||
optics-core -explicit-generic-labels,
|
optics-core -explicit-generic-labels,
|
||||||
@@ -161,25 +164,25 @@ constraints: any.Cabal ==3.2.1.0,
|
|||||||
any.parsec ==3.1.14.0,
|
any.parsec ==3.1.14.0,
|
||||||
any.parser-combinators ==1.3.0,
|
any.parser-combinators ==1.3.0,
|
||||||
parser-combinators -dev,
|
parser-combinators -dev,
|
||||||
|
any.polyparse ==1.13,
|
||||||
any.pretty ==1.1.3.6,
|
any.pretty ==1.1.3.6,
|
||||||
any.pretty-terminal ==0.1.0.0,
|
any.pretty-terminal ==0.1.0.0,
|
||||||
any.primitive ==0.7.1.0,
|
any.primitive ==0.7.1.0,
|
||||||
any.primitive-extras ==0.8.2,
|
|
||||||
any.primitive-unlifted ==0.1.3.0,
|
|
||||||
any.process ==1.6.9.0,
|
any.process ==1.6.9.0,
|
||||||
any.profunctors ==5.6.2,
|
any.profunctors ==5.6.2,
|
||||||
any.quickcheck-arbitrary-adt ==0.3.1.0,
|
any.quickcheck-arbitrary-adt ==0.3.1.0,
|
||||||
any.quickcheck-io ==0.2.0,
|
any.quickcheck-io ==0.2.0,
|
||||||
any.random ==1.2.0,
|
any.random ==1.2.0,
|
||||||
any.recursion-schemes ==5.2.2,
|
any.recursion-schemes ==5.2.2.1,
|
||||||
recursion-schemes +template-haskell,
|
recursion-schemes +template-haskell,
|
||||||
any.regex-posix ==0.96.0.0,
|
any.regex-base ==0.94.0.1,
|
||||||
|
any.regex-posix ==0.96.0.1,
|
||||||
regex-posix -_regex-posix-clib,
|
regex-posix -_regex-posix-clib,
|
||||||
any.resourcet ==1.2.4.2,
|
any.resourcet ==1.2.4.2,
|
||||||
any.rts ==1.0,
|
any.rts ==1.0.1,
|
||||||
any.safe ==0.3.19,
|
any.safe ==0.3.19,
|
||||||
any.safe-exceptions ==0.1.7.1,
|
any.safe-exceptions ==0.1.7.2,
|
||||||
any.scientific ==0.3.6.2,
|
any.scientific ==0.3.7.0,
|
||||||
scientific -bytestring-builder -integer-simple,
|
scientific -bytestring-builder -integer-simple,
|
||||||
any.semigroupoids ==5.3.5,
|
any.semigroupoids ==5.3.5,
|
||||||
semigroupoids +comonad +containers +contravariant +distributive +tagged +unordered-containers,
|
semigroupoids +comonad +containers +contravariant +distributive +tagged +unordered-containers,
|
||||||
@@ -188,36 +191,31 @@ constraints: any.Cabal ==3.2.1.0,
|
|||||||
any.split ==0.2.3.4,
|
any.split ==0.2.3.4,
|
||||||
any.splitmix ==0.1.0.3,
|
any.splitmix ==0.1.0.3,
|
||||||
splitmix -optimised-mixer,
|
splitmix -optimised-mixer,
|
||||||
any.stm ==2.5.0.0,
|
any.stm ==2.5.0.1,
|
||||||
any.stm-chans ==3.0.0.4,
|
any.stm-chans ==3.0.0.4,
|
||||||
any.streaming-commons ==0.2.2.1,
|
any.streaming-commons ==0.2.2.1,
|
||||||
streaming-commons -use-bytestring-builder,
|
streaming-commons -use-bytestring-builder,
|
||||||
any.streamly ==0.7.3,
|
|
||||||
streamly -debug -dev -examples -examples-sdl -fusion-plugin -has-llvm -inspection -no-fusion -streamk,
|
|
||||||
any.streamly-bytestring ==0.1.2,
|
|
||||||
any.streamly-posix ==0.1.0.1,
|
|
||||||
any.strict ==0.4.0.1,
|
any.strict ==0.4.0.1,
|
||||||
strict +assoc,
|
strict +assoc,
|
||||||
any.strict-base ==0.4.0.0,
|
any.strict-base ==0.4.0.0,
|
||||||
any.string-interpolate ==0.3.1.0,
|
any.string-interpolate ==0.3.1.1,
|
||||||
string-interpolate -bytestring-builder -extended-benchmarks -text-builder,
|
string-interpolate -bytestring-builder -extended-benchmarks -text-builder,
|
||||||
any.syb ==0.7.2.1,
|
any.syb ==0.7.2.1,
|
||||||
any.tagged ==0.8.6.1,
|
any.tagged ==0.8.6.1,
|
||||||
tagged +deepseq +transformers,
|
tagged +deepseq +transformers,
|
||||||
any.tasty ==1.3.1,
|
any.tar ==0.6.0.0,
|
||||||
tasty +clock,
|
|
||||||
any.tasty-hunit ==0.10.0.3,
|
|
||||||
any.tasty-quickcheck ==0.10.1.2,
|
|
||||||
any.template-haskell ==2.16.0.0,
|
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.terminal-size ==0.3.2.1,
|
||||||
any.terminfo ==0.4.1.4,
|
any.terminfo ==0.4.1.4,
|
||||||
any.text ==1.2.4.1,
|
any.text ==1.2.4.1,
|
||||||
any.text-conversions ==0.3.1,
|
any.text-conversions ==0.3.1,
|
||||||
any.text-short ==0.1.3,
|
any.text-zipper ==0.11,
|
||||||
text-short -asserts,
|
|
||||||
any.tf-random ==0.5,
|
any.tf-random ==0.5,
|
||||||
any.th-abstraction ==0.4.2.0,
|
any.th-abstraction ==0.4.2.0,
|
||||||
any.th-compat ==0.1.1,
|
any.th-compat ==0.1.2,
|
||||||
|
any.th-expand-syns ==0.4.8.0,
|
||||||
any.th-lift ==0.8.2,
|
any.th-lift ==0.8.2,
|
||||||
any.th-lift-instances ==0.1.18,
|
any.th-lift-instances ==0.1.18,
|
||||||
any.th-orphans ==0.13.11,
|
any.th-orphans ==0.13.11,
|
||||||
@@ -225,37 +223,42 @@ constraints: any.Cabal ==3.2.1.0,
|
|||||||
any.these ==1.1.1.1,
|
any.these ==1.1.1.1,
|
||||||
these +assoc,
|
these +assoc,
|
||||||
any.time ==1.9.3,
|
any.time ==1.9.3,
|
||||||
any.time-compat ==1.9.5,
|
any.time-compat ==1.9.6,
|
||||||
time-compat -old-locale,
|
time-compat -old-locale,
|
||||||
any.transformers ==0.5.6.2,
|
any.transformers ==0.5.6.2,
|
||||||
any.transformers-base ==0.4.5.2,
|
any.transformers-base ==0.4.5.2,
|
||||||
transformers-base +orphaninstances,
|
transformers-base +orphaninstances,
|
||||||
any.transformers-compat ==0.6.6,
|
any.transformers-compat ==0.7,
|
||||||
transformers-compat -five +five-three -four +generic-deriving +mtl -three -two,
|
transformers-compat -five +five-three -four +generic-deriving +mtl -three -two,
|
||||||
any.typed-process ==0.2.6.0,
|
any.typed-process ==0.2.6.0,
|
||||||
any.unbounded-delays ==0.1.1.1,
|
|
||||||
any.unix ==2.7.2.2,
|
any.unix ==2.7.2.2,
|
||||||
any.unix-bytestring ==0.3.7.3,
|
any.unix-bytestring ==0.3.7.3,
|
||||||
any.unix-compat ==0.5.3,
|
any.unix-compat ==0.5.3,
|
||||||
unix-compat -old-time,
|
unix-compat -old-time,
|
||||||
any.unix-time ==0.4.7,
|
any.unix-time ==0.4.7,
|
||||||
any.unliftio-core ==0.2.0.1,
|
any.unliftio-core ==0.2.0.1,
|
||||||
any.unordered-containers ==0.2.13.0,
|
any.unordered-containers ==0.2.14.0,
|
||||||
unordered-containers -debug,
|
unordered-containers -debug,
|
||||||
any.uri-bytestring ==0.3.3.0,
|
any.uri-bytestring ==0.3.3.1,
|
||||||
uri-bytestring -lib-werror,
|
uri-bytestring -lib-werror,
|
||||||
any.utf8-string ==1.0.2,
|
any.utf8-string ==1.0.2,
|
||||||
any.uuid-types ==1.0.4,
|
any.uuid-types ==1.0.5,
|
||||||
any.vector ==0.12.2.0,
|
any.vector ==0.12.3.0,
|
||||||
vector +boundschecks -internalchecks -unsafechecks -wall,
|
vector +boundschecks -internalchecks -unsafechecks -wall,
|
||||||
any.vector-algorithms ==0.8.0.4,
|
any.vector-algorithms ==0.8.0.4,
|
||||||
vector-algorithms +bench +boundschecks -internalchecks -llvm +properties -unsafechecks,
|
vector-algorithms +bench +boundschecks -internalchecks -llvm +properties -unsafechecks,
|
||||||
any.versions ==4.0.3,
|
any.versions ==5.0.0,
|
||||||
any.vty ==5.33,
|
any.vty ==5.33,
|
||||||
any.wcwidth ==0.0.2,
|
any.word-wrap ==0.4.1,
|
||||||
wcwidth -cli +split-base,
|
|
||||||
any.word8 ==0.1.3,
|
any.word8 ==0.1.3,
|
||||||
|
any.xor ==0.0.1.0,
|
||||||
any.yaml ==0.11.5.0,
|
any.yaml ==0.11.5.0,
|
||||||
yaml +no-examples +no-exe,
|
yaml +no-examples +no-exe,
|
||||||
zlib -non-blocking-ffi -pkg-config -static
|
any.zip ==1.7.1,
|
||||||
index-state: hackage.haskell.org 2021-03-07T18:36:25Z
|
zip -dev -disable-bzip2 -disable-zstd,
|
||||||
|
any.zlib ==0.6.2.3,
|
||||||
|
zlib -bundled-c-zlib -non-blocking-ffi -pkg-config,
|
||||||
|
any.zlib-bindings ==0.1.1.5,
|
||||||
|
any.zstd ==0.1.2.0,
|
||||||
|
zstd +standalone
|
||||||
|
index-state: hackage.haskell.org 2021-07-27T07:59:57Z
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
packages: ./ghcup.cabal
|
|
||||||
|
|
||||||
with-compiler: ghc-8.8.4
|
|
||||||
|
|
||||||
optional-packages: ./3rdparty/*/*.cabal
|
|
||||||
|
|
||||||
optimization: 2
|
|
||||||
|
|
||||||
package streamly
|
|
||||||
ghc-options: -O2 -fspec-constr-recursive=16 -fmax-worker-args=16
|
|
||||||
|
|
||||||
package ghcup
|
|
||||||
ghc-options: -O2 -fspec-constr-recursive=16 -fmax-worker-args=16
|
|
||||||
|
|
||||||
constraints: http-io-streams -brotli
|
|
||||||
|
|
||||||
package libarchive
|
|
||||||
flags: -system-libarchive
|
|
||||||
|
|
||||||
allow-newer: base, ghc-prim, template-haskell
|
|
||||||
33
cabal.ghc901.project
Normal file
33
cabal.ghc901.project
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
packages: ./ghcup.cabal
|
||||||
|
|
||||||
|
optional-packages: ./vendored/*/*.cabal
|
||||||
|
|
||||||
|
optimization: 2
|
||||||
|
|
||||||
|
package ghcup
|
||||||
|
tests: True
|
||||||
|
flags: +tui
|
||||||
|
|
||||||
|
source-repository-package
|
||||||
|
type: git
|
||||||
|
location: https://github.com/jtdaugherty/brick.git
|
||||||
|
tag: b3b96cfe66dfd398d338e3feb2b6855e66a35190
|
||||||
|
|
||||||
|
source-repository-package
|
||||||
|
type: git
|
||||||
|
location: https://github.com/Bodigrim/tar
|
||||||
|
tag: ac197ec7ea4838dc2b4e22b9b888b080cedf29cf
|
||||||
|
|
||||||
|
source-repository-package
|
||||||
|
type: git
|
||||||
|
location: https://github.com/bgamari/terminal-size
|
||||||
|
tag: 34ea816bd63f75f800eedac12c6908c6f3736036
|
||||||
|
|
||||||
|
constraints: http-io-streams -brotli
|
||||||
|
|
||||||
|
package libarchive
|
||||||
|
flags: -system-libarchive
|
||||||
|
|
||||||
|
allow-newer: base, ghc-prim, template-haskell, language-c
|
||||||
|
|
||||||
|
with-compiler: ghc-9.0.1
|
||||||
@@ -1,12 +1,11 @@
|
|||||||
active-repositories: hackage.haskell.org:merge
|
active-repositories: hackage.haskell.org:merge
|
||||||
constraints: any.Cabal ==3.0.1.0,
|
constraints: any.Cabal ==3.4.0.0,
|
||||||
any.HUnit ==1.6.2.0,
|
any.HUnit ==1.6.2.0,
|
||||||
any.IfElse ==0.85,
|
any.HsOpenSSL ==0.11.7,
|
||||||
|
HsOpenSSL -fast-bignum -homebrew-openssl -macports-openssl -use-pkg-config,
|
||||||
any.QuickCheck ==2.14.2,
|
any.QuickCheck ==2.14.2,
|
||||||
QuickCheck -old-random +templatehaskell,
|
QuickCheck -old-random +templatehaskell,
|
||||||
any.StateVar ==1.2.1,
|
any.StateVar ==1.2.2,
|
||||||
any.abstract-deque ==0.3,
|
|
||||||
abstract-deque -usecas,
|
|
||||||
any.aeson ==1.5.6.0,
|
any.aeson ==1.5.6.0,
|
||||||
aeson -bytestring-builder -cffi -developer -fast,
|
aeson -bytestring-builder -cffi -developer -fast,
|
||||||
any.aeson-pretty ==0.8.8,
|
any.aeson-pretty ==0.8.8,
|
||||||
@@ -18,31 +17,32 @@ constraints: any.Cabal ==3.0.1.0,
|
|||||||
any.ansi-wl-pprint ==0.6.9,
|
any.ansi-wl-pprint ==0.6.9,
|
||||||
ansi-wl-pprint -example,
|
ansi-wl-pprint -example,
|
||||||
any.array ==0.5.4.0,
|
any.array ==0.5.4.0,
|
||||||
any.ascii-string ==1.0.1.4,
|
|
||||||
any.assoc ==1.0.2,
|
any.assoc ==1.0.2,
|
||||||
any.async ==2.2.3,
|
any.async ==2.2.3,
|
||||||
async -bench,
|
async -bench,
|
||||||
any.atomic-primops ==0.8.4,
|
|
||||||
atomic-primops -debug,
|
|
||||||
any.attoparsec ==0.13.2.5,
|
any.attoparsec ==0.13.2.5,
|
||||||
attoparsec -developer,
|
attoparsec -developer,
|
||||||
any.auto-update ==0.1.6,
|
any.auto-update ==0.1.6,
|
||||||
any.base ==4.13.0.0,
|
any.base ==4.15.0.0,
|
||||||
any.base-compat ==0.11.2,
|
any.base-compat ==0.11.2,
|
||||||
any.base-compat-batteries ==0.11.2,
|
any.base-compat-batteries ==0.11.2,
|
||||||
any.base-orphans ==0.8.4,
|
any.base-orphans ==0.8.4,
|
||||||
any.base16-bytestring ==1.0.1.0,
|
any.base16-bytestring ==1.0.1.0,
|
||||||
any.base64-bytestring ==1.2.0.1,
|
any.base64-bytestring ==1.1.0.0,
|
||||||
any.bifunctors ==5.5.10,
|
any.bifunctors ==5.5.11,
|
||||||
bifunctors +semigroups +tagged,
|
bifunctors +semigroups +tagged,
|
||||||
any.binary ==0.8.7.0,
|
any.binary ==0.8.8.0,
|
||||||
|
any.bindings-DSL ==1.0.25,
|
||||||
any.blaze-builder ==0.4.2.1,
|
any.blaze-builder ==0.4.2.1,
|
||||||
any.bytestring ==0.10.10.1,
|
any.brick ==0.63,
|
||||||
|
brick -demos,
|
||||||
|
any.bytestring ==0.10.12.1,
|
||||||
any.bz2 ==1.0.1.0,
|
any.bz2 ==1.0.1.0,
|
||||||
bz2 -cross +with-bzlib,
|
bz2 -cross +with-bzlib,
|
||||||
any.c2hs ==0.28.7,
|
any.bzlib-conduit ==0.3.0.2,
|
||||||
|
any.c2hs ==0.28.8,
|
||||||
c2hs +base3 -regression,
|
c2hs +base3 -regression,
|
||||||
any.call-stack ==0.3.0,
|
any.call-stack ==0.4.0,
|
||||||
any.case-insensitive ==1.2.1.0,
|
any.case-insensitive ==1.2.1.0,
|
||||||
any.casing ==0.1.4.1,
|
any.casing ==0.1.4.1,
|
||||||
any.cereal ==0.5.8.1,
|
any.cereal ==0.5.8.1,
|
||||||
@@ -54,7 +54,7 @@ constraints: any.Cabal ==3.0.1.0,
|
|||||||
clock -llvm,
|
clock -llvm,
|
||||||
any.cmdargs ==0.10.21,
|
any.cmdargs ==0.10.21,
|
||||||
cmdargs +quotation -testprog,
|
cmdargs +quotation -testprog,
|
||||||
any.colour ==2.3.5,
|
any.colour ==2.3.6,
|
||||||
any.comonad ==5.0.8,
|
any.comonad ==5.0.8,
|
||||||
comonad +containers +distributive +indexed-traversable,
|
comonad +containers +distributive +indexed-traversable,
|
||||||
any.composition-prelude ==3.0.0.2,
|
any.composition-prelude ==3.0.0.2,
|
||||||
@@ -62,16 +62,25 @@ constraints: any.Cabal ==3.0.1.0,
|
|||||||
any.concurrent-output ==1.10.12,
|
any.concurrent-output ==1.10.12,
|
||||||
any.conduit ==1.3.4.1,
|
any.conduit ==1.3.4.1,
|
||||||
any.conduit-extra ==1.3.5,
|
any.conduit-extra ==1.3.5,
|
||||||
any.containers ==0.6.2.1,
|
any.conduit-zstd ==0.0.2.0,
|
||||||
any.contravariant ==1.5.3,
|
any.config-ini ==0.2.4.0,
|
||||||
|
config-ini -enable-doctests,
|
||||||
|
any.containers ==0.6.4.1,
|
||||||
|
any.contravariant ==1.5.4,
|
||||||
contravariant +semigroups +statevar +tagged,
|
contravariant +semigroups +statevar +tagged,
|
||||||
|
any.cpphs ==1.20.9.1,
|
||||||
|
cpphs -old-locale,
|
||||||
|
any.cryptohash-sha1 ==0.11.100.1,
|
||||||
any.cryptohash-sha256 ==0.11.102.0,
|
any.cryptohash-sha256 ==0.11.102.0,
|
||||||
cryptohash-sha256 -exe +use-cbits,
|
cryptohash-sha256 -exe +use-cbits,
|
||||||
|
any.data-clist ==0.1.2.3,
|
||||||
any.data-default-class ==0.1.2.0,
|
any.data-default-class ==0.1.2.0,
|
||||||
any.data-fix ==0.3.1,
|
any.data-fix ==0.3.1,
|
||||||
any.deepseq ==1.4.4.0,
|
any.deepseq ==1.4.5.0,
|
||||||
any.deferred-folds ==0.9.17,
|
any.digest ==0.0.1.3,
|
||||||
any.directory ==1.3.6.0,
|
digest -bytestring-in-base,
|
||||||
|
any.directory ==1.3.6.1,
|
||||||
|
any.disk-free-space ==0.1.0.1,
|
||||||
any.distributive ==0.6.2.1,
|
any.distributive ==0.6.2.1,
|
||||||
distributive +semigroups +tagged,
|
distributive +semigroups +tagged,
|
||||||
any.dlist ==1.0,
|
any.dlist ==1.0,
|
||||||
@@ -79,75 +88,68 @@ constraints: any.Cabal ==3.0.1.0,
|
|||||||
any.easy-file ==0.2.2,
|
any.easy-file ==0.2.2,
|
||||||
any.errors ==2.3.0,
|
any.errors ==2.3.0,
|
||||||
any.exceptions ==0.10.4,
|
any.exceptions ==0.10.4,
|
||||||
exceptions +transformers-0-4,
|
any.extra ==1.7.9,
|
||||||
any.fast-logger ==3.0.3,
|
any.fast-logger ==3.0.5,
|
||||||
any.filepath ==1.4.2.1,
|
any.filepath ==1.4.2.1,
|
||||||
any.focus ==1.0.2,
|
any.free ==5.1.7,
|
||||||
any.foldl ==1.4.11,
|
|
||||||
any.free ==5.1.6,
|
|
||||||
any.fusion-plugin-types ==0.1.0,
|
|
||||||
any.generic-arbitrary ==0.1.0,
|
any.generic-arbitrary ==0.1.0,
|
||||||
any.generics-sop ==0.5.1.1,
|
any.generics-sop ==0.5.1.1,
|
||||||
any.ghc-boot-th ==8.8.4,
|
any.ghc-bignum ==1.0,
|
||||||
any.ghc-prim ==0.5.3,
|
any.ghc-boot-th ==9.0.1,
|
||||||
ghcup -internal-downloader -tar -tui,
|
any.ghc-byteorder ==4.11.0.0.10,
|
||||||
|
any.ghc-prim ==0.7.0,
|
||||||
any.happy ==1.20.0,
|
any.happy ==1.20.0,
|
||||||
any.hashable ==1.3.1.0,
|
any.hashable ==1.3.2.0,
|
||||||
hashable +integer-gmp,
|
hashable +integer-gmp -random-initial-seed,
|
||||||
any.haskell-src-exts ==1.23.1,
|
any.haskell-src-exts ==1.23.1,
|
||||||
any.haskell-src-meta ==0.8.7,
|
any.haskell-src-meta ==0.8.7,
|
||||||
any.haskus-utils-data ==1.4,
|
any.haskus-utils-data ==1.4,
|
||||||
any.haskus-utils-types ==1.5.1,
|
any.haskus-utils-types ==1.5.1,
|
||||||
any.haskus-utils-variant ==3.1,
|
any.haskus-utils-variant ==3.1,
|
||||||
any.heaps ==0.3.6.1,
|
|
||||||
any.hpath ==0.11.0,
|
|
||||||
any.hpath-directory ==0.14.1,
|
|
||||||
any.hpath-filepath ==0.10.4,
|
any.hpath-filepath ==0.10.4,
|
||||||
any.hpath-io ==0.14.1,
|
any.hpath-posix ==0.13.3,
|
||||||
any.hpath-posix ==0.13.2,
|
|
||||||
any.hsc2hs ==0.68.7,
|
any.hsc2hs ==0.68.7,
|
||||||
hsc2hs -in-ghc-tree,
|
hsc2hs -in-ghc-tree,
|
||||||
any.hspec ==2.7.8,
|
any.hspec ==2.7.10,
|
||||||
any.hspec-core ==2.7.8,
|
any.hspec-core ==2.7.10,
|
||||||
any.hspec-discover ==2.7.8,
|
any.hspec-discover ==2.7.10 || ==2.8.2,
|
||||||
any.hspec-expectations ==0.8.2,
|
any.hspec-expectations ==0.8.2,
|
||||||
any.hspec-golden-aeson ==0.7.0.0,
|
any.hspec-golden-aeson ==0.9.0.0,
|
||||||
any.indexed-profunctors ==0.1,
|
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 ==0.1.1,
|
||||||
any.indexed-traversable-instances ==0.1,
|
any.indexed-traversable-instances ==0.1,
|
||||||
any.integer-gmp ==1.0.2.0,
|
|
||||||
any.integer-logarithms ==1.0.3.1,
|
any.integer-logarithms ==1.0.3.1,
|
||||||
integer-logarithms -check-bounds +integer-gmp,
|
integer-logarithms -check-bounds +integer-gmp,
|
||||||
any.language-c ==0.8.3,
|
any.io-streams ==1.5.2.1,
|
||||||
language-c -allwarnings +iecfpextension +separatesyb +usebytestrings,
|
io-streams +network -nointeractivetests +zlib,
|
||||||
any.libarchive ==3.0.2.1,
|
any.language-c ==0.9.0.1,
|
||||||
|
language-c -allwarnings +iecfpextension +usebytestrings,
|
||||||
|
any.libarchive ==3.0.2.2,
|
||||||
libarchive -cross -low-memory -system-libarchive,
|
libarchive -cross -low-memory -system-libarchive,
|
||||||
any.libyaml ==0.1.2,
|
any.libyaml ==0.1.2,
|
||||||
libyaml -no-unicode -system-libyaml,
|
libyaml -no-unicode -system-libyaml,
|
||||||
any.lifted-base ==0.2.3.12,
|
any.lifted-base ==0.2.3.12,
|
||||||
any.list-t ==1.0.4,
|
any.lzma-static ==5.2.5.4,
|
||||||
any.lockfree-queue ==0.2.3.1,
|
|
||||||
lzma -static,
|
|
||||||
any.math-functions ==0.3.4.1,
|
|
||||||
math-functions +system-erf +system-expm1,
|
|
||||||
any.megaparsec ==9.0.1,
|
any.megaparsec ==9.0.1,
|
||||||
megaparsec -dev,
|
megaparsec -dev,
|
||||||
any.microlens ==0.4.12.0,
|
any.microlens ==0.4.12.0,
|
||||||
any.microlens-mtl ==0.2.0.1,
|
any.microlens-mtl ==0.2.0.1,
|
||||||
any.microlens-th ==0.4.3.9,
|
any.microlens-th ==0.4.3.10,
|
||||||
any.mmorph ==1.1.5,
|
any.monad-control ==1.0.3,
|
||||||
any.monad-control ==1.0.2.3,
|
|
||||||
any.monad-logger ==0.3.36,
|
any.monad-logger ==0.3.36,
|
||||||
monad-logger +template_haskell,
|
monad-logger +template_haskell,
|
||||||
any.monad-loops ==0.4.3,
|
any.monad-loops ==0.4.3,
|
||||||
monad-loops +base4,
|
monad-loops +base4,
|
||||||
any.mono-traversable ==1.0.15.1,
|
any.mono-traversable ==1.0.15.1,
|
||||||
any.mtl ==2.2.2,
|
any.mtl ==2.2.2,
|
||||||
any.mwc-random ==0.15.0.1,
|
any.network ==3.1.2.2,
|
||||||
any.network ==3.1.2.1,
|
|
||||||
network -devel,
|
network -devel,
|
||||||
|
any.network-uri ==2.6.4.1,
|
||||||
any.old-locale ==1.0.0.7,
|
any.old-locale ==1.0.0.7,
|
||||||
any.old-time ==1.1.0.3,
|
any.old-time ==1.1.0.3,
|
||||||
|
any.openssl-streams ==1.2.3.0,
|
||||||
any.optics ==0.4,
|
any.optics ==0.4,
|
||||||
any.optics-core ==0.4,
|
any.optics-core ==0.4,
|
||||||
optics-core -explicit-generic-labels,
|
optics-core -explicit-generic-labels,
|
||||||
@@ -162,25 +164,25 @@ constraints: any.Cabal ==3.0.1.0,
|
|||||||
any.parsec ==3.1.14.0,
|
any.parsec ==3.1.14.0,
|
||||||
any.parser-combinators ==1.3.0,
|
any.parser-combinators ==1.3.0,
|
||||||
parser-combinators -dev,
|
parser-combinators -dev,
|
||||||
|
any.polyparse ==1.13,
|
||||||
any.pretty ==1.1.3.6,
|
any.pretty ==1.1.3.6,
|
||||||
any.pretty-terminal ==0.1.0.0,
|
any.pretty-terminal ==0.1.0.0,
|
||||||
any.primitive ==0.7.1.0,
|
any.primitive ==0.7.1.0,
|
||||||
any.primitive-extras ==0.8.2,
|
any.process ==1.6.11.0,
|
||||||
any.primitive-unlifted ==0.1.3.0,
|
|
||||||
any.process ==1.6.9.0,
|
|
||||||
any.profunctors ==5.6.2,
|
any.profunctors ==5.6.2,
|
||||||
any.quickcheck-arbitrary-adt ==0.3.1.0,
|
any.quickcheck-arbitrary-adt ==0.3.1.0,
|
||||||
any.quickcheck-io ==0.2.0,
|
any.quickcheck-io ==0.2.0,
|
||||||
any.random ==1.2.0,
|
any.random ==1.2.0,
|
||||||
any.recursion-schemes ==5.2.2,
|
any.recursion-schemes ==5.2.2.1,
|
||||||
recursion-schemes +template-haskell,
|
recursion-schemes +template-haskell,
|
||||||
any.regex-posix ==0.96.0.0,
|
any.regex-base ==0.94.0.1,
|
||||||
|
any.regex-posix ==0.96.0.1,
|
||||||
regex-posix -_regex-posix-clib,
|
regex-posix -_regex-posix-clib,
|
||||||
any.resourcet ==1.2.4.2,
|
any.resourcet ==1.2.4.2,
|
||||||
any.rts ==1.0,
|
any.rts ==1.0,
|
||||||
any.safe ==0.3.19,
|
any.safe ==0.3.19,
|
||||||
any.safe-exceptions ==0.1.7.1,
|
any.safe-exceptions ==0.1.7.2,
|
||||||
any.scientific ==0.3.6.2,
|
any.scientific ==0.3.7.0,
|
||||||
scientific -bytestring-builder -integer-simple,
|
scientific -bytestring-builder -integer-simple,
|
||||||
any.semigroupoids ==5.3.5,
|
any.semigroupoids ==5.3.5,
|
||||||
semigroupoids +comonad +containers +contravariant +distributive +tagged +unordered-containers,
|
semigroupoids +comonad +containers +contravariant +distributive +tagged +unordered-containers,
|
||||||
@@ -193,32 +195,27 @@ constraints: any.Cabal ==3.0.1.0,
|
|||||||
any.stm-chans ==3.0.0.4,
|
any.stm-chans ==3.0.0.4,
|
||||||
any.streaming-commons ==0.2.2.1,
|
any.streaming-commons ==0.2.2.1,
|
||||||
streaming-commons -use-bytestring-builder,
|
streaming-commons -use-bytestring-builder,
|
||||||
any.streamly ==0.7.3,
|
|
||||||
streamly -debug -dev -examples -examples-sdl -fusion-plugin -has-llvm -inspection -no-fusion -streamk,
|
|
||||||
any.streamly-bytestring ==0.1.2,
|
|
||||||
any.streamly-posix ==0.1.0.1,
|
|
||||||
any.strict ==0.4.0.1,
|
any.strict ==0.4.0.1,
|
||||||
strict +assoc,
|
strict +assoc,
|
||||||
any.strict-base ==0.4.0.0,
|
any.strict-base ==0.4.0.0,
|
||||||
any.string-interpolate ==0.3.1.0,
|
any.string-interpolate ==0.3.1.1,
|
||||||
string-interpolate -bytestring-builder -extended-benchmarks -text-builder,
|
string-interpolate -bytestring-builder -extended-benchmarks -text-builder,
|
||||||
any.syb ==0.7.2.1,
|
any.syb ==0.7.2.1,
|
||||||
any.tagged ==0.8.6.1,
|
any.tagged ==0.8.6.1,
|
||||||
tagged +deepseq +transformers,
|
tagged +deepseq +transformers,
|
||||||
any.tasty ==1.3.1,
|
any.tar ==0.6.0.0,
|
||||||
tasty +clock,
|
any.template-haskell ==2.17.0.0,
|
||||||
any.tasty-hunit ==0.10.0.3,
|
any.temporary ==1.3,
|
||||||
any.tasty-quickcheck ==0.10.1.2,
|
any.terminal-progress-bar ==0.4.1,
|
||||||
any.template-haskell ==2.15.0.0,
|
|
||||||
any.terminal-size ==0.3.2.1,
|
any.terminal-size ==0.3.2.1,
|
||||||
any.terminfo ==0.4.1.4,
|
any.terminfo ==0.4.1.4,
|
||||||
any.text ==1.2.4.0,
|
any.text ==1.2.4.1,
|
||||||
any.text-conversions ==0.3.1,
|
any.text-conversions ==0.3.1,
|
||||||
any.text-short ==0.1.3,
|
any.text-zipper ==0.11,
|
||||||
text-short -asserts,
|
|
||||||
any.tf-random ==0.5,
|
any.tf-random ==0.5,
|
||||||
any.th-abstraction ==0.4.2.0,
|
any.th-abstraction ==0.4.2.0,
|
||||||
any.th-compat ==0.1.1,
|
any.th-compat ==0.1.2,
|
||||||
|
any.th-expand-syns ==0.4.8.0,
|
||||||
any.th-lift ==0.8.2,
|
any.th-lift ==0.8.2,
|
||||||
any.th-lift-instances ==0.1.18,
|
any.th-lift-instances ==0.1.18,
|
||||||
any.th-orphans ==0.13.11,
|
any.th-orphans ==0.13.11,
|
||||||
@@ -226,37 +223,42 @@ constraints: any.Cabal ==3.0.1.0,
|
|||||||
any.these ==1.1.1.1,
|
any.these ==1.1.1.1,
|
||||||
these +assoc,
|
these +assoc,
|
||||||
any.time ==1.9.3,
|
any.time ==1.9.3,
|
||||||
any.time-compat ==1.9.5,
|
any.time-compat ==1.9.6,
|
||||||
time-compat -old-locale,
|
time-compat -old-locale,
|
||||||
any.transformers ==0.5.6.2,
|
any.transformers ==0.5.6.2,
|
||||||
any.transformers-base ==0.4.5.2,
|
any.transformers-base ==0.4.5.2,
|
||||||
transformers-base +orphaninstances,
|
transformers-base +orphaninstances,
|
||||||
any.transformers-compat ==0.6.6,
|
any.transformers-compat ==0.7,
|
||||||
transformers-compat -five +five-three -four +generic-deriving +mtl -three -two,
|
transformers-compat -five +five-three -four +generic-deriving +mtl -three -two,
|
||||||
any.typed-process ==0.2.6.0,
|
any.typed-process ==0.2.6.0,
|
||||||
any.unbounded-delays ==0.1.1.1,
|
|
||||||
any.unix ==2.7.2.2,
|
any.unix ==2.7.2.2,
|
||||||
any.unix-bytestring ==0.3.7.3,
|
any.unix-bytestring ==0.3.7.3,
|
||||||
any.unix-compat ==0.5.3,
|
any.unix-compat ==0.5.3,
|
||||||
unix-compat -old-time,
|
unix-compat -old-time,
|
||||||
any.unix-time ==0.4.7,
|
any.unix-time ==0.4.7,
|
||||||
any.unliftio-core ==0.2.0.1,
|
any.unliftio-core ==0.2.0.1,
|
||||||
any.unordered-containers ==0.2.13.0,
|
any.unordered-containers ==0.2.14.0,
|
||||||
unordered-containers -debug,
|
unordered-containers -debug,
|
||||||
any.uri-bytestring ==0.3.3.0,
|
any.uri-bytestring ==0.3.3.1,
|
||||||
uri-bytestring -lib-werror,
|
uri-bytestring -lib-werror,
|
||||||
any.utf8-string ==1.0.2,
|
any.utf8-string ==1.0.2,
|
||||||
any.uuid-types ==1.0.4,
|
any.uuid-types ==1.0.5,
|
||||||
any.vector ==0.12.2.0,
|
any.vector ==0.12.3.0,
|
||||||
vector +boundschecks -internalchecks -unsafechecks -wall,
|
vector +boundschecks -internalchecks -unsafechecks -wall,
|
||||||
any.vector-algorithms ==0.8.0.4,
|
any.vector-algorithms ==0.8.0.4,
|
||||||
vector-algorithms +bench +boundschecks -internalchecks -llvm +properties -unsafechecks,
|
vector-algorithms +bench +boundschecks -internalchecks -llvm +properties -unsafechecks,
|
||||||
any.versions ==4.0.3,
|
any.versions ==5.0.0,
|
||||||
any.vty ==5.33,
|
any.vty ==5.33,
|
||||||
any.wcwidth ==0.0.2,
|
any.word-wrap ==0.4.1,
|
||||||
wcwidth -cli +split-base,
|
|
||||||
any.word8 ==0.1.3,
|
any.word8 ==0.1.3,
|
||||||
|
any.xor ==0.0.1.0,
|
||||||
any.yaml ==0.11.5.0,
|
any.yaml ==0.11.5.0,
|
||||||
yaml +no-examples +no-exe,
|
yaml +no-examples +no-exe,
|
||||||
zlib -non-blocking-ffi -pkg-config -static
|
any.zip ==1.7.1,
|
||||||
index-state: hackage.haskell.org 2021-03-07T18:36:25Z
|
zip -dev -disable-bzip2 -disable-zstd,
|
||||||
|
any.zlib ==0.6.2.3,
|
||||||
|
zlib -bundled-c-zlib -non-blocking-ffi -pkg-config,
|
||||||
|
any.zlib-bindings ==0.1.1.5,
|
||||||
|
any.zstd ==0.1.2.0,
|
||||||
|
zstd +standalone
|
||||||
|
index-state: hackage.haskell.org 2021-07-27T07:59:57Z
|
||||||
@@ -1,18 +1,31 @@
|
|||||||
packages: ./ghcup.cabal
|
packages: ./ghcup.cabal
|
||||||
|
|
||||||
|
optional-packages: ./vendored/*/*.cabal
|
||||||
|
|
||||||
optimization: 2
|
optimization: 2
|
||||||
|
|
||||||
package streamly
|
|
||||||
ghc-options: -O2 -fspec-constr-recursive=16 -fmax-worker-args=16
|
|
||||||
|
|
||||||
package ghcup
|
package ghcup
|
||||||
ghc-options: -O2 -fspec-constr-recursive=16 -fmax-worker-args=16
|
|
||||||
tests: True
|
tests: True
|
||||||
flags: +tui
|
flags: +tui
|
||||||
|
|
||||||
|
source-repository-package
|
||||||
|
type: git
|
||||||
|
location: https://github.com/jtdaugherty/brick.git
|
||||||
|
tag: b3b96cfe66dfd398d338e3feb2b6855e66a35190
|
||||||
|
|
||||||
|
source-repository-package
|
||||||
|
type: git
|
||||||
|
location: https://github.com/Bodigrim/tar
|
||||||
|
tag: ac197ec7ea4838dc2b4e22b9b888b080cedf29cf
|
||||||
|
|
||||||
|
source-repository-package
|
||||||
|
type: git
|
||||||
|
location: https://github.com/bgamari/terminal-size
|
||||||
|
tag: 34ea816bd63f75f800eedac12c6908c6f3736036
|
||||||
|
|
||||||
constraints: http-io-streams -brotli
|
constraints: http-io-streams -brotli
|
||||||
|
|
||||||
package libarchive
|
package libarchive
|
||||||
flags: -system-libarchive
|
flags: -system-libarchive
|
||||||
|
|
||||||
allow-newer: base, ghc-prim, template-haskell
|
allow-newer: base, ghc-prim, template-haskell, language-c
|
||||||
|
|||||||
2
cabal.project.freeze
Normal file
2
cabal.project.freeze
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
-- windows picks weird version
|
||||||
|
constraints: any.hsc2hs ==0.68.7
|
||||||
@@ -29,6 +29,8 @@ key-bindings:
|
|||||||
KChar: 'c'
|
KChar: 'c'
|
||||||
show-all:
|
show-all:
|
||||||
KChar: 'a'
|
KChar: 'a'
|
||||||
|
show-all-tools:
|
||||||
|
KChar: 't'
|
||||||
|
|
||||||
# Where to get GHC/cabal/hls download info/versions from. For more detailed explanation
|
# Where to get GHC/cabal/hls download info/versions from. For more detailed explanation
|
||||||
# check the 'URLSource' type in the code.
|
# check the 'URLSource' type in the code.
|
||||||
|
|||||||
2179
ghcup-0.0.1.json
Normal file
2179
ghcup-0.0.1.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1384,7 +1384,7 @@ ghcupDownloads:
|
|||||||
dlUri: https://oleg.fi/cabal-install-3.4.0.0-rc4/cabal-install-3.4.0.0-x86_64-freebsd-12.1-release.tar.xz
|
dlUri: https://oleg.fi/cabal-install-3.4.0.0-rc4/cabal-install-3.4.0.0-x86_64-freebsd-12.1-release.tar.xz
|
||||||
dlHash: 9705e16d03497b46be4ad477e6c64d10890af853eafa8a9adf6dba89aa9e05f7
|
dlHash: 9705e16d03497b46be4ad477e6c64d10890af853eafa8a9adf6dba89aa9e05f7
|
||||||
GHCup:
|
GHCup:
|
||||||
0.1.14:
|
0.1.16.1:
|
||||||
viTags:
|
viTags:
|
||||||
- Recommended
|
- Recommended
|
||||||
- Latest
|
- Latest
|
||||||
@@ -1394,22 +1394,22 @@ ghcupDownloads:
|
|||||||
A_64:
|
A_64:
|
||||||
Linux_UnknownLinux:
|
Linux_UnknownLinux:
|
||||||
unknown_versioning: &ghcup-64
|
unknown_versioning: &ghcup-64
|
||||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.14/x86_64-linux-ghcup-0.1.14
|
dlUri: https://downloads.haskell.org/~ghcup/0.1.16.1/x86_64-linux-ghcup-0.1.16.1
|
||||||
dlHash: e9b314d248f4d4604ce64cee1be7161c77c8940efd11986c9205779ec3b598dd
|
dlHash: c3505d929722e245b22ec7a05267f1ae8e04089e139bbb470783eb9a1b648f83
|
||||||
Darwin:
|
Darwin:
|
||||||
unknown_versioning:
|
unknown_versioning:
|
||||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.14/x86_64-apple-darwin-ghcup-0.1.14
|
dlUri: https://downloads.haskell.org/~ghcup/0.1.16.1/x86_64-apple-darwin-ghcup-0.1.16.1
|
||||||
dlHash: 69ede9db36c0ae631b679fceb87dd856d4753ee26f33610da37dd7a694809919
|
dlHash: 7edde6bb42323232d28495abbe630321d7eb8e3827e200438a9ae4c41e531e71
|
||||||
FreeBSD:
|
FreeBSD:
|
||||||
unknown_versioning:
|
unknown_versioning:
|
||||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.14/x86_64-portbld-freebsd-ghcup-0.1.14
|
dlUri: https://downloads.haskell.org/~ghcup/0.1.16.1/x86_64-portbld-freebsd-ghcup-0.1.16.1
|
||||||
dlHash: 68b09404cf49061da539463f42f8ad67c9cef5c5d3f68a3c7c4f6760e8442bb9
|
dlHash: 6b7fc3a52e859f186d30b04c823fd0c5997179222fe9aa510a33435f41599f5c
|
||||||
Linux_Alpine:
|
Linux_Alpine:
|
||||||
unknown_versioning: *ghcup-64
|
unknown_versioning: *ghcup-64
|
||||||
A_32:
|
A_32:
|
||||||
Linux_UnknownLinux:
|
Linux_UnknownLinux:
|
||||||
unknown_versioning: &ghcup-32
|
unknown_versioning: &ghcup-32
|
||||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.14/i386-linux-ghcup-0.1.14
|
dlUri: https://downloads.haskell.org/~ghcup/0.1.16.1/i386-linux-ghcup-0.1.16.1
|
||||||
dlHash: ecb1157f010d2421764c52ab0cdbbf9a5c3da555827172c7b904d5f3f96c80fa
|
dlHash: 93ca5d77247b6ecac01be75e9ef5454adbb503b7957b8e9c59a5abd2046aef3c
|
||||||
Linux_Alpine:
|
Linux_Alpine:
|
||||||
unknown_versioning: *ghcup-32
|
unknown_versioning: *ghcup-32
|
||||||
|
|||||||
@@ -1451,7 +1451,7 @@ ghcupDownloads:
|
|||||||
dlUri: https://oleg.fi/cabal-install-3.4.0.0-rc4/cabal-install-3.4.0.0-x86_64-freebsd-12.1-release.tar.xz
|
dlUri: https://oleg.fi/cabal-install-3.4.0.0-rc4/cabal-install-3.4.0.0-x86_64-freebsd-12.1-release.tar.xz
|
||||||
dlHash: 9705e16d03497b46be4ad477e6c64d10890af853eafa8a9adf6dba89aa9e05f7
|
dlHash: 9705e16d03497b46be4ad477e6c64d10890af853eafa8a9adf6dba89aa9e05f7
|
||||||
GHCup:
|
GHCup:
|
||||||
0.1.14:
|
0.1.16.1:
|
||||||
viTags:
|
viTags:
|
||||||
- Recommended
|
- Recommended
|
||||||
- Latest
|
- Latest
|
||||||
@@ -1461,23 +1461,23 @@ ghcupDownloads:
|
|||||||
A_64:
|
A_64:
|
||||||
Linux_UnknownLinux:
|
Linux_UnknownLinux:
|
||||||
unknown_versioning: &ghcup-64
|
unknown_versioning: &ghcup-64
|
||||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.14/x86_64-linux-ghcup-0.1.14
|
dlUri: https://downloads.haskell.org/~ghcup/0.1.16.1/x86_64-linux-ghcup-0.1.16.1
|
||||||
dlHash: e9b314d248f4d4604ce64cee1be7161c77c8940efd11986c9205779ec3b598dd
|
dlHash: c3505d929722e245b22ec7a05267f1ae8e04089e139bbb470783eb9a1b648f83
|
||||||
Darwin:
|
Darwin:
|
||||||
unknown_versioning:
|
unknown_versioning:
|
||||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.14/x86_64-apple-darwin-ghcup-0.1.14
|
dlUri: https://downloads.haskell.org/~ghcup/0.1.16.1/x86_64-apple-darwin-ghcup-0.1.16.1
|
||||||
dlHash: 69ede9db36c0ae631b679fceb87dd856d4753ee26f33610da37dd7a694809919
|
dlHash: 7edde6bb42323232d28495abbe630321d7eb8e3827e200438a9ae4c41e531e71
|
||||||
FreeBSD:
|
FreeBSD:
|
||||||
unknown_versioning:
|
unknown_versioning:
|
||||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.14/x86_64-portbld-freebsd-ghcup-0.1.14
|
dlUri: https://downloads.haskell.org/~ghcup/0.1.16.1/x86_64-portbld-freebsd-ghcup-0.1.16.1
|
||||||
dlHash: 68b09404cf49061da539463f42f8ad67c9cef5c5d3f68a3c7c4f6760e8442bb9
|
dlHash: 6b7fc3a52e859f186d30b04c823fd0c5997179222fe9aa510a33435f41599f5c
|
||||||
Linux_Alpine:
|
Linux_Alpine:
|
||||||
unknown_versioning: *ghcup-64
|
unknown_versioning: *ghcup-64
|
||||||
A_32:
|
A_32:
|
||||||
Linux_UnknownLinux:
|
Linux_UnknownLinux:
|
||||||
unknown_versioning: &ghcup-32
|
unknown_versioning: &ghcup-32
|
||||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.14/i386-linux-ghcup-0.1.14
|
dlUri: https://downloads.haskell.org/~ghcup/0.1.16.1/i386-linux-ghcup-0.1.16.1
|
||||||
dlHash: ecb1157f010d2421764c52ab0cdbbf9a5c3da555827172c7b904d5f3f96c80fa
|
dlHash: 93ca5d77247b6ecac01be75e9ef5454adbb503b7957b8e9c59a5abd2046aef3c
|
||||||
Linux_Alpine:
|
Linux_Alpine:
|
||||||
unknown_versioning: *ghcup-32
|
unknown_versioning: *ghcup-32
|
||||||
HLS:
|
HLS:
|
||||||
|
|||||||
253
ghcup-0.0.4.yaml
253
ghcup-0.0.4.yaml
@@ -139,6 +139,7 @@ ghcupDownloads:
|
|||||||
dlSubdir: ghc-7.10.3
|
dlSubdir: ghc-7.10.3
|
||||||
dlHash: cf90cedce1c28fd0e2b9e72fe8a938756668d18ea1fcc884a19f698658ac4fef
|
dlHash: cf90cedce1c28fd0e2b9e72fe8a938756668d18ea1fcc884a19f698658ac4fef
|
||||||
viPostRemove: &ghc-post-remove "After removing GHC you might also want to clean up your cabal store at: ~/.cabal/store/ghc-<ghcver>"
|
viPostRemove: &ghc-post-remove "After removing GHC you might also want to clean up your cabal store at: ~/.cabal/store/ghc-<ghcver>"
|
||||||
|
viPostInstall: "GHC-7.10.3 may give linking errors on most modern distros. You may have to pass '--ghc-option=-optc-no-pie --ghc-option=-optl-no-pie' to cabal build/install. Also see https://gitlab.haskell.org/ghc/ghc/-/issues/18763"
|
||||||
viArch:
|
viArch:
|
||||||
A_64:
|
A_64:
|
||||||
Linux_Debian:
|
Linux_Debian:
|
||||||
@@ -1285,6 +1286,7 @@ ghcupDownloads:
|
|||||||
dlHash: bb9c97826b1f4d7a8ef8bce0616b612f1ded10480ef10fcf7fb4e6d10a6681c8
|
dlHash: bb9c97826b1f4d7a8ef8bce0616b612f1ded10480ef10fcf7fb4e6d10a6681c8
|
||||||
8.10.3:
|
8.10.3:
|
||||||
viTags:
|
viTags:
|
||||||
|
- old
|
||||||
- base-4.14.1.0
|
- base-4.14.1.0
|
||||||
viChangeLog: https://downloads.haskell.org/~ghc/8.10.3/docs/html/users_guide/8.10.3-notes.html
|
viChangeLog: https://downloads.haskell.org/~ghc/8.10.3/docs/html/users_guide/8.10.3-notes.html
|
||||||
viSourceDL:
|
viSourceDL:
|
||||||
@@ -1374,7 +1376,6 @@ ghcupDownloads:
|
|||||||
dlHash: b823b58cae36fbac0741680ca7605180fa4cf4c6ae439123d282184b94d32fd6
|
dlHash: b823b58cae36fbac0741680ca7605180fa4cf4c6ae439123d282184b94d32fd6
|
||||||
8.10.4:
|
8.10.4:
|
||||||
viTags:
|
viTags:
|
||||||
- Recommended
|
|
||||||
- base-4.14.1.0
|
- base-4.14.1.0
|
||||||
viChangeLog: https://downloads.haskell.org/~ghc/8.10.4/docs/html/users_guide/8.10.4-notes.html
|
viChangeLog: https://downloads.haskell.org/~ghc/8.10.4/docs/html/users_guide/8.10.4-notes.html
|
||||||
viSourceDL:
|
viSourceDL:
|
||||||
@@ -1382,7 +1383,7 @@ ghcupDownloads:
|
|||||||
dlSubdir: ghc-8.10.4
|
dlSubdir: ghc-8.10.4
|
||||||
dlHash: 52af871b4e08550257d720c2944ac85727d0b948407cef1bebfe7508c224910e
|
dlHash: 52af871b4e08550257d720c2944ac85727d0b948407cef1bebfe7508c224910e
|
||||||
viPostRemove: *ghc-post-remove
|
viPostRemove: *ghc-post-remove
|
||||||
viPreCompile: "If you have autoconf >= 2.70 you'll need this patch https://gitlab.haskell.org/ghc/ghc/-/snippets/2040 (see the --patchdir option)"
|
viPreCompile: &ghc-pre-compile "If you have autoconf >= 2.70 you'll need this patch https://gitlab.haskell.org/ghc/ghc/-/snippets/2040 (see the --patchdir option)"
|
||||||
viArch:
|
viArch:
|
||||||
A_64:
|
A_64:
|
||||||
Linux_Debian:
|
Linux_Debian:
|
||||||
@@ -1463,6 +1464,97 @@ ghcupDownloads:
|
|||||||
dlUri: https://downloads.haskell.org/~ghc/8.10.4/ghc-8.10.4-armv7-deb10-linux.tar.xz
|
dlUri: https://downloads.haskell.org/~ghc/8.10.4/ghc-8.10.4-armv7-deb10-linux.tar.xz
|
||||||
dlSubdir: ghc-8.10.4
|
dlSubdir: ghc-8.10.4
|
||||||
dlHash: 0d18ef83593272f6196a41cc3abdc48dfe5e14372db75d71ea19fe35320c4e81
|
dlHash: 0d18ef83593272f6196a41cc3abdc48dfe5e14372db75d71ea19fe35320c4e81
|
||||||
|
8.10.5:
|
||||||
|
viTags:
|
||||||
|
- Recommended
|
||||||
|
- base-4.14.2.0
|
||||||
|
viChangeLog: https://downloads.haskell.org/~ghc/8.10.5/docs/html/users_guide/8.10.5-notes.html
|
||||||
|
viSourceDL:
|
||||||
|
dlUri: https://downloads.haskell.org/~ghc/8.10.5/ghc-8.10.5-src.tar.xz
|
||||||
|
dlSubdir: ghc-8.10.5
|
||||||
|
dlHash: f10941f16e4fbd98580ab5241b9271bb0851304560c4d5ca127e3b0e20e3076f
|
||||||
|
viPostRemove: *ghc-post-remove
|
||||||
|
viPreCompile: *ghc-pre-compile
|
||||||
|
viArch:
|
||||||
|
A_64:
|
||||||
|
Linux_Debian:
|
||||||
|
'( >= 9 && < 10 )': &ghc-8105-64-deb9
|
||||||
|
dlUri: https://downloads.haskell.org/~ghc/8.10.5/ghc-8.10.5-x86_64-deb9-linux.tar.xz
|
||||||
|
dlSubdir: ghc-8.10.5
|
||||||
|
dlHash: 15e71325c3bdfe3804be0f84c2fc5c913d811322d19b0f4d4cff20f29cdd804d
|
||||||
|
'( >= 10 && < 11 )': &ghc-8105-64-deb10
|
||||||
|
dlUri: https://downloads.haskell.org/~ghc/8.10.5/ghc-8.10.5-x86_64-deb10-linux.tar.xz
|
||||||
|
dlSubdir: ghc-8.10.5
|
||||||
|
dlHash: bc623c20ca4c5c18e952071ba14aa0cfc5c94d34219bffaa615f7b491f376787
|
||||||
|
unknown_versioning: *ghc-8105-64-deb9
|
||||||
|
Linux_Ubuntu:
|
||||||
|
unknown_versioning: &ghc-8105-64-fedora
|
||||||
|
dlUri: https://downloads.haskell.org/~ghc/8.10.5/ghc-8.10.5-x86_64-fedora27-linux.tar.xz
|
||||||
|
dlSubdir: ghc-8.10.5
|
||||||
|
dlHash: 73528ebfb219b50aa9042ee51a0a2bd764828d605f058404989d0b645752d210
|
||||||
|
'( >= 16 && < 19 )': *ghc-8105-64-deb9
|
||||||
|
Linux_Mint:
|
||||||
|
unknown_versioning: *ghc-8105-64-deb10
|
||||||
|
Linux_Fedora:
|
||||||
|
'( >= 27 && < 28 )': *ghc-8105-64-fedora
|
||||||
|
unknown_versioning: *ghc-8105-64-fedora
|
||||||
|
Linux_CentOS:
|
||||||
|
'( >= 7 && < 8 )': &ghc-8105-64-centos
|
||||||
|
dlUri: https://downloads.haskell.org/~ghc/8.10.5/ghc-8.10.5-x86_64-centos7-linux.tar.xz
|
||||||
|
dlSubdir: ghc-8.10.5
|
||||||
|
dlHash: 4cdb259ec74d1408dab45dab20dcedc21690f39921c2ea4546486fb3e81f4fbd
|
||||||
|
unknown_versioning: *ghc-8105-64-centos
|
||||||
|
Linux_RedHat:
|
||||||
|
unknown_versioning: *ghc-8105-64-centos
|
||||||
|
Linux_Alpine:
|
||||||
|
unknown_versioning:
|
||||||
|
dlUri: https://downloads.haskell.org/~ghc/8.10.5/ghc-8.10.5-x86_64-alpine3.10-linux-integer-simple.tar.xz
|
||||||
|
dlSubdir: ghc-8.10.5-x86_64-unknown-linux
|
||||||
|
dlHash: f4d7cd9ed12a4b8592219c9a63a86db1a256a09fa9e6ed755a60afc57dc782e2
|
||||||
|
Linux_AmazonLinux:
|
||||||
|
unknown_versioning: *ghc-8105-64-centos
|
||||||
|
Linux_UnknownLinux:
|
||||||
|
unknown_versioning: *ghc-8105-64-fedora
|
||||||
|
Darwin:
|
||||||
|
unknown_versioning:
|
||||||
|
dlUri: https://downloads.haskell.org/~ghc/8.10.5/ghc-8.10.5-x86_64-apple-darwin.tar.xz
|
||||||
|
dlSubdir: ghc-8.10.5
|
||||||
|
dlHash: ef0f47eff8962d58fa447123636cf8ef31c1e5b2d0ae90177d3388861ddf4a22
|
||||||
|
FreeBSD:
|
||||||
|
unknown_versioning:
|
||||||
|
dlUri: https://downloads.haskell.org/~ghcup/unofficial-bindists/ghc/8.10.5/ghc-8.10.5-x86_64-portbld-freebsd.tar.xz
|
||||||
|
dlSubdir: ghc-8.10.5
|
||||||
|
dlHash: 11a0b490bfb2f57b5bc87c69c197542eafce1b4991cc22f625179a6c6e567834
|
||||||
|
A_32:
|
||||||
|
Linux_Debian:
|
||||||
|
'( >= 9 && < 10 )': &ghc-8105-32-deb9
|
||||||
|
dlUri: https://downloads.haskell.org/~ghc/8.10.5/ghc-8.10.5-i386-deb9-linux.tar.xz
|
||||||
|
dlSubdir: ghc-8.10.5
|
||||||
|
dlHash: 0ccb5b2c1222374874795c35410754dd650f649b774872abbea2a4ef21ac9c9d
|
||||||
|
unknown_versioning: *ghc-8105-32-deb9
|
||||||
|
Linux_Ubuntu:
|
||||||
|
unknown_versioning: *ghc-8105-32-deb9
|
||||||
|
Linux_Mint:
|
||||||
|
unknown_versioning: *ghc-8105-32-deb9
|
||||||
|
Linux_UnknownLinux:
|
||||||
|
unknown_versioning: *ghc-8105-32-deb9
|
||||||
|
Linux_Alpine:
|
||||||
|
unknown_versioning:
|
||||||
|
dlUri: https://downloads.haskell.org/~ghcup/unofficial-bindists/ghc/8.10.5/ghc-8.10.5-i386-alpine-linux.tar.xz
|
||||||
|
dlSubdir: ghc-8.10.5
|
||||||
|
dlHash: 0e91abe61607f9375d4e252ee9c261e4856df396f60641bb1b880ab8a3a83ea7
|
||||||
|
A_ARM64:
|
||||||
|
Linux_UnknownLinux:
|
||||||
|
unknown_versioning:
|
||||||
|
dlUri: https://downloads.haskell.org/~ghc/8.10.5/ghc-8.10.5-aarch64-deb10-linux.tar.xz
|
||||||
|
dlSubdir: ghc-8.10.5
|
||||||
|
dlHash: 9a085cd8a7f8e0ace21ac67dbf659a56fcf41564b48817ba42cd8a1aac7f0ddc
|
||||||
|
A_ARM:
|
||||||
|
Linux_UnknownLinux:
|
||||||
|
unknown_versioning:
|
||||||
|
dlUri: https://downloads.haskell.org/~ghc/8.10.5/ghc-8.10.5-armv7-deb10-linux.tar.xz
|
||||||
|
dlSubdir: ghc-8.10.5
|
||||||
|
dlHash: 56170d1a8450e18b7eb9c23c94723da352815b27ec250bb23742a62f16dcab6c
|
||||||
9.0.1:
|
9.0.1:
|
||||||
viTags:
|
viTags:
|
||||||
- Latest
|
- Latest
|
||||||
@@ -1553,86 +1645,91 @@ ghcupDownloads:
|
|||||||
dlUri: https://downloads.haskell.org/~ghc/9.0.1/ghc-9.0.1-armv7-deb9-linux.tar.xz
|
dlUri: https://downloads.haskell.org/~ghc/9.0.1/ghc-9.0.1-armv7-deb9-linux.tar.xz
|
||||||
dlSubdir: ghc-9.0.1
|
dlSubdir: ghc-9.0.1
|
||||||
dlHash: 6f404f9b88468407b3a9ec5800bcc2d01dd453ef3d63414853b4fbbd4d8df496
|
dlHash: 6f404f9b88468407b3a9ec5800bcc2d01dd453ef3d63414853b4fbbd4d8df496
|
||||||
9.2.0.20210331:
|
9.2.0.20210422:
|
||||||
viTags:
|
viTags:
|
||||||
- Prerelease
|
- Prerelease
|
||||||
- base-4.16.0.0
|
- base-4.16.0.0
|
||||||
viChangeLog: https://downloads.haskell.org/~ghc/9.2.1-alpha1/docs/html/users_guide/9.2.1-notes.html
|
viChangeLog: https://downloads.haskell.org/~ghc/9.2.1-alpha2/docs/html/users_guide/index.html
|
||||||
viSourceDL:
|
viSourceDL:
|
||||||
dlUri: https://downloads.haskell.org/~ghc/9.2.1-alpha1/ghc-9.2.0.20210331-src.tar.xz
|
dlUri: https://downloads.haskell.org/~ghc/9.2.1-alpha2/ghc-9.2.0.20210422-src.tar.xz
|
||||||
dlSubdir: ghc-9.2.0.20210331
|
dlSubdir: ghc-9.2.0.20210422
|
||||||
dlHash: 3ec8ec2fb77e14d68ac1c092f3e8605b6822e24f7e6dc7139dccf8feaf168699
|
dlHash: 69be189e6e7f8d51a9078ac8f177176bc5bff54edc8352974c50c1f0e110df27
|
||||||
viPostRemove: *ghc-post-remove
|
viPostRemove: *ghc-post-remove
|
||||||
viArch:
|
viArch:
|
||||||
A_64:
|
A_64:
|
||||||
Linux_Debian:
|
Linux_Debian:
|
||||||
'( >= 9 && < 10 )': &ghc-921-alpha1-64-deb9
|
'( >= 9 && < 10 )': &ghc-921-alpha2-64-deb9
|
||||||
dlUri: https://downloads.haskell.org/~ghc/9.2.1-alpha1/ghc-9.2.0.20210331-x86_64-deb9-linux.tar.xz
|
dlUri: https://downloads.haskell.org/~ghc/9.2.1-alpha2/ghc-9.2.0.20210422-x86_64-deb9-linux.tar.xz
|
||||||
dlSubdir: ghc-9.2.0.20210331
|
dlSubdir: ghc-9.2.0.20210422
|
||||||
dlHash: c13613cb6285a689c5b89c93fad5c6c0e95d66c8936338c44d92a1312f507006
|
dlHash: 7262f3a230cd6945c588882e03941301877a9eb12e58c5975ad264596c2e12f2
|
||||||
'( >= 10 && < 11 )': &ghc-921-alpha1-64-deb10
|
'( >= 10 && < 11 )': &ghc-921-alpha2-64-deb10
|
||||||
dlUri: https://downloads.haskell.org/~ghc/9.2.1-alpha1/ghc-9.2.0.20210331-x86_64-deb10-linux.tar.xz
|
dlUri: https://downloads.haskell.org/~ghc/9.2.1-alpha2/ghc-9.2.0.20210422-x86_64-deb10-linux.tar.xz
|
||||||
dlSubdir: ghc-9.2.0.20210331
|
dlSubdir: ghc-9.2.0.20210422
|
||||||
dlHash: 2b2a0e2bad54d1a41440c093a199207b58ff314bea7edf73387916e9952d6a53
|
dlHash: 6d36cd08576bdee7473fee66b4b8ceb72011983a7d5aa3ec587403815a73e37b
|
||||||
unknown_versioning: *ghc-921-alpha1-64-deb9
|
unknown_versioning: *ghc-921-alpha2-64-deb9
|
||||||
Linux_Ubuntu:
|
Linux_Ubuntu:
|
||||||
unknown_versioning: &ghc-921-alpha1-64-fedora
|
unknown_versioning: &ghc-921-alpha2-64-fedora
|
||||||
dlUri: https://downloads.haskell.org/~ghc/9.2.1-alpha1/ghc-9.2.0.20210331-x86_64-fedora27-linux.tar.xz
|
dlUri: https://downloads.haskell.org/~ghc/9.2.1-alpha2/ghc-9.2.0.20210422-x86_64-fedora27-linux.tar.xz
|
||||||
dlSubdir: ghc-9.2.0.20210331
|
dlSubdir: ghc-9.2.0.20210422
|
||||||
dlHash: c7e648ac313c268aaa3a9651b00650da6eb293abfe14e44f44da22a758c233e7
|
dlHash: 95624192ff0982690bc9093632d6351fdc6f72e6df380b392449229c39a0354b
|
||||||
'( >= 16 && < 19 )': *ghc-921-alpha1-64-deb9
|
'( >= 16 && < 19 )': *ghc-921-alpha2-64-deb9
|
||||||
Linux_Mint:
|
Linux_Mint:
|
||||||
unknown_versioning: *ghc-921-alpha1-64-deb10
|
unknown_versioning: *ghc-921-alpha2-64-deb10
|
||||||
Linux_Fedora:
|
Linux_Fedora:
|
||||||
'( >= 27 && < 28 )': *ghc-921-alpha1-64-fedora
|
'( >= 27 && < 28 )': *ghc-921-alpha2-64-fedora
|
||||||
unknown_versioning: *ghc-921-alpha1-64-fedora
|
unknown_versioning: *ghc-921-alpha2-64-fedora
|
||||||
Linux_CentOS:
|
Linux_CentOS:
|
||||||
'( >= 7 && < 8 )': &ghc-921-alpha1-64-centos
|
'( >= 7 && < 8 )': &ghc-921-alpha2-64-centos
|
||||||
dlUri: https://downloads.haskell.org/~ghc/9.2.1-alpha1/ghc-9.2.0.20210331-x86_64-centos7-linux.tar.xz
|
dlUri: https://downloads.haskell.org/~ghc/9.2.1-alpha2/ghc-9.2.0.20210422-x86_64-centos7-linux.tar.xz
|
||||||
dlSubdir: ghc-9.2.0.20210331
|
dlSubdir: ghc-9.2.0.20210422
|
||||||
dlHash: 50556cc42be665957f2bd8e5deeceb26e58e88badfa0c99a44117fda2d63200c
|
dlHash: dee4f158f2d59bfe97ec3f5773b6b31aa911f9b128a5e56eeefa2dccc754d295
|
||||||
unknown_versioning: *ghc-921-alpha1-64-centos
|
unknown_versioning: *ghc-921-alpha2-64-centos
|
||||||
Linux_RedHat:
|
Linux_RedHat:
|
||||||
unknown_versioning: *ghc-921-alpha1-64-centos
|
unknown_versioning: *ghc-921-alpha2-64-centos
|
||||||
Linux_Alpine:
|
Linux_Alpine:
|
||||||
unknown_versioning:
|
unknown_versioning:
|
||||||
dlUri: https://downloads.haskell.org/~ghc/9.2.1-alpha1/ghc-9.2.0.20210331-x86_64-alpine3.10-linux-integer-simple.tar.xz
|
dlUri: https://downloads.haskell.org/~ghc/9.2.1-alpha2/ghc-9.2.0.20210422-x86_64-alpine3.10-linux-integer-simple.tar.xz
|
||||||
dlSubdir: ghc-9.2.0.20210331-x86_64-unknown-linux
|
dlSubdir: ghc-9.2.0.20210422-x86_64-unknown-linux
|
||||||
dlHash: bab5f5d0ecd6522da372a9a0f0eeebbbecf0bd94788847aa3cd5bdb36682d48a
|
dlHash: f61ae72925325ca7b316e40121e8d6bad94794016d3fa59bcbc8dbe116a7f13c
|
||||||
Linux_AmazonLinux:
|
Linux_AmazonLinux:
|
||||||
unknown_versioning: *ghc-921-alpha1-64-centos
|
unknown_versioning: *ghc-921-alpha2-64-centos
|
||||||
Linux_UnknownLinux:
|
Linux_UnknownLinux:
|
||||||
unknown_versioning: *ghc-921-alpha1-64-fedora
|
unknown_versioning: *ghc-921-alpha2-64-fedora
|
||||||
|
FreeBSD:
|
||||||
|
unknown_versioning:
|
||||||
|
dlUri: https://downloads.haskell.org/~ghc/9.2.1-alpha2/ghc-9.2.0.20210422-x86_64-unknown-freebsd.tar.xz
|
||||||
|
dlSubdir: ghc-9.2.0.20210422
|
||||||
|
dlHash: 195728e02398ea6154fe713b7782a0cae856eb0d9d90f5d09cd0cca610c985e2
|
||||||
Darwin:
|
Darwin:
|
||||||
unknown_versioning:
|
unknown_versioning:
|
||||||
dlUri: https://downloads.haskell.org/~ghc/9.2.1-alpha1/ghc-9.2.0.20210331-x86_64-apple-darwin.tar.xz
|
dlUri: https://downloads.haskell.org/~ghc/9.2.1-alpha2/ghc-9.2.0.20210422-x86_64-apple-darwin.tar.xz
|
||||||
dlSubdir: ghc-9.2.0.20210331
|
dlSubdir: ghc-9.2.0.20210422
|
||||||
dlHash: cfd7d0479ce80607c11cf96fe25d4804783c6ebc623ca9adcb5436e3499c9c5b
|
dlHash: 8884c059f2b76e4c4309ff6bd7a7dde37663f751fd26220e9a2bcabb4d69a401
|
||||||
A_32:
|
A_32:
|
||||||
Linux_Debian:
|
Linux_Debian:
|
||||||
'( >= 9 && < 10 )': &ghc-921-alpha1-32-deb9
|
'( >= 9 && < 10 )': &ghc-921-alpha2-32-deb9
|
||||||
dlUri: https://downloads.haskell.org/~ghc/9.2.1-alpha1/ghc-9.2.0.20210331-i386-deb9-linux.tar.xz
|
dlUri: https://downloads.haskell.org/~ghc/9.2.1-alpha2/ghc-9.2.0.20210422-i386-deb9-linux.tar.xz
|
||||||
dlSubdir: ghc-9.2.0.20210331
|
dlSubdir: ghc-9.2.0.20210422
|
||||||
dlHash: 58ccac8e89e60b4261dfa8ca0e17d335b99f2a1fecb90322436cfea3bdce2240
|
dlHash: a378ec3fd31a9fa2a7134e98159e189362fe969f04031515616e9cc3182c861a
|
||||||
unknown_versioning: *ghc-921-alpha1-32-deb9
|
unknown_versioning: *ghc-921-alpha2-32-deb9
|
||||||
Linux_Ubuntu:
|
Linux_Ubuntu:
|
||||||
unknown_versioning: *ghc-921-alpha1-32-deb9
|
unknown_versioning: *ghc-921-alpha2-32-deb9
|
||||||
Linux_Mint:
|
Linux_Mint:
|
||||||
unknown_versioning: *ghc-921-alpha1-32-deb9
|
unknown_versioning: *ghc-921-alpha2-32-deb9
|
||||||
Linux_UnknownLinux:
|
Linux_UnknownLinux:
|
||||||
unknown_versioning: *ghc-921-alpha1-32-deb9
|
unknown_versioning: *ghc-921-alpha2-32-deb9
|
||||||
A_ARM64:
|
A_ARM64:
|
||||||
Linux_UnknownLinux:
|
Linux_UnknownLinux:
|
||||||
unknown_versioning:
|
unknown_versioning:
|
||||||
dlUri: https://downloads.haskell.org/~ghc/9.2.1-alpha1/ghc-9.2.0.20210331-aarch64-deb10-linux.tar.xz
|
dlUri: https://downloads.haskell.org/~ghc/9.2.1-alpha2/ghc-9.2.0.20210422-aarch64-deb10-linux.tar.xz
|
||||||
dlSubdir: ghc-9.2.0.20210331
|
dlSubdir: ghc-9.2.0.20210422
|
||||||
dlHash: df355e1ed34cf0fef11444299020041f03d6c67f6c5c342db1f76b71fd31e6fe
|
dlHash: fd2f4d0f6122f752aca396fe1a13e7d14d037dc45806bb0404a031eeeeb1994c
|
||||||
A_ARM:
|
A_ARM:
|
||||||
Linux_UnknownLinux:
|
Linux_UnknownLinux:
|
||||||
unknown_versioning:
|
unknown_versioning:
|
||||||
dlUri: https://downloads.haskell.org/~ghc/9.2.1-alpha1/ghc-9.2.0.20210331-armv7-deb10-linux.tar.xz
|
dlUri: https://downloads.haskell.org/~ghc/9.2.1-alpha2/ghc-9.2.0.20210422-armv7-deb10-linux.tar.xz
|
||||||
dlSubdir: ghc-9.2.0.20210331
|
dlSubdir: ghc-9.2.0.20210422
|
||||||
dlHash: 2c5133fb83943371ad8556328db4acb9081271b7c77ceaf2b74817dd0de3b486
|
dlHash: dab7d7785d6ccafb130526b666669fc974ba5c90fc9aaf2024f9c65bcbd097d3
|
||||||
Cabal:
|
Cabal:
|
||||||
2.4.1.0:
|
2.4.1.0:
|
||||||
viTags:
|
viTags:
|
||||||
@@ -1755,13 +1852,11 @@ ghcupDownloads:
|
|||||||
dlHash: a1e2db664ec00e42a1e071a4181f6476f6e0bad321f1ddc0cf27831119f4c6d4
|
dlHash: a1e2db664ec00e42a1e071a4181f6476f6e0bad321f1ddc0cf27831119f4c6d4
|
||||||
A_32:
|
A_32:
|
||||||
Linux_UnknownLinux:
|
Linux_UnknownLinux:
|
||||||
unknown_versioning:
|
unknown_versioning: &cabal-3400-32
|
||||||
dlUri: https://downloads.haskell.org/~cabal/cabal-install-3.4.0.0/cabal-install-3.4.0.0-i386-debian-9.tar.xz
|
dlUri: https://downloads.haskell.org/~ghcup/unofficial-bindists/cabal/3.4.0.0/cabal-install-3.4.0.0-i386-unknown-linux.tar.xz
|
||||||
dlHash: ef3750644a53f7b1fad141b2ad02d4c7a3b239ec0cbfa7f0528fb02c1dfcebce
|
dlHash: cc62a471e9e68a6a9933e54f75bf0cffae67a1d2220df1152ab887c38eb6bc8a
|
||||||
Linux_Alpine:
|
Linux_Alpine:
|
||||||
unknown_versioning:
|
unknown_versioning: *cabal-3400-32
|
||||||
dlUri: https://downloads.haskell.org/ghcup/unofficial-bindists/cabal/3.4.0.0/cabal-install-3.4.0.0-i386-alpine-linux-musl.tar.gz
|
|
||||||
dlHash: 95adb65f3a72aa8d9ce83685bc06e1eee5b801f56e204e27e957e8a35abd9cf8
|
|
||||||
A_ARM64:
|
A_ARM64:
|
||||||
Linux_UnknownLinux:
|
Linux_UnknownLinux:
|
||||||
unknown_versioning:
|
unknown_versioning:
|
||||||
@@ -1773,7 +1868,7 @@ ghcupDownloads:
|
|||||||
dlUri: https://downloads.haskell.org/~ghcup/unofficial-bindists/cabal/3.4.0.0/cabal-install-3.4.0.0-armv7-linux-bootstrapped.tar.xz
|
dlUri: https://downloads.haskell.org/~ghcup/unofficial-bindists/cabal/3.4.0.0/cabal-install-3.4.0.0-armv7-linux-bootstrapped.tar.xz
|
||||||
dlHash: 16c0d1eaba24bed14f3e152970179a45d9f9bb5cc839b2c210ad06eb7d4826ed
|
dlHash: 16c0d1eaba24bed14f3e152970179a45d9f9bb5cc839b2c210ad06eb7d4826ed
|
||||||
GHCup:
|
GHCup:
|
||||||
0.1.14:
|
0.1.16.1:
|
||||||
viTags:
|
viTags:
|
||||||
- Recommended
|
- Recommended
|
||||||
- Latest
|
- Latest
|
||||||
@@ -1783,51 +1878,55 @@ ghcupDownloads:
|
|||||||
A_64:
|
A_64:
|
||||||
Linux_UnknownLinux:
|
Linux_UnknownLinux:
|
||||||
unknown_versioning: &ghcup-64
|
unknown_versioning: &ghcup-64
|
||||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.14/x86_64-linux-ghcup-0.1.14
|
dlUri: https://downloads.haskell.org/~ghcup/0.1.16.1/x86_64-linux-ghcup-0.1.16.1
|
||||||
dlHash: e9b314d248f4d4604ce64cee1be7161c77c8940efd11986c9205779ec3b598dd
|
dlHash: c3505d929722e245b22ec7a05267f1ae8e04089e139bbb470783eb9a1b648f83
|
||||||
Darwin:
|
Darwin:
|
||||||
unknown_versioning:
|
unknown_versioning:
|
||||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.14/x86_64-apple-darwin-ghcup-0.1.14
|
dlUri: https://downloads.haskell.org/~ghcup/0.1.16.1/x86_64-apple-darwin-ghcup-0.1.16.1
|
||||||
dlHash: 69ede9db36c0ae631b679fceb87dd856d4753ee26f33610da37dd7a694809919
|
dlHash: 7edde6bb42323232d28495abbe630321d7eb8e3827e200438a9ae4c41e531e71
|
||||||
FreeBSD:
|
FreeBSD:
|
||||||
unknown_versioning:
|
unknown_versioning:
|
||||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.14/x86_64-portbld-freebsd-ghcup-0.1.14
|
dlUri: https://downloads.haskell.org/~ghcup/0.1.16.1/x86_64-portbld-freebsd-ghcup-0.1.16.1
|
||||||
dlHash: 68b09404cf49061da539463f42f8ad67c9cef5c5d3f68a3c7c4f6760e8442bb9
|
dlHash: 6b7fc3a52e859f186d30b04c823fd0c5997179222fe9aa510a33435f41599f5c
|
||||||
Linux_Alpine:
|
Linux_Alpine:
|
||||||
unknown_versioning: *ghcup-64
|
unknown_versioning: *ghcup-64
|
||||||
A_32:
|
A_32:
|
||||||
Linux_UnknownLinux:
|
Linux_UnknownLinux:
|
||||||
unknown_versioning: &ghcup-32
|
unknown_versioning: &ghcup-32
|
||||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.14/i386-linux-ghcup-0.1.14
|
dlUri: https://downloads.haskell.org/~ghcup/0.1.16.1/i386-linux-ghcup-0.1.16.1
|
||||||
dlHash: ecb1157f010d2421764c52ab0cdbbf9a5c3da555827172c7b904d5f3f96c80fa
|
dlHash: 93ca5d77247b6ecac01be75e9ef5454adbb503b7957b8e9c59a5abd2046aef3c
|
||||||
Linux_Alpine:
|
Linux_Alpine:
|
||||||
unknown_versioning: *ghcup-32
|
unknown_versioning: *ghcup-32
|
||||||
A_ARM64:
|
A_ARM64:
|
||||||
Linux_UnknownLinux:
|
Linux_UnknownLinux:
|
||||||
unknown_versioning:
|
unknown_versioning:
|
||||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.14/aarch64-linux-ghcup-0.1.14
|
dlUri: https://downloads.haskell.org/~ghcup/0.1.16.1/aarch64-linux-ghcup-0.1.16.1
|
||||||
dlHash: 78a15f8a03917a89b67536af0993d7526d2722248a3a5cd8c500adffd7cd7691
|
dlHash: 31fecbb704e9e2474804f42817ab17bfac28e32e5aeba93ae3f4c77fbc105706
|
||||||
|
Darwin:
|
||||||
|
unknown_versioning:
|
||||||
|
dlUri: https://downloads.haskell.org/~ghcup/0.1.16.1/aarch64-apple-darwin-ghcup-0.1.16.1
|
||||||
|
dlHash: 52eb69a5693abf6c18f95a3b9bf4dac59696299d690c6397bd22a9091e76d40e
|
||||||
A_ARM:
|
A_ARM:
|
||||||
Linux_UnknownLinux:
|
Linux_UnknownLinux:
|
||||||
unknown_versioning:
|
unknown_versioning:
|
||||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.14/armv7-linux-ghcup-0.1.14
|
dlUri: https://downloads.haskell.org/~ghcup/0.1.16.1/armv7-linux-ghcup-0.1.16.1
|
||||||
dlHash: 5484dc9e16553c3d1707a9f83404c3c795dc01d01ef998cf173caf960abe793b
|
dlHash: 795dd2032f0f4e4ea9688cd49393aba4c40c9eae84c8dea3477f5f440f750767
|
||||||
HLS:
|
HLS:
|
||||||
1.0.0:
|
1.1.0:
|
||||||
viTags:
|
viTags:
|
||||||
- Recommended
|
- Recommended
|
||||||
- Latest
|
- Latest
|
||||||
viChangeLog: https://github.com/haskell/haskell-language-server/blob/master/ChangeLog.md#100
|
viChangeLog: https://github.com/haskell/haskell-language-server/blob/master/ChangeLog.md#110
|
||||||
viPostInstall: "This is just the server part of your LSP configuration. Consult the README on how to configure HLS, your project and your LSP client in your editor: https://github.com/haskell/haskell-language-server/blob/master/README.md"
|
viPostInstall: "This is just the server part of your LSP configuration. Consult the README on how to configure HLS, your project and your LSP client in your editor: https://github.com/haskell/haskell-language-server/blob/master/README.md"
|
||||||
viArch:
|
viArch:
|
||||||
A_64:
|
A_64:
|
||||||
Linux_UnknownLinux:
|
Linux_UnknownLinux:
|
||||||
unknown_versioning: &hls-64
|
unknown_versioning: &hls-64
|
||||||
dlUri: https://github.com/haskell/haskell-language-server/releases/download/1.0.0/haskell-language-server-Linux-1.0.0.tar.gz
|
dlUri: https://github.com/haskell/haskell-language-server/releases/download/1.1.0/haskell-language-server-Linux-1.1.0.tar.gz
|
||||||
dlHash: 4fab18998c5f67118a26b75b059f3b3e2ad345b6325515a552d1a24cdf87ed3f
|
dlHash: 0f0dadb0e9a08273658f565fd71c636801959b954be2737f38f2a1aac522208f
|
||||||
Darwin:
|
Darwin:
|
||||||
unknown_versioning:
|
unknown_versioning:
|
||||||
dlUri: https://github.com/haskell/haskell-language-server/releases/download/1.0.0/haskell-language-server-macOS-1.0.0.tar.gz
|
dlUri: https://github.com/haskell/haskell-language-server/releases/download/1.1.0/haskell-language-server-macOS-1.1.0.tar.gz
|
||||||
dlHash: 74e7624c889c0235f0b02d7e7f164d5eb95b611d584fc8602f0b3a099b73f8be
|
dlHash: 4e89b192e2f49637d772e974f2c17b16da067ecd5912575eaa542551de97681b
|
||||||
Linux_Alpine:
|
Linux_Alpine:
|
||||||
unknown_versioning: *hls-64
|
unknown_versioning: *hls-64
|
||||||
|
|||||||
2235
ghcup-0.0.5.yaml
Normal file
2235
ghcup-0.0.5.yaml
Normal file
File diff suppressed because it is too large
Load Diff
2235
ghcup-0.0.6.yaml
Normal file
2235
ghcup-0.0.6.yaml
Normal file
File diff suppressed because it is too large
Load Diff
138
ghcup.cabal
138
ghcup.cabal
@@ -1,6 +1,6 @@
|
|||||||
cabal-version: 3.0
|
cabal-version: 3.0
|
||||||
name: ghcup
|
name: ghcup
|
||||||
version: 0.1.14
|
version: 0.1.16.1
|
||||||
license: LGPL-3.0-only
|
license: LGPL-3.0-only
|
||||||
license-file: LICENSE
|
license-file: LICENSE
|
||||||
copyright: Julian Ospald 2020
|
copyright: Julian Ospald 2020
|
||||||
@@ -8,33 +8,43 @@ maintainer: hasufell@posteo.de
|
|||||||
author: Julian Ospald
|
author: Julian Ospald
|
||||||
homepage: https://gitlab.haskell.org/haskell/ghcup-hs
|
homepage: https://gitlab.haskell.org/haskell/ghcup-hs
|
||||||
bug-reports: https://gitlab.haskell.org/haskell/ghcup-hs/issues
|
bug-reports: https://gitlab.haskell.org/haskell/ghcup-hs/issues
|
||||||
synopsis: ghc toolchain installer as an exe/library
|
synopsis: ghc toolchain installer
|
||||||
description:
|
description:
|
||||||
A rewrite of the shell script ghcup, for providing
|
A rewrite of the shell script ghcup, for providing
|
||||||
a more stable user experience and exposing an API.
|
a more stable user experience and exposing an API.
|
||||||
|
|
||||||
category: System
|
category: System
|
||||||
build-type: Simple
|
build-type: Simple
|
||||||
extra-doc-files: CHANGELOG.md
|
extra-doc-files:
|
||||||
|
CHANGELOG.md
|
||||||
|
config.yaml
|
||||||
|
ghcup-0.0.4.yaml
|
||||||
|
ghcup-0.0.5.yaml
|
||||||
|
ghcup-0.0.6.yaml
|
||||||
|
HACKING.md
|
||||||
|
README.md
|
||||||
|
RELEASING.md
|
||||||
|
|
||||||
source-repository head
|
source-repository head
|
||||||
type: git
|
type: git
|
||||||
location: https://gitlab.haskell.org/haskell/ghcup-hs.git
|
location: https://gitlab.haskell.org/haskell/ghcup-hs.git
|
||||||
|
|
||||||
flag tui
|
flag tui
|
||||||
description: Build the brick powered tui (ghcup tui)
|
description:
|
||||||
|
Build the brick powered tui (ghcup tui). This is disabled on windows.
|
||||||
|
|
||||||
default: False
|
default: False
|
||||||
manual: True
|
manual: True
|
||||||
|
|
||||||
flag internal-downloader
|
flag internal-downloader
|
||||||
description:
|
description:
|
||||||
Compile the internal downloader, which links against OpenSSL
|
Compile the internal downloader, which links against OpenSSL. This is disabled on windows.
|
||||||
|
|
||||||
default: False
|
default: False
|
||||||
manual: True
|
manual: True
|
||||||
|
|
||||||
flag tar
|
flag tar
|
||||||
description: Use tar-bytestring instead of libarchive
|
description: Use tar-bytestring instead of libarchive.
|
||||||
default: False
|
default: False
|
||||||
manual: True
|
manual: True
|
||||||
|
|
||||||
@@ -52,6 +62,7 @@ library
|
|||||||
GHCup.Utils
|
GHCup.Utils
|
||||||
GHCup.Utils.Dirs
|
GHCup.Utils.Dirs
|
||||||
GHCup.Utils.File
|
GHCup.Utils.File
|
||||||
|
GHCup.Utils.File.Common
|
||||||
GHCup.Utils.Logger
|
GHCup.Utils.Logger
|
||||||
GHCup.Utils.MegaParsec
|
GHCup.Utils.MegaParsec
|
||||||
GHCup.Utils.Prelude
|
GHCup.Utils.Prelude
|
||||||
@@ -64,14 +75,19 @@ library
|
|||||||
autogen-modules: Paths_ghcup
|
autogen-modules: Paths_ghcup
|
||||||
default-language: Haskell2010
|
default-language: Haskell2010
|
||||||
default-extensions:
|
default-extensions:
|
||||||
|
DeriveGeneric
|
||||||
LambdaCase
|
LambdaCase
|
||||||
MultiWayIf
|
MultiWayIf
|
||||||
|
NamedFieldPuns
|
||||||
PackageImports
|
PackageImports
|
||||||
|
QuasiQuotes
|
||||||
RecordWildCards
|
RecordWildCards
|
||||||
ScopedTypeVariables
|
ScopedTypeVariables
|
||||||
Strict
|
|
||||||
StrictData
|
StrictData
|
||||||
TupleSections
|
TupleSections
|
||||||
|
TypeApplications
|
||||||
|
TypeFamilies
|
||||||
|
ViewPatterns
|
||||||
|
|
||||||
ghc-options:
|
ghc-options:
|
||||||
-Wall -fwarn-tabs -fwarn-incomplete-uni-patterns
|
-Wall -fwarn-tabs -fwarn-incomplete-uni-patterns
|
||||||
@@ -79,31 +95,29 @@ library
|
|||||||
|
|
||||||
build-depends:
|
build-depends:
|
||||||
, aeson >=1.4 && <1.6
|
, aeson >=1.4 && <1.6
|
||||||
, ascii-string ^>=1.0
|
|
||||||
, async >=0.8 && <2.3
|
, async >=0.8 && <2.3
|
||||||
, base >=4.13 && <5
|
, base >=4.13 && <5
|
||||||
, base16-bytestring >=0.1.1.6 && <1.1
|
, base16-bytestring >=0.1.1.6 && <1.1
|
||||||
, binary ^>=0.8.6.0
|
, binary ^>=0.8.6.0
|
||||||
, bytestring ^>=0.10
|
, bytestring ^>=0.10
|
||||||
, bz2 >=0.5.0.5 && <1.1
|
|
||||||
, case-insensitive ^>=1.2.1.0
|
, case-insensitive ^>=1.2.1.0
|
||||||
, casing ^>=0.1.4.1
|
, casing ^>=0.1.4.1
|
||||||
, concurrent-output ^>=1.10.11
|
, concurrent-output ^>=1.10.11
|
||||||
, containers ^>=0.6
|
, containers ^>=0.6
|
||||||
, cryptohash-sha256 ^>=0.11.101.0
|
, cryptohash-sha256 ^>=0.11.101.0
|
||||||
|
, deepseq ^>=1.4.4.0
|
||||||
|
, directory ^>=1.3.6.0
|
||||||
|
, disk-free-space ^>=0.1.0.1
|
||||||
|
, extra ^>=1.7.9
|
||||||
|
, filepath ^>=1.4.2.1
|
||||||
, generics-sop ^>=0.5
|
, generics-sop ^>=0.5
|
||||||
, haskus-utils-types ^>=1.5
|
, haskus-utils-types ^>=1.5
|
||||||
, haskus-utils-variant >=3.0 && <3.2
|
, haskus-utils-variant >=3.0 && <3.2
|
||||||
, hpath >=0.11 && <0.13
|
, lzma-static ^>=5.2.5.3
|
||||||
, hpath-directory ^>=0.14.1
|
|
||||||
, hpath-filepath ^>=0.10.3
|
|
||||||
, hpath-io ^>=0.14.1
|
|
||||||
, hpath-posix ^>=0.13.2
|
|
||||||
, lzma-static ^>=5.2.5.2
|
|
||||||
, megaparsec >=8.0.0 && <9.1
|
, megaparsec >=8.0.0 && <9.1
|
||||||
, monad-logger ^>=0.3.31
|
, monad-logger ^>=0.3.31
|
||||||
, mtl ^>=2.2
|
, mtl ^>=2.2
|
||||||
, optics >=0.2 && <0.5
|
, optics ^>=0.4
|
||||||
, optics-vl ^>=0.2
|
, optics-vl ^>=0.2
|
||||||
, os-release ^>=1.0.0
|
, os-release ^>=1.0.0
|
||||||
, parsec ^>=3.1
|
, parsec ^>=3.1
|
||||||
@@ -114,43 +128,62 @@ library
|
|||||||
, safe ^>=0.3.18
|
, safe ^>=0.3.18
|
||||||
, safe-exceptions ^>=0.1
|
, safe-exceptions ^>=0.1
|
||||||
, split ^>=0.2.3.4
|
, split ^>=0.2.3.4
|
||||||
, streamly ^>=0.7.3
|
|
||||||
, streamly-bytestring ^>=0.1.2
|
|
||||||
, streamly-posix ^>=0.1.0.0
|
|
||||||
, strict-base ^>=0.4
|
, strict-base ^>=0.4
|
||||||
, string-interpolate >=0.2.0.0 && <0.4
|
, string-interpolate >=0.2.0.0 && <0.4
|
||||||
, template-haskell >=2.7 && <2.17
|
, template-haskell >=2.7 && <2.18
|
||||||
|
, temporary ^>=1.3
|
||||||
, text ^>=1.2.4.0
|
, text ^>=1.2.4.0
|
||||||
, time ^>=1.9.3
|
, time ^>=1.9.3
|
||||||
, transformers ^>=0.5
|
, transformers ^>=0.5
|
||||||
, unix ^>=2.7
|
, unliftio-core ^>=0.2.0.1
|
||||||
, unix-bytestring ^>=0.3
|
|
||||||
, unordered-containers ^>=0.2.10.0
|
, unordered-containers ^>=0.2.10.0
|
||||||
, uri-bytestring ^>=0.3.2.2
|
, uri-bytestring ^>=0.3.2.2
|
||||||
, utf8-string ^>=1.0
|
, utf8-string ^>=1.0
|
||||||
, vector ^>=0.12
|
, vector ^>=0.12
|
||||||
, versions ^>=4.0.1
|
, versions >=4.0.1 && <5.1
|
||||||
, vty >=5.28.2 && <5.34
|
|
||||||
, word8 ^>=0.1.3
|
, word8 ^>=0.1.3
|
||||||
, yaml ^>=0.11.4.0
|
, yaml ^>=0.11.4.0
|
||||||
|
, zip ^>=1.7.1
|
||||||
, zlib ^>=0.6.2.2
|
, zlib ^>=0.6.2.2
|
||||||
|
|
||||||
if flag(internal-downloader)
|
if (flag(internal-downloader) && !os(windows))
|
||||||
exposed-modules: GHCup.Download.IOStreams
|
exposed-modules: GHCup.Download.IOStreams
|
||||||
cpp-options: -DINTERNAL_DOWNLOADER
|
cpp-options: -DINTERNAL_DOWNLOADER
|
||||||
build-depends:
|
build-depends:
|
||||||
, HsOpenSSL >=0.11.4.18
|
, HsOpenSSL >=0.11.4.18
|
||||||
, http-io-streams >=0.1.2.0
|
, http-io-streams >=0.1.2.0
|
||||||
, io-streams >=1.5
|
, io-streams >=1.5.2.1
|
||||||
, terminal-progress-bar >=0.4.1
|
, terminal-progress-bar >=0.4.1
|
||||||
|
|
||||||
if flag(tar)
|
if flag(tar)
|
||||||
cpp-options: -DTAR
|
cpp-options: -DTAR
|
||||||
build-depends: tar-bytestring ^>=0.6.3.1
|
build-depends: tar
|
||||||
|
|
||||||
else
|
else
|
||||||
build-depends: libarchive ^>=3.0.0.0
|
build-depends: libarchive ^>=3.0.0.0
|
||||||
|
|
||||||
|
if os(windows)
|
||||||
|
cpp-options: -DIS_WINDOWS
|
||||||
|
other-modules: GHCup.Utils.File.Windows
|
||||||
|
build-depends:
|
||||||
|
, bzlib
|
||||||
|
, process ^>=1.6.11.0
|
||||||
|
, retry ^>=0.8.1.2
|
||||||
|
, Win32 ^>=2.10
|
||||||
|
|
||||||
|
else
|
||||||
|
other-modules: GHCup.Utils.File.Posix
|
||||||
|
build-depends:
|
||||||
|
, bz2 >=0.5.0.5 && <1.1
|
||||||
|
, hpath-posix ^>=0.13.3
|
||||||
|
, process ^>=1.6.9
|
||||||
|
, unix ^>=2.7
|
||||||
|
, unix-bytestring ^>=0.3.7.3
|
||||||
|
|
||||||
|
if (flag(tui) && !os(windows))
|
||||||
|
cpp-options: -DBRICK
|
||||||
|
build-depends: vty >=5.28.2 && <5.34
|
||||||
|
|
||||||
executable ghcup
|
executable ghcup
|
||||||
main-is: Main.hs
|
main-is: Main.hs
|
||||||
hs-source-dirs: app/ghcup
|
hs-source-dirs: app/ghcup
|
||||||
@@ -158,10 +191,10 @@ executable ghcup
|
|||||||
default-extensions:
|
default-extensions:
|
||||||
LambdaCase
|
LambdaCase
|
||||||
MultiWayIf
|
MultiWayIf
|
||||||
|
NamedFieldPuns
|
||||||
PackageImports
|
PackageImports
|
||||||
RecordWildCards
|
RecordWildCards
|
||||||
ScopedTypeVariables
|
ScopedTypeVariables
|
||||||
Strict
|
|
||||||
StrictData
|
StrictData
|
||||||
TupleSections
|
TupleSections
|
||||||
|
|
||||||
@@ -170,14 +203,14 @@ executable ghcup
|
|||||||
-fwarn-incomplete-record-updates -threaded
|
-fwarn-incomplete-record-updates -threaded
|
||||||
|
|
||||||
build-depends:
|
build-depends:
|
||||||
, aeson >=1.4 && <1.6
|
, async ^>=2.2.3
|
||||||
, base >=4.13 && <5
|
, base >=4.13 && <5
|
||||||
, bytestring ^>=0.10
|
, bytestring ^>=0.10
|
||||||
, containers ^>=0.6
|
, containers ^>=0.6
|
||||||
|
, deepseq ^>=1.4
|
||||||
|
, filepath ^>=1.4.2.1
|
||||||
, ghcup
|
, ghcup
|
||||||
, haskus-utils-variant >=3.0 && <3.2
|
, haskus-utils-variant >=3.0 && <3.2
|
||||||
, hpath >=0.11 && <0.13
|
|
||||||
, hpath-io ^>=0.14.1
|
|
||||||
, megaparsec >=8.0.0 && <9.1
|
, megaparsec >=8.0.0 && <9.1
|
||||||
, monad-logger ^>=0.3.31
|
, monad-logger ^>=0.3.31
|
||||||
, mtl ^>=2.2
|
, mtl ^>=2.2
|
||||||
@@ -188,22 +221,26 @@ executable ghcup
|
|||||||
, safe ^>=0.3.18
|
, safe ^>=0.3.18
|
||||||
, safe-exceptions ^>=0.1
|
, safe-exceptions ^>=0.1
|
||||||
, string-interpolate >=0.2.0.0 && <0.4
|
, string-interpolate >=0.2.0.0 && <0.4
|
||||||
, template-haskell >=2.7 && <2.17
|
, template-haskell >=2.7 && <2.18
|
||||||
, text ^>=1.2.4.0
|
, text ^>=1.2.4.0
|
||||||
, uri-bytestring ^>=0.3.2.2
|
, uri-bytestring ^>=0.3.2.2
|
||||||
, utf8-string ^>=1.0
|
, utf8-string ^>=1.0
|
||||||
, versions ^>=4.0.1
|
, versions >=4.0.1 && <5.1
|
||||||
|
|
||||||
if flag(internal-downloader)
|
if flag(internal-downloader)
|
||||||
cpp-options: -DINTERNAL_DOWNLOADER
|
cpp-options: -DINTERNAL_DOWNLOADER
|
||||||
|
|
||||||
if flag(tui)
|
if (flag(tui) && !os(windows))
|
||||||
cpp-options: -DBRICK
|
cpp-options: -DBRICK
|
||||||
other-modules: BrickMain
|
other-modules: BrickMain
|
||||||
build-depends:
|
build-depends:
|
||||||
, brick >=0.5 && <0.62
|
, brick >=0.5 && <0.64
|
||||||
, vector ^>=0.12
|
, transformers ^>=0.5
|
||||||
, vty >=5.28.2 && <5.34
|
, vector ^>=0.12
|
||||||
|
, vty >=5.28.2 && <5.34
|
||||||
|
|
||||||
|
if os(windows)
|
||||||
|
cpp-options: -DIS_WINDOWS
|
||||||
|
|
||||||
if flag(tar)
|
if flag(tar)
|
||||||
cpp-options: -DTAR
|
cpp-options: -DTAR
|
||||||
@@ -217,30 +254,34 @@ executable ghcup-gen
|
|||||||
other-modules: Validate
|
other-modules: Validate
|
||||||
default-language: Haskell2010
|
default-language: Haskell2010
|
||||||
default-extensions:
|
default-extensions:
|
||||||
|
DeriveGeneric
|
||||||
LambdaCase
|
LambdaCase
|
||||||
MultiWayIf
|
MultiWayIf
|
||||||
|
NamedFieldPuns
|
||||||
PackageImports
|
PackageImports
|
||||||
|
QuasiQuotes
|
||||||
RecordWildCards
|
RecordWildCards
|
||||||
ScopedTypeVariables
|
ScopedTypeVariables
|
||||||
|
StrictData
|
||||||
TupleSections
|
TupleSections
|
||||||
|
TypeApplications
|
||||||
|
TypeFamilies
|
||||||
|
ViewPatterns
|
||||||
|
|
||||||
ghc-options:
|
ghc-options:
|
||||||
-Wall -fwarn-tabs -fwarn-incomplete-uni-patterns
|
-Wall -fwarn-tabs -fwarn-incomplete-uni-patterns
|
||||||
-fwarn-incomplete-record-updates -threaded
|
-fwarn-incomplete-record-updates -threaded
|
||||||
|
|
||||||
build-depends:
|
build-depends:
|
||||||
, aeson >=1.4 && <1.6
|
|
||||||
, aeson-pretty ^>=0.8.8
|
|
||||||
, base >=4.13 && <5
|
, base >=4.13 && <5
|
||||||
, bytestring ^>=0.10
|
, bytestring ^>=0.10
|
||||||
, containers ^>=0.6
|
, containers ^>=0.6
|
||||||
|
, filepath ^>=1.4.2.1
|
||||||
, ghcup
|
, ghcup
|
||||||
, haskus-utils-variant >=3.0 && <3.2
|
, haskus-utils-variant >=3.0 && <3.2
|
||||||
, hpath >=0.11 && <0.13
|
|
||||||
, hpath-filepath ^>=0.10.3
|
|
||||||
, monad-logger ^>=0.3.31
|
, monad-logger ^>=0.3.31
|
||||||
, mtl ^>=2.2
|
, mtl ^>=2.2
|
||||||
, optics >=0.2 && <0.5
|
, optics ^>=0.4
|
||||||
, optparse-applicative >=0.15.1.0 && <0.17
|
, optparse-applicative >=0.15.1.0 && <0.17
|
||||||
, pretty ^>=1.1.3.1
|
, pretty ^>=1.1.3.1
|
||||||
, pretty-terminal ^>=0.1.0.0
|
, pretty-terminal ^>=0.1.0.0
|
||||||
@@ -251,13 +292,12 @@ executable ghcup-gen
|
|||||||
, text ^>=1.2.4.0
|
, text ^>=1.2.4.0
|
||||||
, transformers ^>=0.5
|
, transformers ^>=0.5
|
||||||
, uri-bytestring ^>=0.3.2.2
|
, uri-bytestring ^>=0.3.2.2
|
||||||
, utf8-string ^>=1.0
|
, versions >=4.0.1 && <5.1
|
||||||
, versions ^>=4.0.1
|
|
||||||
, yaml ^>=0.11.4.0
|
, yaml ^>=0.11.4.0
|
||||||
|
|
||||||
if flag(tar)
|
if flag(tar)
|
||||||
cpp-options: -DTAR
|
cpp-options: -DTAR
|
||||||
build-depends: tar-bytestring ^>=0.6.3.1
|
build-depends: tar
|
||||||
|
|
||||||
else
|
else
|
||||||
build-depends: libarchive ^>=3.0.0.0
|
build-depends: libarchive ^>=3.0.0.0
|
||||||
@@ -265,6 +305,7 @@ executable ghcup-gen
|
|||||||
test-suite ghcup-test
|
test-suite ghcup-test
|
||||||
type: exitcode-stdio-1.0
|
type: exitcode-stdio-1.0
|
||||||
main-is: Main.hs
|
main-is: Main.hs
|
||||||
|
build-tool-depends: hspec-discover:hspec-discover -any
|
||||||
hs-source-dirs: test
|
hs-source-dirs: test
|
||||||
other-modules:
|
other-modules:
|
||||||
GHCup.ArbitraryTypes
|
GHCup.ArbitraryTypes
|
||||||
@@ -290,11 +331,10 @@ test-suite ghcup-test
|
|||||||
, containers ^>=0.6
|
, containers ^>=0.6
|
||||||
, generic-arbitrary ^>=0.1.0
|
, generic-arbitrary ^>=0.1.0
|
||||||
, ghcup
|
, ghcup
|
||||||
, hpath >=0.11 && <0.13
|
, hspec ^>=2.7.10
|
||||||
, hspec ^>=2.7.4
|
, hspec-golden-aeson ^>=0.9
|
||||||
, hspec-golden-aeson >=0.7 && <0.10
|
|
||||||
, QuickCheck ^>=2.14.1
|
, QuickCheck ^>=2.14.1
|
||||||
, quickcheck-arbitrary-adt ^>=0.3.1.0
|
, quickcheck-arbitrary-adt ^>=0.3.1.0
|
||||||
, text ^>=1.2.4.0
|
, text ^>=1.2.4.0
|
||||||
, uri-bytestring ^>=0.3.2.2
|
, uri-bytestring ^>=0.3.2.2
|
||||||
, versions ^>=4.0.1
|
, versions >=4.0.1 && <5.1
|
||||||
|
|||||||
33548
golden/GHCupInfo.json
33548
golden/GHCupInfo.json
File diff suppressed because it is too large
Load Diff
1714
lib/GHCup.hs
1714
lib/GHCup.hs
File diff suppressed because it is too large
Load Diff
@@ -16,7 +16,7 @@ Copyright : (c) Julian Ospald, 2020
|
|||||||
License : LGPL-3.0
|
License : LGPL-3.0
|
||||||
Maintainer : hasufell@hasufell.de
|
Maintainer : hasufell@hasufell.de
|
||||||
Stability : experimental
|
Stability : experimental
|
||||||
Portability : POSIX
|
Portability : portable
|
||||||
|
|
||||||
Module for handling all download related functions.
|
Module for handling all download related functions.
|
||||||
|
|
||||||
@@ -36,7 +36,7 @@ import GHCup.Errors
|
|||||||
import GHCup.Types
|
import GHCup.Types
|
||||||
import GHCup.Types.JSON ( )
|
import GHCup.Types.JSON ( )
|
||||||
import GHCup.Types.Optics
|
import GHCup.Types.Optics
|
||||||
import GHCup.Utils
|
import GHCup.Utils.Dirs
|
||||||
import GHCup.Utils.File
|
import GHCup.Utils.File
|
||||||
import GHCup.Utils.Prelude
|
import GHCup.Utils.Prelude
|
||||||
import GHCup.Version
|
import GHCup.Version
|
||||||
@@ -55,45 +55,42 @@ import Data.Aeson
|
|||||||
import Data.Bifunctor
|
import Data.Bifunctor
|
||||||
import Data.ByteString ( ByteString )
|
import Data.ByteString ( ByteString )
|
||||||
#if defined(INTERNAL_DOWNLOADER)
|
#if defined(INTERNAL_DOWNLOADER)
|
||||||
import Data.CaseInsensitive ( CI )
|
import Data.CaseInsensitive ( mk )
|
||||||
#endif
|
#endif
|
||||||
import Data.List ( find )
|
import Data.List.Extra
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
import Data.String.Interpolate
|
import Data.String.Interpolate
|
||||||
import Data.Time.Clock
|
import Data.Time.Clock
|
||||||
import Data.Time.Clock.POSIX
|
import Data.Time.Clock.POSIX
|
||||||
#if defined(INTERNAL_DOWNLOADER)
|
|
||||||
import Data.Time.Format
|
|
||||||
#endif
|
|
||||||
import Data.Versions
|
import Data.Versions
|
||||||
import Data.Word8
|
import Data.Word8 hiding ( isSpace )
|
||||||
import GHC.IO.Exception
|
|
||||||
import HPath
|
|
||||||
import HPath.IO as HIO hiding ( hideError )
|
|
||||||
import Haskus.Utils.Variant.Excepts
|
import Haskus.Utils.Variant.Excepts
|
||||||
|
#if defined(INTERNAL_DOWNLOADER)
|
||||||
|
import Network.Http.Client hiding ( URL )
|
||||||
|
#endif
|
||||||
import Optics
|
import Optics
|
||||||
import Prelude hiding ( abs
|
import Prelude hiding ( abs
|
||||||
, readFile
|
, readFile
|
||||||
, writeFile
|
, writeFile
|
||||||
)
|
)
|
||||||
|
import System.Directory
|
||||||
|
import System.Environment
|
||||||
|
import System.Exit
|
||||||
|
import System.FilePath
|
||||||
import System.IO.Error
|
import System.IO.Error
|
||||||
import System.Posix.Env.ByteString ( getEnv )
|
import System.IO.Temp
|
||||||
|
import Text.PrettyPrint.HughesPJClass ( prettyShow )
|
||||||
import URI.ByteString
|
import URI.ByteString
|
||||||
|
|
||||||
import qualified Crypto.Hash.SHA256 as SHA256
|
import qualified Crypto.Hash.SHA256 as SHA256
|
||||||
import qualified Data.ByteString as BS
|
import qualified Data.ByteString as B
|
||||||
import qualified Data.ByteString.Base16 as B16
|
import qualified Data.ByteString.Base16 as B16
|
||||||
import qualified Data.ByteString.Lazy as L
|
import qualified Data.ByteString.Lazy as L
|
||||||
import qualified Data.Map.Strict as M
|
import qualified Data.Map.Strict as M
|
||||||
#if defined(INTERNAL_DOWNLOADER)
|
|
||||||
import qualified Data.CaseInsensitive as CI
|
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
#endif
|
import qualified Data.Text.IO as T
|
||||||
import qualified Data.Text.Encoding as E
|
import qualified Data.Text.Encoding as E
|
||||||
import qualified Data.Yaml as Y
|
import qualified Data.Yaml as Y
|
||||||
import qualified System.Posix.Files.ByteString as PF
|
|
||||||
import qualified System.Posix.RawFilePath.Directory
|
|
||||||
as RD
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -110,32 +107,32 @@ import qualified System.Posix.RawFilePath.Directory
|
|||||||
getDownloadsF :: ( FromJSONKey Tool
|
getDownloadsF :: ( FromJSONKey Tool
|
||||||
, FromJSONKey Version
|
, FromJSONKey Version
|
||||||
, FromJSON VersionInfo
|
, FromJSON VersionInfo
|
||||||
|
, MonadReader env m
|
||||||
|
, HasSettings env
|
||||||
|
, HasDirs env
|
||||||
, MonadIO m
|
, MonadIO m
|
||||||
, MonadCatch m
|
, MonadCatch m
|
||||||
, MonadLogger m
|
, MonadLogger m
|
||||||
, MonadThrow m
|
, MonadThrow m
|
||||||
, MonadFail m
|
, MonadFail m
|
||||||
, MonadReader AppState m
|
, MonadMask m
|
||||||
)
|
)
|
||||||
=> URLSource
|
=> Excepts
|
||||||
-> Excepts
|
|
||||||
'[JSONError , DownloadFailed , FileDoesNotExistError]
|
'[JSONError , DownloadFailed , FileDoesNotExistError]
|
||||||
m
|
m
|
||||||
GHCupInfo
|
GHCupInfo
|
||||||
getDownloadsF urlSource = do
|
getDownloadsF = do
|
||||||
|
Settings { urlSource } <- lift getSettings
|
||||||
case urlSource of
|
case urlSource of
|
||||||
GHCupURL -> liftE getBase
|
GHCupURL -> liftE $ getBase ghcupURL
|
||||||
(OwnSource url) -> do
|
(OwnSource url) -> liftE $ getBase url
|
||||||
bs <- reThrowAll DownloadFailed $ downloadBS url
|
|
||||||
lE' JSONDecodeError $ first show $ Y.decodeEither' (L.toStrict bs)
|
|
||||||
(OwnSpec av) -> pure av
|
(OwnSpec av) -> pure av
|
||||||
(AddSource (Left ext)) -> do
|
(AddSource (Left ext)) -> do
|
||||||
base <- liftE getBase
|
base <- liftE $ getBase ghcupURL
|
||||||
pure (mergeGhcupInfo base ext)
|
pure (mergeGhcupInfo base ext)
|
||||||
(AddSource (Right uri)) -> do
|
(AddSource (Right uri)) -> do
|
||||||
base <- liftE getBase
|
base <- liftE $ getBase ghcupURL
|
||||||
bsExt <- reThrowAll DownloadFailed $ downloadBS uri
|
ext <- liftE $ getBase uri
|
||||||
ext <- lE' JSONDecodeError $ first show $ Y.decodeEither' (L.toStrict bsExt)
|
|
||||||
pure (mergeGhcupInfo base ext)
|
pure (mergeGhcupInfo base ext)
|
||||||
|
|
||||||
where
|
where
|
||||||
@@ -143,181 +140,151 @@ getDownloadsF urlSource = do
|
|||||||
mergeGhcupInfo :: GHCupInfo -- ^ base to merge with
|
mergeGhcupInfo :: GHCupInfo -- ^ base to merge with
|
||||||
-> GHCupInfo -- ^ extension overwriting the base
|
-> GHCupInfo -- ^ extension overwriting the base
|
||||||
-> GHCupInfo
|
-> GHCupInfo
|
||||||
mergeGhcupInfo (GHCupInfo tr base) (GHCupInfo _ ext) =
|
mergeGhcupInfo (GHCupInfo tr base base2) (GHCupInfo _ ext ext2) =
|
||||||
let new = M.mapWithKey (\k a -> case M.lookup k ext of
|
let newDownloads = M.mapWithKey (\k a -> case M.lookup k ext of
|
||||||
Just a' -> M.union a' a
|
Just a' -> M.union a' a
|
||||||
Nothing -> a
|
Nothing -> a
|
||||||
) base
|
) base
|
||||||
in GHCupInfo tr new
|
newGlobalTools = M.union base2 ext2
|
||||||
|
in GHCupInfo tr newDownloads newGlobalTools
|
||||||
|
|
||||||
|
|
||||||
readFromCache :: (MonadIO m, MonadCatch m, MonadLogger m, MonadReader AppState m)
|
yamlFromCache :: (MonadReader env m, HasDirs env) => URI -> m FilePath
|
||||||
=> Excepts '[JSONError, FileDoesNotExistError] m GHCupInfo
|
yamlFromCache uri = do
|
||||||
readFromCache = do
|
Dirs{..} <- getDirs
|
||||||
AppState {dirs = Dirs {..}} <- lift ask
|
pure (cacheDir </> (T.unpack . decUTF8Safe . urlBaseName . view pathL' $ uri))
|
||||||
lift $ $(logWarn)
|
|
||||||
[i|Could not get download info, trying cached version (this may not be recent!)|]
|
|
||||||
let path = view pathL' ghcupURL
|
|
||||||
yaml_file <- (cacheDir </>) <$> urlBaseName path
|
|
||||||
bs <-
|
|
||||||
handleIO' NoSuchThing
|
|
||||||
(\_ -> throwE $ FileDoesNotExistError (toFilePath yaml_file))
|
|
||||||
$ liftIO
|
|
||||||
$ readFile yaml_file
|
|
||||||
lE' JSONDecodeError $ first show $ Y.decodeEither' (L.toStrict bs)
|
|
||||||
|
|
||||||
|
|
||||||
getBase :: (MonadFail m, MonadIO m, MonadCatch m, MonadLogger m, MonadReader AppState m)
|
etagsFile :: FilePath -> FilePath
|
||||||
=> Excepts '[JSONError , FileDoesNotExistError] m GHCupInfo
|
etagsFile = (<.> "etags")
|
||||||
getBase =
|
|
||||||
handleIO (\_ -> readFromCache)
|
|
||||||
$ catchE @_ @'[JSONError, FileDoesNotExistError]
|
getBase :: ( MonadReader env m
|
||||||
(\(DownloadFailed _) -> readFromCache)
|
, HasDirs env
|
||||||
(reThrowAll @_ @_ @'[JSONError, DownloadFailed] DownloadFailed (smartDl ghcupURL)
|
, HasSettings env
|
||||||
>>= (liftE . lE' @_ @_ @'[JSONError] JSONDecodeError . first show . Y.decodeEither' . L.toStrict))
|
, MonadFail m
|
||||||
where
|
, MonadIO m
|
||||||
|
, MonadCatch m
|
||||||
|
, MonadLogger m
|
||||||
|
, MonadMask m
|
||||||
|
)
|
||||||
|
=> URI
|
||||||
|
-> Excepts '[JSONError] m GHCupInfo
|
||||||
|
getBase uri = do
|
||||||
|
Settings { noNetwork } <- lift getSettings
|
||||||
|
yaml <- lift $ yamlFromCache uri
|
||||||
|
unless noNetwork $
|
||||||
|
handleIO (\e -> warnCache (displayException e))
|
||||||
|
. catchE @_ @_ @'[] (\e@(DownloadFailed _) -> warnCache (prettyShow e))
|
||||||
|
. reThrowAll @_ @_ @'[DownloadFailed] DownloadFailed
|
||||||
|
. smartDl
|
||||||
|
$ uri
|
||||||
|
liftE
|
||||||
|
. onE_ (onError yaml)
|
||||||
|
. lEM' @_ @_ @'[JSONError] JSONDecodeError
|
||||||
|
. fmap (first (\e -> [i|#{displayException e}
|
||||||
|
Consider removing "#{yaml}" manually.|]))
|
||||||
|
. liftIO
|
||||||
|
. Y.decodeFileEither
|
||||||
|
$ yaml
|
||||||
|
where
|
||||||
|
-- On error, remove the etags file and set access time to 0. This should ensure the next invocation
|
||||||
|
-- may re-download and succeed.
|
||||||
|
onError :: (MonadLogger m, MonadMask m, MonadCatch m, MonadIO m) => FilePath -> m ()
|
||||||
|
onError fp = do
|
||||||
|
let efp = etagsFile fp
|
||||||
|
handleIO (\e -> $(logWarn) [i|Couldn't remove file #{efp}, error was: #{displayException e}|])
|
||||||
|
(hideError doesNotExistErrorType $ rmFile efp)
|
||||||
|
liftIO $ hideError doesNotExistErrorType $ setAccessTime fp (posixSecondsToUTCTime (fromIntegral @Int 0))
|
||||||
|
warnCache s = do
|
||||||
|
lift $ $(logWarn) [i|Could not get download info, trying cached version (this may not be recent!)|]
|
||||||
|
lift $ $(logDebug) [i|Error was: #{s}|]
|
||||||
|
|
||||||
-- First check if the json file is in the ~/.ghcup/cache dir
|
-- First check if the json file is in the ~/.ghcup/cache dir
|
||||||
-- and check it's access time. If it has been accessed within the
|
-- and check it's access time. If it has been accessed within the
|
||||||
-- last 5 minutes, just reuse it.
|
-- last 5 minutes, just reuse it.
|
||||||
--
|
--
|
||||||
-- If not, then send a HEAD request and check for modification time.
|
|
||||||
-- Only download the file if the modification time is newer
|
|
||||||
-- than the local file.
|
|
||||||
--
|
|
||||||
-- Always save the local file with the mod time of the remote file.
|
-- Always save the local file with the mod time of the remote file.
|
||||||
smartDl :: forall m1
|
smartDl :: forall m1 env1
|
||||||
. ( MonadCatch m1
|
. ( MonadReader env1 m1
|
||||||
|
, HasDirs env1
|
||||||
|
, HasSettings env1
|
||||||
|
, MonadCatch m1
|
||||||
, MonadIO m1
|
, MonadIO m1
|
||||||
, MonadFail m1
|
, MonadFail m1
|
||||||
, MonadLogger m1
|
, MonadLogger m1
|
||||||
, MonadReader AppState m1
|
, MonadMask m1
|
||||||
)
|
)
|
||||||
=> URI
|
=> URI
|
||||||
-> Excepts
|
-> Excepts
|
||||||
'[ FileDoesNotExistError
|
'[ DownloadFailed
|
||||||
, HTTPStatusError
|
, DigestError
|
||||||
, URIParseError
|
|
||||||
, UnsupportedScheme
|
|
||||||
, NoLocationHeader
|
|
||||||
, TooManyRedirs
|
|
||||||
, ProcessError
|
|
||||||
]
|
]
|
||||||
m1
|
m1
|
||||||
L.ByteString
|
()
|
||||||
smartDl uri' = do
|
smartDl uri' = do
|
||||||
AppState {dirs = Dirs {..}} <- lift ask
|
json_file <- lift $ yamlFromCache uri'
|
||||||
let path = view pathL' uri'
|
e <- liftIO $ doesFileExist json_file
|
||||||
json_file <- (cacheDir </>) <$> urlBaseName path
|
currentTime <- liftIO getCurrentTime
|
||||||
e <- liftIO $ doesFileExist json_file
|
|
||||||
if e
|
if e
|
||||||
then do
|
then do
|
||||||
accessTime <-
|
accessTime <- liftIO $ getAccessTime json_file
|
||||||
PF.accessTimeHiRes
|
|
||||||
<$> liftIO (PF.getFileStatus (toFilePath json_file))
|
|
||||||
currentTime <- liftIO getPOSIXTime
|
|
||||||
|
|
||||||
-- access time won't work on most linuxes, but we can try regardless
|
-- access time won't work on most linuxes, but we can try regardless
|
||||||
if (currentTime - accessTime) > 300
|
when ((utcTimeToPOSIXSeconds currentTime - utcTimeToPOSIXSeconds accessTime) > 300) $
|
||||||
then do -- no access in last 5 minutes, re-check upstream mod time
|
-- no access in last 5 minutes, re-check upstream mod time
|
||||||
getModTime >>= \case
|
dlWithMod currentTime json_file
|
||||||
Just modTime -> do
|
else
|
||||||
fileMod <- liftIO $ getModificationTime json_file
|
dlWithMod currentTime json_file
|
||||||
if modTime > fileMod
|
|
||||||
then dlWithMod modTime json_file
|
|
||||||
else liftIO $ readFile json_file
|
|
||||||
Nothing -> do
|
|
||||||
lift $ $(logDebug) [i|Unable to get/parse Last-Modified header|]
|
|
||||||
dlWithoutMod json_file
|
|
||||||
else -- access in less than 5 minutes, re-use file
|
|
||||||
liftIO $ readFile json_file
|
|
||||||
else do
|
|
||||||
liftIO $ createDirRecursive' cacheDir
|
|
||||||
getModTime >>= \case
|
|
||||||
Just modTime -> dlWithMod modTime json_file
|
|
||||||
Nothing -> do
|
|
||||||
-- although we don't know last-modified, we still save
|
|
||||||
-- it to a file, so we might use it in offline mode
|
|
||||||
lift $ $(logDebug) [i|Unable to get/parse Last-Modified header|]
|
|
||||||
dlWithoutMod json_file
|
|
||||||
|
|
||||||
where
|
where
|
||||||
dlWithMod modTime json_file = do
|
dlWithMod modTime json_file = do
|
||||||
bs <- liftE $ downloadBS uri'
|
let (dir, fn) = splitFileName json_file
|
||||||
liftIO $ writeFileWithModTime modTime json_file bs
|
f <- liftE $ download uri' Nothing dir (Just fn) True
|
||||||
pure bs
|
liftIO $ setModificationTime f modTime
|
||||||
dlWithoutMod json_file = do
|
liftIO $ setAccessTime f modTime
|
||||||
bs <- liftE $ downloadBS uri'
|
|
||||||
liftIO $ hideError doesNotExistErrorType $ deleteFile json_file
|
|
||||||
liftIO $ writeFileL json_file (Just newFilePerms) bs
|
|
||||||
liftIO $ setModificationTime json_file (fromIntegral @Int 0)
|
|
||||||
pure bs
|
|
||||||
|
|
||||||
|
|
||||||
getModTime = do
|
getDownloadInfo :: ( MonadReader env m
|
||||||
#if !defined(INTERNAL_DOWNLOADER)
|
, HasPlatformReq env
|
||||||
pure Nothing
|
, HasGHCupInfo env
|
||||||
#else
|
)
|
||||||
headers <-
|
=> Tool
|
||||||
handleIO (\_ -> pure mempty)
|
|
||||||
$ liftE
|
|
||||||
$ ( catchAllE
|
|
||||||
(\_ ->
|
|
||||||
pure mempty :: Excepts '[] m1 (M.Map (CI ByteString) ByteString)
|
|
||||||
)
|
|
||||||
$ getHead uri'
|
|
||||||
)
|
|
||||||
pure $ parseModifiedHeader headers
|
|
||||||
|
|
||||||
parseModifiedHeader :: (M.Map (CI ByteString) ByteString) -> Maybe UTCTime
|
|
||||||
parseModifiedHeader headers =
|
|
||||||
(M.lookup (CI.mk "Last-Modified") headers) >>= \h -> parseTimeM
|
|
||||||
True
|
|
||||||
defaultTimeLocale
|
|
||||||
"%a, %d %b %Y %H:%M:%S %Z"
|
|
||||||
(T.unpack . decUTF8Safe $ h)
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
writeFileWithModTime :: UTCTime -> Path Abs -> L.ByteString -> IO ()
|
|
||||||
writeFileWithModTime utctime path content = do
|
|
||||||
let mod_time = utcTimeToPOSIXSeconds utctime
|
|
||||||
writeFileL path (Just newFilePerms) content
|
|
||||||
setModificationTimeHiRes path mod_time
|
|
||||||
|
|
||||||
|
|
||||||
getDownloadInfo :: Tool
|
|
||||||
-> Version
|
-> Version
|
||||||
-- ^ tool version
|
-- ^ tool version
|
||||||
-> PlatformRequest
|
-> Excepts
|
||||||
-> GHCupDownloads
|
'[NoDownload]
|
||||||
-> Either NoDownload DownloadInfo
|
m
|
||||||
getDownloadInfo t v (PlatformRequest a p mv) dls = maybe
|
DownloadInfo
|
||||||
(Left NoDownload)
|
getDownloadInfo t v = do
|
||||||
Right
|
(PlatformRequest a p mv) <- lift getPlatformReq
|
||||||
(case p of
|
GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo
|
||||||
-- non-musl won't work on alpine
|
|
||||||
Linux Alpine -> with_distro <|> without_distro_ver
|
|
||||||
_ -> with_distro <|> without_distro_ver <|> without_distro
|
|
||||||
)
|
|
||||||
|
|
||||||
where
|
let distro_preview f g =
|
||||||
with_distro = distro_preview id id
|
let platformVersionSpec =
|
||||||
without_distro_ver = distro_preview id (const Nothing)
|
preview (ix t % ix v % viArch % ix a % ix (f p)) dls
|
||||||
without_distro = distro_preview (set _Linux UnknownLinux) (const Nothing)
|
mv' = g mv
|
||||||
|
in fmap snd
|
||||||
|
. find
|
||||||
|
(\(mverRange, _) -> maybe
|
||||||
|
(isNothing mv')
|
||||||
|
(\range -> maybe False (`versionRange` range) mv')
|
||||||
|
mverRange
|
||||||
|
)
|
||||||
|
. M.toList
|
||||||
|
=<< platformVersionSpec
|
||||||
|
with_distro = distro_preview id id
|
||||||
|
without_distro_ver = distro_preview id (const Nothing)
|
||||||
|
without_distro = distro_preview (set _Linux UnknownLinux) (const Nothing)
|
||||||
|
|
||||||
distro_preview f g =
|
maybe
|
||||||
let platformVersionSpec =
|
(throwE NoDownload)
|
||||||
preview (ix t % ix v % viArch % ix a % ix (f p)) dls
|
pure
|
||||||
mv' = g mv
|
(case p of
|
||||||
in fmap snd
|
-- non-musl won't work on alpine
|
||||||
. find
|
Linux Alpine -> with_distro <|> without_distro_ver
|
||||||
(\(mverRange, _) -> maybe
|
_ -> with_distro <|> without_distro_ver <|> without_distro
|
||||||
(isNothing mv')
|
)
|
||||||
(\range -> maybe False (`versionRange` range) mv')
|
|
||||||
mverRange
|
|
||||||
)
|
|
||||||
. M.toList
|
|
||||||
=<< platformVersionSpec
|
|
||||||
|
|
||||||
|
|
||||||
-- | Tries to download from the given http or https url
|
-- | Tries to download from the given http or https url
|
||||||
@@ -327,100 +294,232 @@ getDownloadInfo t v (PlatformRequest a p mv) dls = maybe
|
|||||||
-- 2. otherwise create a random file
|
-- 2. otherwise create a random file
|
||||||
--
|
--
|
||||||
-- The file must not exist.
|
-- The file must not exist.
|
||||||
download :: ( MonadMask m
|
download :: ( MonadReader env m
|
||||||
, MonadReader AppState m
|
, HasSettings env
|
||||||
|
, HasDirs env
|
||||||
|
, MonadMask m
|
||||||
, MonadThrow m
|
, MonadThrow m
|
||||||
, MonadLogger m
|
, MonadLogger m
|
||||||
, MonadIO m
|
, MonadIO m
|
||||||
)
|
)
|
||||||
=> DownloadInfo
|
=> URI
|
||||||
-> Path Abs -- ^ destination dir
|
-> Maybe T.Text -- ^ expected hash
|
||||||
-> Maybe (Path Rel) -- ^ optional filename
|
-> FilePath -- ^ destination dir
|
||||||
-> Excepts '[DigestError , DownloadFailed] m (Path Abs)
|
-> Maybe FilePath -- ^ optional filename
|
||||||
download dli dest mfn
|
-> Bool -- ^ whether to read an write etags
|
||||||
|
-> Excepts '[DigestError , DownloadFailed] m FilePath
|
||||||
|
download uri eDigest dest mfn etags
|
||||||
| scheme == "https" = dl
|
| scheme == "https" = dl
|
||||||
| scheme == "http" = dl
|
| scheme == "http" = dl
|
||||||
| scheme == "file" = cp
|
| scheme == "file" = cp
|
||||||
| otherwise = throwE $ DownloadFailed (variantFromValue UnsupportedScheme)
|
| otherwise = throwE $ DownloadFailed (variantFromValue UnsupportedScheme)
|
||||||
|
|
||||||
where
|
where
|
||||||
scheme = view (dlUri % uriSchemeL' % schemeBSL') dli
|
scheme = view (uriSchemeL' % schemeBSL') uri
|
||||||
cp = do
|
cp = do
|
||||||
-- destination dir must exist
|
-- destination dir must exist
|
||||||
liftIO $ createDirRecursive' dest
|
liftIO $ createDirRecursive' dest
|
||||||
destFile <- getDestFile
|
let fromFile = T.unpack . decUTF8Safe $ path
|
||||||
fromFile <- parseAbs path
|
liftIO $ copyFile fromFile destFile
|
||||||
liftIO $ copyFile fromFile destFile Strict
|
|
||||||
pure destFile
|
pure destFile
|
||||||
dl = do
|
dl = do
|
||||||
let uri' = decUTF8Safe (serializeURIRef' (view dlUri dli))
|
let uri' = decUTF8Safe (serializeURIRef' uri)
|
||||||
lift $ $(logInfo) [i|downloading: #{uri'}|]
|
lift $ $(logInfo) [i|downloading: #{uri'}|]
|
||||||
|
|
||||||
-- destination dir must exist
|
-- destination dir must exist
|
||||||
liftIO $ createDirRecursive' dest
|
liftIO $ createDirRecursive' dest
|
||||||
destFile <- getDestFile
|
|
||||||
|
|
||||||
-- download
|
-- download
|
||||||
flip onException
|
flip onException
|
||||||
(liftIO $ hideError doesNotExistErrorType $ deleteFile destFile)
|
(lift $ hideError doesNotExistErrorType $ recycleFile destFile)
|
||||||
$ catchAllE @_ @'[ProcessError, DownloadFailed, UnsupportedScheme]
|
$ catchAllE @_ @'[ProcessError, DownloadFailed, UnsupportedScheme]
|
||||||
(\e ->
|
(\e ->
|
||||||
liftIO (hideError doesNotExistErrorType $ deleteFile destFile)
|
lift (hideError doesNotExistErrorType $ recycleFile destFile)
|
||||||
>> (throwE . DownloadFailed $ e)
|
>> (throwE . DownloadFailed $ e)
|
||||||
) $ do
|
) $ do
|
||||||
lift getDownloader >>= \case
|
Settings{ downloader, noNetwork } <- lift getSettings
|
||||||
|
when noNetwork $ throwE (DownloadFailed (V NoNetwork :: V '[NoNetwork]))
|
||||||
|
case downloader of
|
||||||
Curl -> do
|
Curl -> do
|
||||||
o' <- liftIO getCurlOpts
|
o' <- liftIO getCurlOpts
|
||||||
liftE $ lEM @_ @'[ProcessError] $ liftIO $ exec "curl" True
|
if etags
|
||||||
(o' ++ ["-fL", "-o", toFilePath destFile, serializeURIRef' $ view dlUri dli]) Nothing Nothing
|
then do
|
||||||
|
dh <- liftIO $ emptySystemTempFile "curl-header"
|
||||||
|
flip finally (try @_ @SomeException $ rmFile dh) $
|
||||||
|
flip finally (try @_ @SomeException $ rmFile (destFile <.> "tmp")) $ do
|
||||||
|
metag <- readETag destFile
|
||||||
|
liftE $ lEM @_ @'[ProcessError] $ exec "curl"
|
||||||
|
(o' ++ (if etags then ["--dump-header", dh] else [])
|
||||||
|
++ maybe [] (\t -> ["-H", [i|If-None-Match: #{t}|]]) metag
|
||||||
|
++ ["-fL", "-o", destFile <.> "tmp", T.unpack uri']) Nothing Nothing
|
||||||
|
headers <- liftIO $ T.readFile dh
|
||||||
|
|
||||||
|
-- this nonsense is necessary, because some older versions of curl would overwrite
|
||||||
|
-- the destination file when 304 is returned
|
||||||
|
case fmap T.words . listToMaybe . fmap T.strip . T.lines $ headers of
|
||||||
|
Just (http':sc:_)
|
||||||
|
| sc == "304"
|
||||||
|
, T.pack "HTTP" `T.isPrefixOf` http' -> $logDebug [i|Status code was 304, not overwriting|]
|
||||||
|
| T.pack "HTTP" `T.isPrefixOf` http' -> do
|
||||||
|
$logDebug [i|Status code was #{sc}, overwriting|]
|
||||||
|
liftIO $ copyFile (destFile <.> "tmp") destFile
|
||||||
|
_ -> liftE $ throwE @_ @'[DownloadFailed] (DownloadFailed (toVariantAt @0 (MalformedHeaders headers)
|
||||||
|
:: V '[MalformedHeaders]))
|
||||||
|
|
||||||
|
writeEtags (parseEtags headers)
|
||||||
|
else
|
||||||
|
liftE $ lEM @_ @'[ProcessError] $ exec "curl"
|
||||||
|
(o' ++ ["-fL", "-o", destFile, T.unpack uri']) Nothing Nothing
|
||||||
Wget -> do
|
Wget -> do
|
||||||
o' <- liftIO getWgetOpts
|
destFileTemp <- liftIO $ emptySystemTempFile "wget-tmp"
|
||||||
liftE $ lEM @_ @'[ProcessError] $ liftIO $ exec "wget" True
|
flip finally (try @_ @SomeException $ rmFile destFileTemp) $ do
|
||||||
(o' ++ ["-O", toFilePath destFile , serializeURIRef' $ view dlUri dli]) Nothing Nothing
|
o' <- liftIO getWgetOpts
|
||||||
|
if etags
|
||||||
|
then do
|
||||||
|
metag <- readETag destFile
|
||||||
|
let opts = o' ++ maybe [] (\t -> ["--header", [i|If-None-Match: #{t}|]]) metag
|
||||||
|
++ ["-q", "-S", "-O", destFileTemp , T.unpack uri']
|
||||||
|
CapturedProcess {_exitCode, _stdErr} <- lift $ executeOut "wget" opts Nothing
|
||||||
|
case _exitCode of
|
||||||
|
ExitSuccess -> do
|
||||||
|
liftIO $ copyFile destFileTemp destFile
|
||||||
|
writeEtags (parseEtags (decUTF8Safe' _stdErr))
|
||||||
|
ExitFailure i'
|
||||||
|
| i' == 8
|
||||||
|
, Just _ <- find (T.pack "304 Not Modified" `T.isInfixOf`) . T.lines . decUTF8Safe' $ _stdErr
|
||||||
|
-> do
|
||||||
|
$logDebug "Not modified, skipping download"
|
||||||
|
writeEtags (parseEtags (decUTF8Safe' _stdErr))
|
||||||
|
| otherwise -> throwE (NonZeroExit i' "wget" opts)
|
||||||
|
else do
|
||||||
|
let opts = o' ++ ["-O", destFileTemp , T.unpack uri']
|
||||||
|
liftE $ lEM @_ @'[ProcessError] $ exec "wget" opts Nothing Nothing
|
||||||
|
liftIO $ copyFile destFileTemp destFile
|
||||||
#if defined(INTERNAL_DOWNLOADER)
|
#if defined(INTERNAL_DOWNLOADER)
|
||||||
Internal -> do
|
Internal -> do
|
||||||
(https, host, fullPath, port) <- liftE $ uriToQuadruple (view dlUri dli)
|
(https, host, fullPath, port) <- liftE $ uriToQuadruple uri
|
||||||
liftE $ downloadToFile https host fullPath port destFile
|
if etags
|
||||||
|
then do
|
||||||
|
metag <- readETag destFile
|
||||||
|
let addHeaders = maybe mempty (\etag -> M.fromList [ (mk . E.encodeUtf8 . T.pack $ "If-None-Match"
|
||||||
|
, E.encodeUtf8 etag)]) metag
|
||||||
|
liftE
|
||||||
|
$ catchE @HTTPNotModified @'[DownloadFailed] @'[] (\(HTTPNotModified etag) -> lift $ writeEtags (pure $ Just etag))
|
||||||
|
$ do
|
||||||
|
r <- downloadToFile https host fullPath port destFile addHeaders
|
||||||
|
writeEtags (pure $ decUTF8Safe <$> getHeader r "etag")
|
||||||
|
else void $ liftE $ catchE @HTTPNotModified
|
||||||
|
@'[DownloadFailed]
|
||||||
|
(\e@(HTTPNotModified _) ->
|
||||||
|
throwE @_ @'[DownloadFailed] (DownloadFailed (toVariantAt @0 e :: V '[HTTPNotModified])))
|
||||||
|
$ downloadToFile https host fullPath port destFile mempty
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
liftE $ checkDigest dli destFile
|
forM_ eDigest (liftE . flip checkDigest destFile)
|
||||||
pure destFile
|
pure destFile
|
||||||
|
|
||||||
-- Manage to find a file we can write the body into.
|
|
||||||
getDestFile :: MonadThrow m => m (Path Abs)
|
|
||||||
getDestFile = maybe (urlBaseName path <&> (dest </>)) (pure . (dest </>)) mfn
|
|
||||||
|
|
||||||
path = view (dlUri % pathL') dli
|
-- Manage to find a file we can write the body into.
|
||||||
|
destFile :: FilePath
|
||||||
|
destFile = maybe (dest </> T.unpack (decUTF8Safe (urlBaseName path)))
|
||||||
|
(dest </>)
|
||||||
|
mfn
|
||||||
|
|
||||||
|
path = view pathL' uri
|
||||||
|
|
||||||
|
parseEtags :: (MonadLogger m, MonadIO m, MonadThrow m) => T.Text -> m (Maybe T.Text)
|
||||||
|
parseEtags stderr = do
|
||||||
|
let mEtag = find (\line -> T.pack "etag:" `T.isPrefixOf` T.toLower line) . fmap T.strip . T.lines $ stderr
|
||||||
|
case T.words <$> mEtag of
|
||||||
|
(Just []) -> do
|
||||||
|
$logDebug "Couldn't parse etags, no input: "
|
||||||
|
pure Nothing
|
||||||
|
(Just [_, etag']) -> do
|
||||||
|
$logDebug [i|Parsed etag: #{etag'}|]
|
||||||
|
pure (Just etag')
|
||||||
|
(Just xs) -> do
|
||||||
|
$logDebug ("Couldn't parse etags, unexpected input: " <> T.unwords xs)
|
||||||
|
pure Nothing
|
||||||
|
Nothing -> do
|
||||||
|
$logDebug "No etags header found"
|
||||||
|
pure Nothing
|
||||||
|
|
||||||
|
writeEtags :: (MonadLogger m, MonadIO m, MonadThrow m) => m (Maybe T.Text) -> m ()
|
||||||
|
writeEtags getTags = do
|
||||||
|
getTags >>= \case
|
||||||
|
Just t -> do
|
||||||
|
$logDebug [i|Writing etagsFile #{(etagsFile destFile)}|]
|
||||||
|
liftIO $ T.writeFile (etagsFile destFile) t
|
||||||
|
Nothing ->
|
||||||
|
$logDebug [i|No etags files written|]
|
||||||
|
|
||||||
|
readETag :: (MonadLogger m, MonadCatch m, MonadIO m) => FilePath -> m (Maybe T.Text)
|
||||||
|
readETag fp = do
|
||||||
|
e <- liftIO $ doesFileExist fp
|
||||||
|
if e
|
||||||
|
then do
|
||||||
|
rE <- try @_ @SomeException $ liftIO $ fmap stripNewline' $ T.readFile (etagsFile fp)
|
||||||
|
case rE of
|
||||||
|
(Right et) -> do
|
||||||
|
$logDebug [i|Read etag: #{et}|]
|
||||||
|
pure (Just et)
|
||||||
|
(Left _) -> do
|
||||||
|
$logDebug [i|Etag file doesn't exist (yet)|]
|
||||||
|
pure Nothing
|
||||||
|
else do
|
||||||
|
$logDebug [i|Skipping and deleting etags file because destination file #{fp} doesn't exist|]
|
||||||
|
liftIO $ hideError doesNotExistErrorType $ rmFile (etagsFile fp)
|
||||||
|
pure Nothing
|
||||||
|
|
||||||
|
|
||||||
-- | Download into tmpdir or use cached version, if it exists. If filename
|
-- | Download into tmpdir or use cached version, if it exists. If filename
|
||||||
-- is omitted, infers the filename from the url.
|
-- is omitted, infers the filename from the url.
|
||||||
downloadCached :: ( MonadMask m
|
downloadCached :: ( MonadReader env m
|
||||||
|
, HasDirs env
|
||||||
|
, HasSettings env
|
||||||
|
, MonadMask m
|
||||||
, MonadResource m
|
, MonadResource m
|
||||||
, MonadThrow m
|
, MonadThrow m
|
||||||
, MonadLogger m
|
, MonadLogger m
|
||||||
, MonadIO m
|
, MonadIO m
|
||||||
, MonadReader AppState m
|
, MonadUnliftIO m
|
||||||
)
|
)
|
||||||
=> DownloadInfo
|
=> DownloadInfo
|
||||||
-> Maybe (Path Rel) -- ^ optional filename
|
-> Maybe FilePath -- ^ optional filename
|
||||||
-> Excepts '[DigestError , DownloadFailed] m (Path Abs)
|
-> Excepts '[DigestError , DownloadFailed] m FilePath
|
||||||
downloadCached dli mfn = do
|
downloadCached dli mfn = do
|
||||||
cache <- lift getCache
|
Settings{ cache } <- lift getSettings
|
||||||
case cache of
|
case cache of
|
||||||
True -> do
|
True -> downloadCached' dli mfn Nothing
|
||||||
AppState {dirs = Dirs {..}} <- lift ask
|
|
||||||
fn <- maybe (urlBaseName $ view (dlUri % pathL') dli) pure mfn
|
|
||||||
let cachfile = cacheDir </> fn
|
|
||||||
fileExists <- liftIO $ doesFileExist cachfile
|
|
||||||
if
|
|
||||||
| fileExists -> do
|
|
||||||
liftE $ checkDigest dli cachfile
|
|
||||||
pure cachfile
|
|
||||||
| otherwise -> liftE $ download dli cacheDir mfn
|
|
||||||
False -> do
|
False -> do
|
||||||
tmp <- lift withGHCupTmpDir
|
tmp <- lift withGHCupTmpDir
|
||||||
liftE $ download dli tmp mfn
|
liftE $ download (_dlUri dli) (Just (_dlHash dli)) tmp mfn False
|
||||||
|
|
||||||
|
|
||||||
|
downloadCached' :: ( MonadReader env m
|
||||||
|
, HasDirs env
|
||||||
|
, HasSettings env
|
||||||
|
, MonadMask m
|
||||||
|
, MonadThrow m
|
||||||
|
, MonadLogger m
|
||||||
|
, MonadIO m
|
||||||
|
, MonadUnliftIO m
|
||||||
|
)
|
||||||
|
=> DownloadInfo
|
||||||
|
-> Maybe FilePath -- ^ optional filename
|
||||||
|
-> Maybe FilePath -- ^ optional destination dir (default: cacheDir)
|
||||||
|
-> Excepts '[DigestError , DownloadFailed] m FilePath
|
||||||
|
downloadCached' dli mfn mDestDir = do
|
||||||
|
Dirs { cacheDir } <- lift getDirs
|
||||||
|
let destDir = fromMaybe cacheDir mDestDir
|
||||||
|
let fn = fromMaybe ((T.unpack . decUTF8Safe) $ urlBaseName $ view (dlUri % pathL') dli) mfn
|
||||||
|
let cachfile = destDir </> fn
|
||||||
|
fileExists <- liftIO $ doesFileExist cachfile
|
||||||
|
if
|
||||||
|
| fileExists -> do
|
||||||
|
liftE $ checkDigest (view dlHash dli) cachfile
|
||||||
|
pure cachfile
|
||||||
|
| otherwise -> liftE $ download (_dlUri dli) (Just (_dlHash dli)) destDir mfn False
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -431,92 +530,44 @@ downloadCached dli mfn = do
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
checkDigest :: ( MonadReader env m
|
||||||
-- | This is used for downloading the JSON.
|
, HasDirs env
|
||||||
downloadBS :: (MonadReader AppState m, MonadCatch m, MonadIO m, MonadLogger m)
|
, HasSettings env
|
||||||
=> URI
|
, MonadIO m
|
||||||
-> Excepts
|
, MonadThrow m
|
||||||
'[ FileDoesNotExistError
|
, MonadLogger m
|
||||||
, HTTPStatusError
|
)
|
||||||
, URIParseError
|
=> T.Text -- ^ the hash
|
||||||
, UnsupportedScheme
|
-> FilePath
|
||||||
, NoLocationHeader
|
|
||||||
, TooManyRedirs
|
|
||||||
, ProcessError
|
|
||||||
]
|
|
||||||
m
|
|
||||||
L.ByteString
|
|
||||||
downloadBS uri'
|
|
||||||
| scheme == "https"
|
|
||||||
= dl True
|
|
||||||
| scheme == "http"
|
|
||||||
= dl False
|
|
||||||
| scheme == "file"
|
|
||||||
= liftIOException doesNotExistErrorType (FileDoesNotExistError path)
|
|
||||||
(liftIO $ RD.readFile path)
|
|
||||||
| otherwise
|
|
||||||
= throwE UnsupportedScheme
|
|
||||||
|
|
||||||
where
|
|
||||||
scheme = view (uriSchemeL' % schemeBSL') uri'
|
|
||||||
path = view pathL' uri'
|
|
||||||
#if defined(INTERNAL_DOWNLOADER)
|
|
||||||
dl https = do
|
|
||||||
#else
|
|
||||||
dl _ = do
|
|
||||||
#endif
|
|
||||||
lift $ $(logDebug) [i|downloading: #{serializeURIRef' uri'}|]
|
|
||||||
lift getDownloader >>= \case
|
|
||||||
Curl -> do
|
|
||||||
o' <- liftIO getCurlOpts
|
|
||||||
let exe = [rel|curl|]
|
|
||||||
args = o' ++ ["-sSfL", serializeURIRef' uri']
|
|
||||||
liftIO (executeOut exe args Nothing) >>= \case
|
|
||||||
CapturedProcess ExitSuccess stdout _ -> do
|
|
||||||
pure $ L.fromStrict stdout
|
|
||||||
CapturedProcess (ExitFailure i') _ _ -> throwE $ NonZeroExit i' (toFilePath exe) args
|
|
||||||
Wget -> do
|
|
||||||
o' <- liftIO getWgetOpts
|
|
||||||
let exe = [rel|wget|]
|
|
||||||
args = o' ++ ["-qO-", serializeURIRef' uri']
|
|
||||||
liftIO (executeOut exe args Nothing) >>= \case
|
|
||||||
CapturedProcess ExitSuccess stdout _ -> do
|
|
||||||
pure $ L.fromStrict stdout
|
|
||||||
CapturedProcess (ExitFailure i') _ _ -> throwE $ NonZeroExit i' (toFilePath exe) args
|
|
||||||
#if defined(INTERNAL_DOWNLOADER)
|
|
||||||
Internal -> do
|
|
||||||
(_, host', fullPath', port') <- liftE $ uriToQuadruple uri'
|
|
||||||
liftE $ downloadBS' https host' fullPath' port'
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
checkDigest :: (MonadIO m, MonadThrow m, MonadLogger m, MonadReader AppState m)
|
|
||||||
=> DownloadInfo
|
|
||||||
-> Path Abs
|
|
||||||
-> Excepts '[DigestError] m ()
|
-> Excepts '[DigestError] m ()
|
||||||
checkDigest dli file = do
|
checkDigest eDigest file = do
|
||||||
verify <- lift ask <&> (not . noVerify . settings)
|
Settings{ noVerify } <- lift getSettings
|
||||||
|
let verify = not noVerify
|
||||||
when verify $ do
|
when verify $ do
|
||||||
p' <- toFilePath <$> basename file
|
let p' = takeFileName file
|
||||||
lift $ $(logInfo) [i|verifying digest of: #{p'}|]
|
lift $ $(logInfo) [i|verifying digest of: #{p'}|]
|
||||||
c <- liftIO $ readFile file
|
c <- liftIO $ L.readFile file
|
||||||
cDigest <- throwEither . E.decodeUtf8' . B16.encode . SHA256.hashlazy $ c
|
cDigest <- throwEither . E.decodeUtf8' . B16.encode . SHA256.hashlazy $ c
|
||||||
let eDigest = view dlHash dli
|
|
||||||
when ((cDigest /= eDigest) && verify) $ throwE (DigestError cDigest eDigest)
|
when ((cDigest /= eDigest) && verify) $ throwE (DigestError cDigest eDigest)
|
||||||
|
|
||||||
|
|
||||||
-- | Get additional curl args from env. This is an undocumented option.
|
-- | Get additional curl args from env. This is an undocumented option.
|
||||||
getCurlOpts :: IO [ByteString]
|
getCurlOpts :: IO [String]
|
||||||
getCurlOpts =
|
getCurlOpts =
|
||||||
getEnv "GHCUP_CURL_OPTS" >>= \case
|
lookupEnv "GHCUP_CURL_OPTS" >>= \case
|
||||||
Just r -> pure $ BS.split _space r
|
Just r -> pure $ splitOn " " r
|
||||||
Nothing -> pure []
|
Nothing -> pure []
|
||||||
|
|
||||||
|
|
||||||
-- | Get additional wget args from env. This is an undocumented option.
|
-- | Get additional wget args from env. This is an undocumented option.
|
||||||
getWgetOpts :: IO [ByteString]
|
getWgetOpts :: IO [String]
|
||||||
getWgetOpts =
|
getWgetOpts =
|
||||||
getEnv "GHCUP_WGET_OPTS" >>= \case
|
lookupEnv "GHCUP_WGET_OPTS" >>= \case
|
||||||
Just r -> pure $ BS.split _space r
|
Just r -> pure $ splitOn " " r
|
||||||
Nothing -> pure []
|
Nothing -> pure []
|
||||||
|
|
||||||
|
|
||||||
|
urlBaseName :: ByteString -- ^ the url path (without scheme and host)
|
||||||
|
-> ByteString
|
||||||
|
urlBaseName = snd . B.breakEnd (== _slash) . urlDecode False
|
||||||
|
|
||||||
|
|||||||
@@ -9,9 +9,7 @@ module GHCup.Download.IOStreams where
|
|||||||
|
|
||||||
import GHCup.Download.Utils
|
import GHCup.Download.Utils
|
||||||
import GHCup.Errors
|
import GHCup.Errors
|
||||||
import GHCup.Types.Optics
|
|
||||||
import GHCup.Types.JSON ( )
|
import GHCup.Types.JSON ( )
|
||||||
import GHCup.Utils.File
|
|
||||||
import GHCup.Utils.Prelude
|
import GHCup.Utils.Prelude
|
||||||
|
|
||||||
import Control.Applicative
|
import Control.Applicative
|
||||||
@@ -20,12 +18,10 @@ import Control.Monad
|
|||||||
import Control.Monad.Reader
|
import Control.Monad.Reader
|
||||||
import Data.ByteString ( ByteString )
|
import Data.ByteString ( ByteString )
|
||||||
import Data.ByteString.Builder
|
import Data.ByteString.Builder
|
||||||
import Data.CaseInsensitive ( CI )
|
import Data.CaseInsensitive ( CI, original, mk )
|
||||||
import Data.IORef
|
import Data.IORef
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
import Data.Text.Read
|
import Data.Text.Read
|
||||||
import HPath
|
|
||||||
import HPath.IO as HIO
|
|
||||||
import Haskus.Utils.Variant.Excepts
|
import Haskus.Utils.Variant.Excepts
|
||||||
import Network.Http.Client hiding ( URL )
|
import Network.Http.Client hiding ( URL )
|
||||||
import Optics
|
import Optics
|
||||||
@@ -33,10 +29,6 @@ import Prelude hiding ( abs
|
|||||||
, readFile
|
, readFile
|
||||||
, writeFile
|
, writeFile
|
||||||
)
|
)
|
||||||
import "unix" System.Posix.IO.ByteString
|
|
||||||
hiding ( fdWrite )
|
|
||||||
import "unix-bytestring" System.Posix.IO.ByteString
|
|
||||||
( fdWrite )
|
|
||||||
import System.ProgressBar
|
import System.ProgressBar
|
||||||
import URI.ByteString
|
import URI.ByteString
|
||||||
|
|
||||||
@@ -72,7 +64,7 @@ downloadBS' :: MonadIO m
|
|||||||
downloadBS' https host path port = do
|
downloadBS' https host path port = do
|
||||||
bref <- liftIO $ newIORef (mempty :: Builder)
|
bref <- liftIO $ newIORef (mempty :: Builder)
|
||||||
let stepper bs = modifyIORef bref (<> byteString bs)
|
let stepper bs = modifyIORef bref (<> byteString bs)
|
||||||
downloadInternal False https host path port stepper
|
void $ downloadInternal False https host path port stepper (pure ()) mempty
|
||||||
liftIO (readIORef bref <&> toLazyByteString)
|
liftIO (readIORef bref <&> toLazyByteString)
|
||||||
|
|
||||||
|
|
||||||
@@ -81,13 +73,18 @@ downloadToFile :: (MonadMask m, MonadIO m)
|
|||||||
-> ByteString -- ^ host (e.g. "www.example.com")
|
-> ByteString -- ^ host (e.g. "www.example.com")
|
||||||
-> ByteString -- ^ path (e.g. "/my/file") including query
|
-> ByteString -- ^ path (e.g. "/my/file") including query
|
||||||
-> Maybe Int -- ^ optional port (e.g. 3000)
|
-> Maybe Int -- ^ optional port (e.g. 3000)
|
||||||
-> Path Abs -- ^ destination file to create and write to
|
-> FilePath -- ^ destination file to create and write to
|
||||||
-> Excepts '[DownloadFailed] m ()
|
-> M.Map (CI ByteString) ByteString -- ^ additional headers
|
||||||
downloadToFile https host fullPath port destFile = do
|
-> Excepts '[DownloadFailed, HTTPNotModified] m Response
|
||||||
fd <- liftIO $ createRegularFileFd newFilePerms destFile
|
downloadToFile https host fullPath port destFile addHeaders = do
|
||||||
let stepper = fdWrite fd
|
let stepper = BS.appendFile destFile
|
||||||
flip finally (liftIO $ closeFd fd)
|
setup = BS.writeFile destFile mempty
|
||||||
$ reThrowAll DownloadFailed $ downloadInternal True https host fullPath port stepper
|
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
|
downloadInternal :: MonadIO m
|
||||||
@@ -97,6 +94,8 @@ downloadInternal :: MonadIO m
|
|||||||
-> ByteString -- ^ path with query
|
-> ByteString -- ^ path with query
|
||||||
-> Maybe Int -- ^ optional port
|
-> Maybe Int -- ^ optional port
|
||||||
-> (ByteString -> IO a) -- ^ the consuming step function
|
-> (ByteString -> IO a) -- ^ the consuming step function
|
||||||
|
-> IO a -- ^ setup action
|
||||||
|
-> M.Map (CI ByteString) ByteString -- ^ additional headers
|
||||||
-> Excepts
|
-> Excepts
|
||||||
'[ HTTPStatusError
|
'[ HTTPStatusError
|
||||||
, URIParseError
|
, URIParseError
|
||||||
@@ -105,19 +104,21 @@ downloadInternal :: MonadIO m
|
|||||||
, TooManyRedirs
|
, TooManyRedirs
|
||||||
]
|
]
|
||||||
m
|
m
|
||||||
()
|
Response
|
||||||
downloadInternal = go (5 :: Int)
|
downloadInternal = go (5 :: Int)
|
||||||
|
|
||||||
where
|
where
|
||||||
go redirs progressBar https host path port consumer = do
|
go redirs progressBar https host path port consumer setup addHeaders = do
|
||||||
r <- liftIO $ withConnection' https host port action
|
r <- liftIO $ withConnection' https host port action
|
||||||
veitherToExcepts r >>= \case
|
veitherToExcepts r >>= \case
|
||||||
Just r' ->
|
Right r' ->
|
||||||
if redirs > 0 then followRedirectURL r' else throwE TooManyRedirs
|
if redirs > 0 then followRedirectURL r' else throwE TooManyRedirs
|
||||||
Nothing -> pure ()
|
Left res -> pure res
|
||||||
where
|
where
|
||||||
action c = do
|
action c = do
|
||||||
let q = buildRequest1 $ http GET path
|
let q = buildRequest1 $ do
|
||||||
|
http GET path
|
||||||
|
flip M.traverseWithKey addHeaders $ \key val -> setHeader (original key) val
|
||||||
|
|
||||||
sendRequest c q emptyBody
|
sendRequest c q emptyBody
|
||||||
|
|
||||||
@@ -126,28 +127,30 @@ downloadInternal = go (5 :: Int)
|
|||||||
(\r i' -> runE $ do
|
(\r i' -> runE $ do
|
||||||
let scode = getStatusCode r
|
let scode = getStatusCode r
|
||||||
if
|
if
|
||||||
| scode >= 200 && scode < 300 -> downloadStream r i' >> pure Nothing
|
| scode >= 200 && scode < 300 -> liftIO $ downloadStream r i' >> pure (Left r)
|
||||||
|
| scode == 304 -> throwE $ HTTPStatusError scode (getHeaderMap r)
|
||||||
| scode >= 300 && scode < 400 -> case getHeader r "Location" of
|
| scode >= 300 && scode < 400 -> case getHeader r "Location" of
|
||||||
Just r' -> pure $ Just r'
|
Just r' -> pure $ Right r'
|
||||||
Nothing -> throwE NoLocationHeader
|
Nothing -> throwE NoLocationHeader
|
||||||
| otherwise -> throwE $ HTTPStatusError scode
|
| otherwise -> throwE $ HTTPStatusError scode (getHeaderMap r)
|
||||||
)
|
)
|
||||||
|
|
||||||
followRedirectURL bs = case parseURI strictURIParserOptions bs of
|
followRedirectURL bs = case parseURI strictURIParserOptions bs of
|
||||||
Right uri' -> do
|
Right uri' -> do
|
||||||
(https', host', fullPath', port') <- liftE $ uriToQuadruple uri'
|
(https', host', fullPath', port') <- liftE $ uriToQuadruple uri'
|
||||||
go (redirs - 1) progressBar https' host' fullPath' port' consumer
|
go (redirs - 1) progressBar https' host' fullPath' port' consumer setup addHeaders
|
||||||
Left e -> throwE e
|
Left e -> throwE e
|
||||||
|
|
||||||
downloadStream r i' = do
|
downloadStream r i' = do
|
||||||
|
void setup
|
||||||
let size = case getHeader r "Content-Length" of
|
let size = case getHeader r "Content-Length" of
|
||||||
Just x' -> case decimal $ decUTF8Safe x' of
|
Just x' -> case decimal $ decUTF8Safe x' of
|
||||||
Left _ -> 0
|
Left _ -> 0
|
||||||
Right (r', _) -> r'
|
Right (r', _) -> r'
|
||||||
Nothing -> 0
|
Nothing -> 0
|
||||||
|
|
||||||
mpb <- if progressBar
|
(mpb :: Maybe (ProgressBar ())) <- if progressBar
|
||||||
then Just <$> liftIO (newProgressBar defStyle 10 (Progress 0 size ()))
|
then Just <$> newProgressBar defStyle 10 (Progress 0 size ())
|
||||||
else pure Nothing
|
else pure Nothing
|
||||||
|
|
||||||
outStream <- liftIO $ Streams.makeOutputStream
|
outStream <- liftIO $ Streams.makeOutputStream
|
||||||
@@ -160,79 +163,6 @@ downloadInternal = go (5 :: Int)
|
|||||||
liftIO $ Streams.connect i' outStream
|
liftIO $ Streams.connect i' outStream
|
||||||
|
|
||||||
|
|
||||||
getHead :: (MonadCatch m, MonadIO m)
|
|
||||||
=> URI
|
|
||||||
-> Excepts
|
|
||||||
'[ HTTPStatusError
|
|
||||||
, URIParseError
|
|
||||||
, UnsupportedScheme
|
|
||||||
, NoLocationHeader
|
|
||||||
, TooManyRedirs
|
|
||||||
, ProcessError
|
|
||||||
]
|
|
||||||
m
|
|
||||||
(M.Map (CI ByteString) ByteString)
|
|
||||||
getHead uri' | scheme == "https" = head' True
|
|
||||||
| scheme == "http" = head' False
|
|
||||||
| otherwise = throwE UnsupportedScheme
|
|
||||||
|
|
||||||
where
|
|
||||||
scheme = view (uriSchemeL' % schemeBSL') uri'
|
|
||||||
head' https = do
|
|
||||||
(_, host', fullPath', port') <- liftE $ uriToQuadruple uri'
|
|
||||||
liftE $ headInternal https host' fullPath' port'
|
|
||||||
|
|
||||||
|
|
||||||
headInternal :: MonadIO m
|
|
||||||
=> Bool -- ^ https?
|
|
||||||
-> ByteString -- ^ host
|
|
||||||
-> ByteString -- ^ path with query
|
|
||||||
-> Maybe Int -- ^ optional port
|
|
||||||
-> Excepts
|
|
||||||
'[ HTTPStatusError
|
|
||||||
, URIParseError
|
|
||||||
, UnsupportedScheme
|
|
||||||
, TooManyRedirs
|
|
||||||
, NoLocationHeader
|
|
||||||
]
|
|
||||||
m
|
|
||||||
(M.Map (CI ByteString) ByteString)
|
|
||||||
headInternal = go (5 :: Int)
|
|
||||||
|
|
||||||
where
|
|
||||||
go redirs https host path port = do
|
|
||||||
r <- liftIO $ withConnection' https host port action
|
|
||||||
veitherToExcepts r >>= \case
|
|
||||||
Left r' ->
|
|
||||||
if redirs > 0 then followRedirectURL r' else throwE TooManyRedirs
|
|
||||||
Right hs -> pure hs
|
|
||||||
where
|
|
||||||
|
|
||||||
action c = do
|
|
||||||
let q = buildRequest1 $ http HEAD path
|
|
||||||
|
|
||||||
sendRequest c q emptyBody
|
|
||||||
|
|
||||||
unsafeReceiveResponse
|
|
||||||
c
|
|
||||||
(\r _ -> runE $ do
|
|
||||||
let scode = getStatusCode r
|
|
||||||
if
|
|
||||||
| scode >= 200 && scode < 300 -> do
|
|
||||||
let headers = getHeaderMap r
|
|
||||||
pure $ Right headers
|
|
||||||
| scode >= 300 && scode < 400 -> case getHeader r "Location" of
|
|
||||||
Just r' -> pure $ Left r'
|
|
||||||
Nothing -> throwE NoLocationHeader
|
|
||||||
| otherwise -> throwE $ HTTPStatusError scode
|
|
||||||
)
|
|
||||||
|
|
||||||
followRedirectURL bs = case parseURI strictURIParserOptions bs of
|
|
||||||
Right uri' -> do
|
|
||||||
(https', host', fullPath', port') <- liftE $ uriToQuadruple uri'
|
|
||||||
go (redirs - 1) https' host' fullPath' port'
|
|
||||||
Left e -> throwE e
|
|
||||||
|
|
||||||
|
|
||||||
withConnection' :: Bool
|
withConnection' :: Bool
|
||||||
-> ByteString
|
-> ByteString
|
||||||
|
|||||||
@@ -15,27 +15,30 @@ Copyright : (c) Julian Ospald, 2020
|
|||||||
License : LGPL-3.0
|
License : LGPL-3.0
|
||||||
Maintainer : hasufell@hasufell.de
|
Maintainer : hasufell@hasufell.de
|
||||||
Stability : experimental
|
Stability : experimental
|
||||||
Portability : POSIX
|
Portability : portable
|
||||||
-}
|
-}
|
||||||
module GHCup.Errors where
|
module GHCup.Errors where
|
||||||
|
|
||||||
import GHCup.Types
|
import GHCup.Types
|
||||||
import GHCup.Utils.Prelude
|
|
||||||
|
|
||||||
#if !defined(TAR)
|
#if !defined(TAR)
|
||||||
import Codec.Archive
|
import Codec.Archive
|
||||||
|
#else
|
||||||
|
import qualified Codec.Archive.Tar as Tar
|
||||||
#endif
|
#endif
|
||||||
import Control.Exception.Safe
|
import Control.Exception.Safe
|
||||||
import Data.ByteString ( ByteString )
|
import Data.ByteString ( ByteString )
|
||||||
|
import Data.CaseInsensitive ( CI )
|
||||||
import Data.String.Interpolate
|
import Data.String.Interpolate
|
||||||
import Data.Text ( Text )
|
import Data.Text ( Text )
|
||||||
import Data.Versions
|
import Data.Versions
|
||||||
import HPath
|
|
||||||
import Haskus.Utils.Variant
|
import Haskus.Utils.Variant
|
||||||
import Text.PrettyPrint
|
import Text.PrettyPrint hiding ( (<>) )
|
||||||
import Text.PrettyPrint.HughesPJClass
|
import Text.PrettyPrint.HughesPJClass hiding ( (<>) )
|
||||||
import URI.ByteString
|
import URI.ByteString
|
||||||
|
|
||||||
|
import qualified Data.Map.Strict as M
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
------------------------
|
------------------------
|
||||||
@@ -84,12 +87,12 @@ instance Pretty DistroNotFound where
|
|||||||
text "Unable to figure out the distribution of the host."
|
text "Unable to figure out the distribution of the host."
|
||||||
|
|
||||||
-- | The archive format is unknown. We don't know how to extract it.
|
-- | The archive format is unknown. We don't know how to extract it.
|
||||||
data UnknownArchive = UnknownArchive ByteString
|
data UnknownArchive = UnknownArchive FilePath
|
||||||
deriving Show
|
deriving Show
|
||||||
|
|
||||||
instance Pretty UnknownArchive where
|
instance Pretty UnknownArchive where
|
||||||
pPrint (UnknownArchive file) =
|
pPrint (UnknownArchive file) =
|
||||||
text [i|The archive format is unknown. We don't know how to extract the file "#{decUTF8Safe file}"|]
|
text [i|The archive format is unknown. We don't know how to extract the file "#{file}"|]
|
||||||
|
|
||||||
-- | The scheme is not supported (such as ftp).
|
-- | The scheme is not supported (such as ftp).
|
||||||
data UnsupportedScheme = UnsupportedScheme
|
data UnsupportedScheme = UnsupportedScheme
|
||||||
@@ -141,12 +144,12 @@ instance Pretty NotInstalled where
|
|||||||
text [i|The version "#{prettyShow ver}" of the tool "#{tool}" is not installed.|]
|
text [i|The version "#{prettyShow ver}" of the tool "#{tool}" is not installed.|]
|
||||||
|
|
||||||
-- | An executable was expected to be in PATH, but was not found.
|
-- | An executable was expected to be in PATH, but was not found.
|
||||||
data NotFoundInPATH = NotFoundInPATH (Path Rel)
|
data NotFoundInPATH = NotFoundInPATH FilePath
|
||||||
deriving Show
|
deriving Show
|
||||||
|
|
||||||
instance Pretty NotFoundInPATH where
|
instance Pretty NotFoundInPATH where
|
||||||
pPrint (NotFoundInPATH exe) =
|
pPrint (NotFoundInPATH exe) =
|
||||||
text [i|The exe "#{decUTF8Safe . toFilePath $ exe}" was not found in PATH.|]
|
text [i|The exe "#{exe}" was not found in PATH.|]
|
||||||
|
|
||||||
-- | JSON decoding failed.
|
-- | JSON decoding failed.
|
||||||
data JSONError = JSONDecodeError String
|
data JSONError = JSONDecodeError String
|
||||||
@@ -158,12 +161,12 @@ instance Pretty JSONError where
|
|||||||
|
|
||||||
-- | A file that is supposed to exist does not exist
|
-- | A file that is supposed to exist does not exist
|
||||||
-- (e.g. when we use file scheme to "download" something).
|
-- (e.g. when we use file scheme to "download" something).
|
||||||
data FileDoesNotExistError = FileDoesNotExistError ByteString
|
data FileDoesNotExistError = FileDoesNotExistError FilePath
|
||||||
deriving Show
|
deriving Show
|
||||||
|
|
||||||
instance Pretty FileDoesNotExistError where
|
instance Pretty FileDoesNotExistError where
|
||||||
pPrint (FileDoesNotExistError file) =
|
pPrint (FileDoesNotExistError file) =
|
||||||
text [i|File "#{decUTF8Safe file}" does not exist.|]
|
text [i|File "#{file}" does not exist.|]
|
||||||
|
|
||||||
data TarDirDoesNotExist = TarDirDoesNotExist TarDir
|
data TarDirDoesNotExist = TarDirDoesNotExist TarDir
|
||||||
deriving Show
|
deriving Show
|
||||||
@@ -181,13 +184,29 @@ instance Pretty DigestError where
|
|||||||
text [i|Digest error: expected "#{expectedDigest}", but got "#{currentDigest}"|]
|
text [i|Digest error: expected "#{expectedDigest}", but got "#{currentDigest}"|]
|
||||||
|
|
||||||
-- | Unexpected HTTP status.
|
-- | Unexpected HTTP status.
|
||||||
data HTTPStatusError = HTTPStatusError Int
|
data HTTPStatusError = HTTPStatusError Int (M.Map (CI ByteString) ByteString)
|
||||||
deriving Show
|
deriving Show
|
||||||
|
|
||||||
instance Pretty HTTPStatusError where
|
instance Pretty HTTPStatusError where
|
||||||
pPrint (HTTPStatusError status) =
|
pPrint (HTTPStatusError status _) =
|
||||||
text [i|Unexpected HTTP status: #{status}|]
|
text [i|Unexpected HTTP status: #{status}|]
|
||||||
|
|
||||||
|
-- | Malformed headers.
|
||||||
|
data MalformedHeaders = MalformedHeaders Text
|
||||||
|
deriving Show
|
||||||
|
|
||||||
|
instance Pretty MalformedHeaders where
|
||||||
|
pPrint (MalformedHeaders h) =
|
||||||
|
text [i|Headers are malformed: #{h}|]
|
||||||
|
|
||||||
|
-- | Unexpected HTTP status.
|
||||||
|
data HTTPNotModified = HTTPNotModified Text
|
||||||
|
deriving Show
|
||||||
|
|
||||||
|
instance Pretty HTTPNotModified where
|
||||||
|
pPrint (HTTPNotModified etag) =
|
||||||
|
text [i|Remote resource not modifed, etag was: #{etag}|]
|
||||||
|
|
||||||
-- | The 'Location' header was expected during a 3xx redirect, but not found.
|
-- | The 'Location' header was expected during a 3xx redirect, but not found.
|
||||||
data NoLocationHeader = NoLocationHeader
|
data NoLocationHeader = NoLocationHeader
|
||||||
deriving Show
|
deriving Show
|
||||||
@@ -234,6 +253,20 @@ instance Pretty NoToolVersionSet where
|
|||||||
pPrint (NoToolVersionSet tool) =
|
pPrint (NoToolVersionSet tool) =
|
||||||
text [i|No version is set for tool "#{tool}".|]
|
text [i|No version is set for tool "#{tool}".|]
|
||||||
|
|
||||||
|
data NoNetwork = NoNetwork
|
||||||
|
deriving Show
|
||||||
|
|
||||||
|
instance Pretty NoNetwork where
|
||||||
|
pPrint NoNetwork =
|
||||||
|
text [i|A download was required or requested, but '--offline' was specified.|]
|
||||||
|
|
||||||
|
data HadrianNotFound = HadrianNotFound
|
||||||
|
deriving Show
|
||||||
|
|
||||||
|
instance Pretty HadrianNotFound where
|
||||||
|
pPrint HadrianNotFound =
|
||||||
|
text [i|Could not find Hadrian build files. Does this GHC version support Hadrian builds?|]
|
||||||
|
|
||||||
|
|
||||||
-------------------------
|
-------------------------
|
||||||
--[ High-level errors ]--
|
--[ High-level errors ]--
|
||||||
@@ -250,11 +283,11 @@ deriving instance Show DownloadFailed
|
|||||||
|
|
||||||
|
|
||||||
-- | A build failed.
|
-- | A build failed.
|
||||||
data BuildFailed = forall es . Show (V es) => BuildFailed (Path Abs) (V es)
|
data BuildFailed = forall es . (Pretty (V es), Show (V es)) => BuildFailed FilePath (V es)
|
||||||
|
|
||||||
instance Pretty BuildFailed where
|
instance Pretty BuildFailed where
|
||||||
pPrint (BuildFailed path reason) =
|
pPrint (BuildFailed path reason) =
|
||||||
text [i|BuildFailed failed in dir "#{decUTF8Safe . toFilePath $ path}": #{reason}|]
|
text [i|BuildFailed failed in dir "#{path}": |] <> pPrint reason
|
||||||
|
|
||||||
deriving instance Show BuildFailed
|
deriving instance Show BuildFailed
|
||||||
|
|
||||||
@@ -339,4 +372,14 @@ instance Pretty ArchiveResult where
|
|||||||
pPrint ArchiveRetry = text "Archive result: retry"
|
pPrint ArchiveRetry = text "Archive result: retry"
|
||||||
pPrint ArchiveOk = text "Archive result: Ok"
|
pPrint ArchiveOk = text "Archive result: Ok"
|
||||||
pPrint ArchiveEOF = text "Archive result: EOF"
|
pPrint ArchiveEOF = text "Archive result: EOF"
|
||||||
|
#else
|
||||||
|
instance Pretty Tar.FormatError where
|
||||||
|
pPrint Tar.TruncatedArchive = text "Truncated archive"
|
||||||
|
pPrint Tar.ShortTrailer = text "Short trailer"
|
||||||
|
pPrint Tar.BadTrailer = text "Bad trailer"
|
||||||
|
pPrint Tar.TrailingJunk = text "Trailing junk"
|
||||||
|
pPrint Tar.ChecksumIncorrect = text "Checksum incorrect"
|
||||||
|
pPrint Tar.NotTarFormat = text "Not a tar format"
|
||||||
|
pPrint Tar.UnrecognisedTarFormat = text "Unrecognised tar format"
|
||||||
|
pPrint Tar.HeaderBadNumericEncoding = text "Header has bad numeric encoding"
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ Copyright : (c) Julian Ospald, 2020
|
|||||||
License : LGPL-3.0
|
License : LGPL-3.0
|
||||||
Maintainer : hasufell@hasufell.de
|
Maintainer : hasufell@hasufell.de
|
||||||
Stability : experimental
|
Stability : experimental
|
||||||
Portability : POSIX
|
Portability : portable
|
||||||
-}
|
-}
|
||||||
module GHCup.Platform where
|
module GHCup.Platform where
|
||||||
|
|
||||||
@@ -36,18 +36,21 @@ import Data.Maybe
|
|||||||
import Data.String.Interpolate
|
import Data.String.Interpolate
|
||||||
import Data.Text ( Text )
|
import Data.Text ( Text )
|
||||||
import Data.Versions
|
import Data.Versions
|
||||||
import HPath
|
|
||||||
import HPath.IO
|
|
||||||
import Haskus.Utils.Variant.Excepts
|
import Haskus.Utils.Variant.Excepts
|
||||||
import Prelude hiding ( abs
|
import Prelude hiding ( abs
|
||||||
, readFile
|
, readFile
|
||||||
, writeFile
|
, writeFile
|
||||||
)
|
)
|
||||||
import System.Info
|
import System.Info
|
||||||
|
import System.Directory
|
||||||
import System.OsRelease
|
import System.OsRelease
|
||||||
|
import Text.PrettyPrint.HughesPJClass ( prettyShow )
|
||||||
import Text.Regex.Posix
|
import Text.Regex.Posix
|
||||||
|
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
|
import qualified Data.Text.IO as T
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--------------------------
|
--------------------------
|
||||||
--[ Platform detection ]--
|
--[ Platform detection ]--
|
||||||
@@ -55,7 +58,7 @@ import qualified Data.Text as T
|
|||||||
|
|
||||||
|
|
||||||
-- | Get the full platform request, consisting of architecture, distro, ...
|
-- | Get the full platform request, consisting of architecture, distro, ...
|
||||||
platformRequest :: (MonadLogger m, MonadCatch m, MonadIO m)
|
platformRequest :: (Alternative m, MonadFail m, MonadLogger m, MonadCatch m, MonadIO m)
|
||||||
=> Excepts
|
=> Excepts
|
||||||
'[NoCompatiblePlatform, NoCompatibleArch, DistroNotFound]
|
'[NoCompatiblePlatform, NoCompatibleArch, DistroNotFound]
|
||||||
m
|
m
|
||||||
@@ -80,7 +83,7 @@ getArchitecture = case arch of
|
|||||||
what -> Left (NoCompatibleArch what)
|
what -> Left (NoCompatibleArch what)
|
||||||
|
|
||||||
|
|
||||||
getPlatform :: (MonadLogger m, MonadCatch m, MonadIO m)
|
getPlatform :: (Alternative m, MonadLogger m, MonadCatch m, MonadIO m, MonadFail m)
|
||||||
=> Excepts
|
=> Excepts
|
||||||
'[NoCompatiblePlatform, DistroNotFound]
|
'[NoCompatiblePlatform, DistroNotFound]
|
||||||
m
|
m
|
||||||
@@ -95,36 +98,34 @@ getPlatform = do
|
|||||||
either (const Nothing) Just
|
either (const Nothing) Just
|
||||||
. versioning
|
. versioning
|
||||||
-- TODO: maybe do this somewhere else
|
-- TODO: maybe do this somewhere else
|
||||||
. getMajorVersion
|
. decUTF8Safe'
|
||||||
. decUTF8Safe
|
|
||||||
<$> getDarwinVersion
|
<$> getDarwinVersion
|
||||||
pure $ PlatformResult { _platform = Darwin, _distroVersion = ver }
|
pure $ PlatformResult { _platform = Darwin, _distroVersion = ver }
|
||||||
"freebsd" -> do
|
"freebsd" -> do
|
||||||
ver <-
|
ver <-
|
||||||
either (const Nothing) Just . versioning . decUTF8Safe
|
either (const Nothing) Just . versioning . decUTF8Safe'
|
||||||
<$> getFreeBSDVersion
|
<$> getFreeBSDVersion
|
||||||
pure $ PlatformResult { _platform = FreeBSD, _distroVersion = ver }
|
pure $ PlatformResult { _platform = FreeBSD, _distroVersion = ver }
|
||||||
|
"mingw32" -> pure PlatformResult { _platform = Windows, _distroVersion = Nothing }
|
||||||
what -> throwE $ NoCompatiblePlatform what
|
what -> throwE $ NoCompatiblePlatform what
|
||||||
lift $ $(logDebug) [i|Identified Platform as: #{pfr}|]
|
lift $ $(logDebug) [i|Identified Platform as: #{prettyShow pfr}|]
|
||||||
pure pfr
|
pure pfr
|
||||||
where
|
where
|
||||||
getMajorVersion = T.intercalate "." . take 2 . T.split (== '.')
|
getFreeBSDVersion = lift $ fmap _stdOut $ executeOut "freebsd-version" [] Nothing
|
||||||
getFreeBSDVersion =
|
getDarwinVersion = lift $ fmap _stdOut $ executeOut "sw_vers"
|
||||||
liftIO $ fmap _stdOut $ executeOut [rel|freebsd-version|] [] Nothing
|
|
||||||
getDarwinVersion = liftIO $ fmap _stdOut $ executeOut [rel|sw_vers|]
|
|
||||||
["-productVersion"]
|
["-productVersion"]
|
||||||
Nothing
|
Nothing
|
||||||
|
|
||||||
|
|
||||||
getLinuxDistro :: (MonadCatch m, MonadIO m)
|
getLinuxDistro :: (Alternative m, MonadCatch m, MonadIO m, MonadFail m)
|
||||||
=> Excepts '[DistroNotFound] m (LinuxDistro, Maybe Versioning)
|
=> Excepts '[DistroNotFound] m (LinuxDistro, Maybe Versioning)
|
||||||
getLinuxDistro = do
|
getLinuxDistro = do
|
||||||
-- TODO: don't do alternative on IO, because it hides bugs
|
-- TODO: don't do alternative on IO, because it hides bugs
|
||||||
(name, ver) <- handleIO (\_ -> throwE DistroNotFound) $ liftIO $ asum
|
(name, ver) <- handleIO (\_ -> throwE DistroNotFound) $ lift $ asum
|
||||||
[ try_os_release
|
[ liftIO try_os_release
|
||||||
, try_lsb_release_cmd
|
, try_lsb_release_cmd
|
||||||
, try_redhat_release
|
, liftIO try_redhat_release
|
||||||
, try_debian_version
|
, liftIO try_debian_version
|
||||||
]
|
]
|
||||||
let parsedVer = ver >>= either (const Nothing) Just . versioning
|
let parsedVer = ver >>= either (const Nothing) Just . versioning
|
||||||
distro = if
|
distro = if
|
||||||
@@ -147,12 +148,12 @@ getLinuxDistro = do
|
|||||||
where
|
where
|
||||||
regex x = makeRegexOpts compIgnoreCase execBlank ([s|\<|] ++ x ++ [s|\>|])
|
regex x = makeRegexOpts compIgnoreCase execBlank ([s|\<|] ++ x ++ [s|\>|])
|
||||||
|
|
||||||
lsb_release_cmd :: Path Rel
|
lsb_release_cmd :: FilePath
|
||||||
lsb_release_cmd = [rel|lsb-release|]
|
lsb_release_cmd = "lsb-release"
|
||||||
redhat_release :: Path Abs
|
redhat_release :: FilePath
|
||||||
redhat_release = [abs|/etc/redhat-release|]
|
redhat_release = "/etc/redhat-release"
|
||||||
debian_version :: Path Abs
|
debian_version :: FilePath
|
||||||
debian_version = [abs|/etc/debian_version|]
|
debian_version = "/etc/debian_version"
|
||||||
|
|
||||||
try_os_release :: IO (Text, Maybe Text)
|
try_os_release :: IO (Text, Maybe Text)
|
||||||
try_os_release = do
|
try_os_release = do
|
||||||
@@ -160,16 +161,17 @@ getLinuxDistro = do
|
|||||||
fmap osRelease <$> parseOsRelease
|
fmap osRelease <$> parseOsRelease
|
||||||
pure (T.pack name, fmap T.pack version_id)
|
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
|
try_lsb_release_cmd = do
|
||||||
(Just _) <- findExecutable lsb_release_cmd
|
(Just _) <- liftIO $ findExecutable lsb_release_cmd
|
||||||
name <- fmap _stdOut $ executeOut lsb_release_cmd ["-si"] Nothing
|
name <- fmap _stdOut $ executeOut lsb_release_cmd ["-si"] Nothing
|
||||||
ver <- fmap _stdOut $ executeOut lsb_release_cmd ["-sr"] Nothing
|
ver <- fmap _stdOut $ executeOut lsb_release_cmd ["-sr"] Nothing
|
||||||
pure (decUTF8Safe name, Just $ decUTF8Safe ver)
|
pure (decUTF8Safe' name, Just $ decUTF8Safe' ver)
|
||||||
|
|
||||||
try_redhat_release :: IO (Text, Maybe Text)
|
try_redhat_release :: IO (Text, Maybe Text)
|
||||||
try_redhat_release = do
|
try_redhat_release = do
|
||||||
t <- fmap decUTF8Safe' $ readFile redhat_release
|
t <- T.readFile redhat_release
|
||||||
let nameRegex n =
|
let nameRegex n =
|
||||||
makeRegexOpts compIgnoreCase
|
makeRegexOpts compIgnoreCase
|
||||||
execBlank
|
execBlank
|
||||||
@@ -191,5 +193,5 @@ getLinuxDistro = do
|
|||||||
|
|
||||||
try_debian_version :: IO (Text, Maybe Text)
|
try_debian_version :: IO (Text, Maybe Text)
|
||||||
try_debian_version = do
|
try_debian_version = do
|
||||||
ver <- readFile debian_version
|
ver <- T.readFile debian_version
|
||||||
pure (T.pack "debian", Just . decUTF8Safe' $ ver)
|
pure (T.pack "debian", Just ver)
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ Copyright : (c) Julian Ospald, 2020
|
|||||||
License : LGPL-3.0
|
License : LGPL-3.0
|
||||||
Maintainer : hasufell@hasufell.de
|
Maintainer : hasufell@hasufell.de
|
||||||
Stability : experimental
|
Stability : experimental
|
||||||
Portability : POSIX
|
Portability : portable
|
||||||
-}
|
-}
|
||||||
module GHCup.Requirements where
|
module GHCup.Requirements where
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
{-# OPTIONS_GHC -Wno-orphans #-}
|
{-# OPTIONS_GHC -Wno-orphans #-}
|
||||||
{-# LANGUAGE CPP #-}
|
{-# LANGUAGE CPP #-}
|
||||||
|
{-# LANGUAGE BangPatterns #-}
|
||||||
|
{-# LANGUAGE DataKinds #-}
|
||||||
{-# LANGUAGE DeriveGeneric #-}
|
{-# LANGUAGE DeriveGeneric #-}
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
{-# LANGUAGE QuasiQuotes #-}
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
|
{-# LANGUAGE FlexibleInstances #-}
|
||||||
|
{-# LANGUAGE DuplicateRecordFields #-}
|
||||||
|
|
||||||
{-|
|
{-|
|
||||||
Module : GHCup.Types
|
Module : GHCup.Types
|
||||||
@@ -11,26 +15,44 @@ Copyright : (c) Julian Ospald, 2020
|
|||||||
License : LGPL-3.0
|
License : LGPL-3.0
|
||||||
Maintainer : hasufell@hasufell.de
|
Maintainer : hasufell@hasufell.de
|
||||||
Stability : experimental
|
Stability : experimental
|
||||||
Portability : POSIX
|
Portability : portable
|
||||||
-}
|
-}
|
||||||
module GHCup.Types where
|
module GHCup.Types
|
||||||
|
( module GHCup.Types
|
||||||
|
#if defined(BRICK)
|
||||||
|
, Key(..)
|
||||||
|
#endif
|
||||||
|
)
|
||||||
|
where
|
||||||
|
|
||||||
|
import Control.Applicative
|
||||||
|
import Control.DeepSeq ( NFData, rnf )
|
||||||
|
import Control.Monad.Logger
|
||||||
import Data.Map.Strict ( Map )
|
import Data.Map.Strict ( Map )
|
||||||
import Data.List.NonEmpty ( NonEmpty (..) )
|
import Data.List.NonEmpty ( NonEmpty (..) )
|
||||||
import Data.String.Interpolate
|
|
||||||
import Data.Text ( Text )
|
import Data.Text ( Text )
|
||||||
import Data.Versions
|
import Data.Versions
|
||||||
import HPath
|
import Haskus.Utils.Variant.Excepts
|
||||||
import Text.PrettyPrint.HughesPJClass (Pretty, pPrint, text)
|
import Text.PrettyPrint.HughesPJClass (Pretty, pPrint, text)
|
||||||
import URI.ByteString
|
import URI.ByteString
|
||||||
|
#if defined(BRICK)
|
||||||
|
import Graphics.Vty ( Key(..) )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
import qualified Control.Monad.Trans.Class as Trans
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import qualified Data.Text.Encoding as E
|
|
||||||
import qualified Data.Text.Encoding.Error as E
|
|
||||||
import qualified GHC.Generics as GHC
|
import qualified GHC.Generics as GHC
|
||||||
import qualified Graphics.Vty as Vty
|
|
||||||
|
|
||||||
|
|
||||||
|
#if !defined(BRICK)
|
||||||
|
data Key = KEsc | KChar Char | KBS | KEnter
|
||||||
|
| KLeft | KRight | KUp | KDown
|
||||||
|
| KUpLeft | KUpRight | KDownLeft | KDownRight | KCenter
|
||||||
|
| KFun Int | KBackTab | KPrtScr | KPause | KIns
|
||||||
|
| KHome | KPageUp | KDel | KEnd | KPageDown | KBegin | KMenu
|
||||||
|
deriving (Eq,Show,Read,Ord,GHC.Generic)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
--------------------
|
--------------------
|
||||||
--[ GHCInfo Tree ]--
|
--[ GHCInfo Tree ]--
|
||||||
@@ -40,9 +62,12 @@ import qualified Graphics.Vty as Vty
|
|||||||
data GHCupInfo = GHCupInfo
|
data GHCupInfo = GHCupInfo
|
||||||
{ _toolRequirements :: ToolRequirements
|
{ _toolRequirements :: ToolRequirements
|
||||||
, _ghcupDownloads :: GHCupDownloads
|
, _ghcupDownloads :: GHCupDownloads
|
||||||
|
, _globalTools :: Map GlobalTool DownloadInfo
|
||||||
}
|
}
|
||||||
deriving (Show, GHC.Generic)
|
deriving (Show, GHC.Generic)
|
||||||
|
|
||||||
|
instance NFData GHCupInfo
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-------------------------
|
-------------------------
|
||||||
@@ -62,6 +87,8 @@ data Requirements = Requirements
|
|||||||
}
|
}
|
||||||
deriving (Show, GHC.Generic)
|
deriving (Show, GHC.Generic)
|
||||||
|
|
||||||
|
instance NFData Requirements
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -85,8 +112,16 @@ data Tool = GHC
|
|||||||
| Cabal
|
| Cabal
|
||||||
| GHCup
|
| GHCup
|
||||||
| HLS
|
| HLS
|
||||||
|
| Stack
|
||||||
deriving (Eq, GHC.Generic, Ord, Show, Enum, Bounded)
|
deriving (Eq, GHC.Generic, Ord, Show, Enum, Bounded)
|
||||||
|
|
||||||
|
instance NFData Tool
|
||||||
|
|
||||||
|
data GlobalTool = ShimGen
|
||||||
|
deriving (Eq, GHC.Generic, Ord, Show, Enum, Bounded)
|
||||||
|
|
||||||
|
instance NFData GlobalTool
|
||||||
|
|
||||||
|
|
||||||
-- | All necessary information of a tool version, including
|
-- | All necessary information of a tool version, including
|
||||||
-- source download and per-architecture downloads.
|
-- source download and per-architecture downloads.
|
||||||
@@ -102,6 +137,8 @@ data VersionInfo = VersionInfo
|
|||||||
}
|
}
|
||||||
deriving (Eq, GHC.Generic, Show)
|
deriving (Eq, GHC.Generic, Show)
|
||||||
|
|
||||||
|
instance NFData VersionInfo
|
||||||
|
|
||||||
|
|
||||||
-- | A tag. These are currently attached to a version of a tool.
|
-- | A tag. These are currently attached to a version of a tool.
|
||||||
data Tag = Latest
|
data Tag = Latest
|
||||||
@@ -112,6 +149,8 @@ data Tag = Latest
|
|||||||
| UnknownTag String -- ^ used for upwardscompat
|
| UnknownTag String -- ^ used for upwardscompat
|
||||||
deriving (Ord, Eq, GHC.Generic, Show) -- FIXME: manual JSON instance
|
deriving (Ord, Eq, GHC.Generic, Show) -- FIXME: manual JSON instance
|
||||||
|
|
||||||
|
instance NFData Tag
|
||||||
|
|
||||||
tagToString :: Tag -> String
|
tagToString :: Tag -> String
|
||||||
tagToString Recommended = "recommended"
|
tagToString Recommended = "recommended"
|
||||||
tagToString Latest = "latest"
|
tagToString Latest = "latest"
|
||||||
@@ -138,6 +177,8 @@ data Architecture = A_64
|
|||||||
| A_ARM64
|
| A_ARM64
|
||||||
deriving (Eq, GHC.Generic, Ord, Show)
|
deriving (Eq, GHC.Generic, Ord, Show)
|
||||||
|
|
||||||
|
instance NFData Architecture
|
||||||
|
|
||||||
archToString :: Architecture -> String
|
archToString :: Architecture -> String
|
||||||
archToString A_64 = "x86_64"
|
archToString A_64 = "x86_64"
|
||||||
archToString A_32 = "i386"
|
archToString A_32 = "i386"
|
||||||
@@ -156,12 +197,17 @@ data Platform = Linux LinuxDistro
|
|||||||
| Darwin
|
| Darwin
|
||||||
-- ^ must exit
|
-- ^ must exit
|
||||||
| FreeBSD
|
| FreeBSD
|
||||||
|
| Windows
|
||||||
|
-- ^ must exit
|
||||||
deriving (Eq, GHC.Generic, Ord, Show)
|
deriving (Eq, GHC.Generic, Ord, Show)
|
||||||
|
|
||||||
|
instance NFData Platform
|
||||||
|
|
||||||
platformToString :: Platform -> String
|
platformToString :: Platform -> String
|
||||||
platformToString (Linux distro) = "linux-" ++ distroToString distro
|
platformToString (Linux distro) = "linux-" ++ distroToString distro
|
||||||
platformToString Darwin = "darwin"
|
platformToString Darwin = "darwin"
|
||||||
platformToString FreeBSD = "freebsd"
|
platformToString FreeBSD = "freebsd"
|
||||||
|
platformToString Windows = "windows"
|
||||||
|
|
||||||
instance Pretty Platform where
|
instance Pretty Platform where
|
||||||
pPrint = text . platformToString
|
pPrint = text . platformToString
|
||||||
@@ -182,6 +228,8 @@ data LinuxDistro = Debian
|
|||||||
-- ^ must exit
|
-- ^ must exit
|
||||||
deriving (Eq, GHC.Generic, Ord, Show)
|
deriving (Eq, GHC.Generic, Ord, Show)
|
||||||
|
|
||||||
|
instance NFData LinuxDistro
|
||||||
|
|
||||||
distroToString :: LinuxDistro -> String
|
distroToString :: LinuxDistro -> String
|
||||||
distroToString Debian = "debian"
|
distroToString Debian = "debian"
|
||||||
distroToString Ubuntu = "ubuntu"
|
distroToString Ubuntu = "ubuntu"
|
||||||
@@ -208,6 +256,7 @@ data DownloadInfo = DownloadInfo
|
|||||||
}
|
}
|
||||||
deriving (Eq, Ord, GHC.Generic, Show)
|
deriving (Eq, Ord, GHC.Generic, Show)
|
||||||
|
|
||||||
|
instance NFData DownloadInfo
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -217,12 +266,14 @@ data DownloadInfo = DownloadInfo
|
|||||||
|
|
||||||
|
|
||||||
-- | How to descend into a tar archive.
|
-- | How to descend into a tar archive.
|
||||||
data TarDir = RealDir (Path Rel)
|
data TarDir = RealDir FilePath
|
||||||
| RegexDir String -- ^ will be compiled to regex, the first match will "win"
|
| RegexDir String -- ^ will be compiled to regex, the first match will "win"
|
||||||
deriving (Eq, Ord, GHC.Generic, Show)
|
deriving (Eq, Ord, GHC.Generic, Show)
|
||||||
|
|
||||||
|
instance NFData TarDir
|
||||||
|
|
||||||
instance Pretty TarDir where
|
instance Pretty TarDir where
|
||||||
pPrint (RealDir path) = text [i|#{E.decodeUtf8With E.lenientDecode . toFilePath $ path}|]
|
pPrint (RealDir path) = text path
|
||||||
pPrint (RegexDir regex) = text regex
|
pPrint (RegexDir regex) = text regex
|
||||||
|
|
||||||
|
|
||||||
@@ -233,6 +284,10 @@ data URLSource = GHCupURL
|
|||||||
| AddSource (Either GHCupInfo URI) -- ^ merge with GHCupURL
|
| AddSource (Either GHCupInfo URI) -- ^ merge with GHCupURL
|
||||||
deriving (GHC.Generic, Show)
|
deriving (GHC.Generic, Show)
|
||||||
|
|
||||||
|
instance NFData URLSource
|
||||||
|
instance NFData (URIRef Absolute) where
|
||||||
|
rnf (URI !_ !_ !_ !_ !_) = ()
|
||||||
|
|
||||||
|
|
||||||
data UserSettings = UserSettings
|
data UserSettings = UserSettings
|
||||||
{ uCache :: Maybe Bool
|
{ uCache :: Maybe Bool
|
||||||
@@ -242,53 +297,73 @@ data UserSettings = UserSettings
|
|||||||
, uDownloader :: Maybe Downloader
|
, uDownloader :: Maybe Downloader
|
||||||
, uKeyBindings :: Maybe UserKeyBindings
|
, uKeyBindings :: Maybe UserKeyBindings
|
||||||
, uUrlSource :: Maybe URLSource
|
, uUrlSource :: Maybe URLSource
|
||||||
|
, uNoNetwork :: Maybe Bool
|
||||||
}
|
}
|
||||||
deriving (Show, GHC.Generic)
|
deriving (Show, GHC.Generic)
|
||||||
|
|
||||||
defaultUserSettings :: UserSettings
|
defaultUserSettings :: UserSettings
|
||||||
defaultUserSettings = UserSettings Nothing Nothing Nothing Nothing Nothing Nothing Nothing
|
defaultUserSettings = UserSettings Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing
|
||||||
|
|
||||||
data UserKeyBindings = UserKeyBindings
|
data UserKeyBindings = UserKeyBindings
|
||||||
{ kUp :: Maybe Vty.Key
|
{ kUp :: Maybe Key
|
||||||
, kDown :: Maybe Vty.Key
|
, kDown :: Maybe Key
|
||||||
, kQuit :: Maybe Vty.Key
|
, kQuit :: Maybe Key
|
||||||
, kInstall :: Maybe Vty.Key
|
, kInstall :: Maybe Key
|
||||||
, kUninstall :: Maybe Vty.Key
|
, kUninstall :: Maybe Key
|
||||||
, kSet :: Maybe Vty.Key
|
, kSet :: Maybe Key
|
||||||
, kChangelog :: Maybe Vty.Key
|
, kChangelog :: Maybe Key
|
||||||
, kShowAll :: Maybe Vty.Key
|
, kShowAll :: Maybe Key
|
||||||
|
, kShowAllTools :: Maybe Key
|
||||||
}
|
}
|
||||||
deriving (Show, GHC.Generic)
|
deriving (Show, GHC.Generic)
|
||||||
|
|
||||||
data KeyBindings = KeyBindings
|
data KeyBindings = KeyBindings
|
||||||
{ bUp :: Vty.Key
|
{ bUp :: Key
|
||||||
, bDown :: Vty.Key
|
, bDown :: Key
|
||||||
, bQuit :: Vty.Key
|
, bQuit :: Key
|
||||||
, bInstall :: Vty.Key
|
, bInstall :: Key
|
||||||
, bUninstall :: Vty.Key
|
, bUninstall :: Key
|
||||||
, bSet :: Vty.Key
|
, bSet :: Key
|
||||||
, bChangelog :: Vty.Key
|
, bChangelog :: Key
|
||||||
, bShowAll :: Vty.Key
|
, bShowAllVersions :: Key
|
||||||
|
, bShowAllTools :: Key
|
||||||
}
|
}
|
||||||
deriving (Show, GHC.Generic)
|
deriving (Show, GHC.Generic)
|
||||||
|
|
||||||
|
instance NFData KeyBindings
|
||||||
|
instance NFData Key
|
||||||
|
|
||||||
defaultKeyBindings :: KeyBindings
|
defaultKeyBindings :: KeyBindings
|
||||||
defaultKeyBindings = KeyBindings
|
defaultKeyBindings = KeyBindings
|
||||||
{ bUp = Vty.KUp
|
{ bUp = KUp
|
||||||
, bDown = Vty.KDown
|
, bDown = KDown
|
||||||
, bQuit = Vty.KChar 'q'
|
, bQuit = KChar 'q'
|
||||||
, bInstall = Vty.KChar 'i'
|
, bInstall = KChar 'i'
|
||||||
, bUninstall = Vty.KChar 'u'
|
, bUninstall = KChar 'u'
|
||||||
, bSet = Vty.KChar 's'
|
, bSet = KChar 's'
|
||||||
, bChangelog = Vty.KChar 'c'
|
, bChangelog = KChar 'c'
|
||||||
, bShowAll = Vty.KChar 'a'
|
, bShowAllVersions = KChar 'a'
|
||||||
|
, bShowAllTools = KChar 't'
|
||||||
}
|
}
|
||||||
|
|
||||||
data AppState = AppState
|
data AppState = AppState
|
||||||
{ settings :: Settings
|
{ settings :: Settings
|
||||||
, dirs :: Dirs
|
, dirs :: Dirs
|
||||||
, keyBindings :: KeyBindings
|
, keyBindings :: KeyBindings
|
||||||
} deriving (Show)
|
, ghcupInfo :: GHCupInfo
|
||||||
|
, pfreq :: PlatformRequest
|
||||||
|
} deriving (Show, GHC.Generic)
|
||||||
|
|
||||||
|
instance NFData AppState
|
||||||
|
|
||||||
|
data LeanAppState = LeanAppState
|
||||||
|
{ settings :: Settings
|
||||||
|
, dirs :: Dirs
|
||||||
|
, keyBindings :: KeyBindings
|
||||||
|
} deriving (Show, GHC.Generic)
|
||||||
|
|
||||||
|
instance NFData LeanAppState
|
||||||
|
|
||||||
|
|
||||||
data Settings = Settings
|
data Settings = Settings
|
||||||
{ cache :: Bool
|
{ cache :: Bool
|
||||||
@@ -297,35 +372,45 @@ data Settings = Settings
|
|||||||
, downloader :: Downloader
|
, downloader :: Downloader
|
||||||
, verbose :: Bool
|
, verbose :: Bool
|
||||||
, urlSource :: URLSource
|
, urlSource :: URLSource
|
||||||
|
, noNetwork :: Bool
|
||||||
}
|
}
|
||||||
deriving (Show, GHC.Generic)
|
deriving (Show, GHC.Generic)
|
||||||
|
|
||||||
|
instance NFData Settings
|
||||||
|
|
||||||
data Dirs = Dirs
|
data Dirs = Dirs
|
||||||
{ baseDir :: Path Abs
|
{ baseDir :: FilePath
|
||||||
, binDir :: Path Abs
|
, binDir :: FilePath
|
||||||
, cacheDir :: Path Abs
|
, cacheDir :: FilePath
|
||||||
, logsDir :: Path Abs
|
, logsDir :: FilePath
|
||||||
, confDir :: Path Abs
|
, confDir :: FilePath
|
||||||
|
, recycleDir :: FilePath -- mainly used on windows
|
||||||
}
|
}
|
||||||
deriving Show
|
deriving (Show, GHC.Generic)
|
||||||
|
|
||||||
|
instance NFData Dirs
|
||||||
|
|
||||||
data KeepDirs = Always
|
data KeepDirs = Always
|
||||||
| Errors
|
| Errors
|
||||||
| Never
|
| Never
|
||||||
deriving (Eq, Show, Ord)
|
deriving (Eq, Show, Ord, GHC.Generic)
|
||||||
|
|
||||||
|
instance NFData KeepDirs
|
||||||
|
|
||||||
data Downloader = Curl
|
data Downloader = Curl
|
||||||
| Wget
|
| Wget
|
||||||
#if defined(INTERNAL_DOWNLOADER)
|
#if defined(INTERNAL_DOWNLOADER)
|
||||||
| Internal
|
| Internal
|
||||||
#endif
|
#endif
|
||||||
deriving (Eq, Show, Ord)
|
deriving (Eq, Show, Ord, GHC.Generic)
|
||||||
|
|
||||||
|
instance NFData Downloader
|
||||||
|
|
||||||
data DebugInfo = DebugInfo
|
data DebugInfo = DebugInfo
|
||||||
{ diBaseDir :: Path Abs
|
{ diBaseDir :: FilePath
|
||||||
, diBinDir :: Path Abs
|
, diBinDir :: FilePath
|
||||||
, diGHCDir :: Path Abs
|
, diGHCDir :: FilePath
|
||||||
, diCacheDir :: Path Abs
|
, diCacheDir :: FilePath
|
||||||
, diArch :: Architecture
|
, diArch :: Architecture
|
||||||
, diPlatform :: PlatformResult
|
, diPlatform :: PlatformResult
|
||||||
}
|
}
|
||||||
@@ -342,7 +427,9 @@ data PlatformResult = PlatformResult
|
|||||||
{ _platform :: Platform
|
{ _platform :: Platform
|
||||||
, _distroVersion :: Maybe Versioning
|
, _distroVersion :: Maybe Versioning
|
||||||
}
|
}
|
||||||
deriving (Eq, Show)
|
deriving (Eq, Show, GHC.Generic)
|
||||||
|
|
||||||
|
instance NFData PlatformResult
|
||||||
|
|
||||||
platResToString :: PlatformResult -> String
|
platResToString :: PlatformResult -> String
|
||||||
platResToString PlatformResult { _platform = plat, _distroVersion = Just v' }
|
platResToString PlatformResult { _platform = plat, _distroVersion = Just v' }
|
||||||
@@ -358,7 +445,9 @@ data PlatformRequest = PlatformRequest
|
|||||||
, _rPlatform :: Platform
|
, _rPlatform :: Platform
|
||||||
, _rVersion :: Maybe Versioning
|
, _rVersion :: Maybe Versioning
|
||||||
}
|
}
|
||||||
deriving (Eq, Show)
|
deriving (Eq, Show, GHC.Generic)
|
||||||
|
|
||||||
|
instance NFData PlatformRequest
|
||||||
|
|
||||||
pfReqToString :: PlatformRequest -> String
|
pfReqToString :: PlatformRequest -> String
|
||||||
pfReqToString (PlatformRequest arch plat ver) =
|
pfReqToString (PlatformRequest arch plat ver) =
|
||||||
@@ -379,6 +468,11 @@ data GHCTargetVersion = GHCTargetVersion
|
|||||||
}
|
}
|
||||||
deriving (Ord, Eq, Show)
|
deriving (Ord, Eq, Show)
|
||||||
|
|
||||||
|
data GitBranch = GitBranch
|
||||||
|
{ ref :: String
|
||||||
|
, repo :: Maybe String
|
||||||
|
}
|
||||||
|
deriving (Ord, Eq, Show)
|
||||||
|
|
||||||
mkTVer :: Version -> GHCTargetVersion
|
mkTVer :: Version -> GHCTargetVersion
|
||||||
mkTVer = GHCTargetVersion Nothing
|
mkTVer = GHCTargetVersion Nothing
|
||||||
@@ -400,6 +494,8 @@ data VersionCmp = VR_gt Versioning
|
|||||||
| VR_eq Versioning
|
| VR_eq Versioning
|
||||||
deriving (Eq, GHC.Generic, Ord, Show)
|
deriving (Eq, GHC.Generic, Ord, Show)
|
||||||
|
|
||||||
|
instance NFData VersionCmp
|
||||||
|
|
||||||
|
|
||||||
-- | A version range. Supports && and ||, but not arbitrary
|
-- | A version range. Supports && and ||, but not arbitrary
|
||||||
-- combinations. This is a little simplified.
|
-- combinations. This is a little simplified.
|
||||||
@@ -407,9 +503,22 @@ data VersionRange = SimpleRange (NonEmpty VersionCmp) -- And
|
|||||||
| OrRange (NonEmpty VersionCmp) VersionRange
|
| OrRange (NonEmpty VersionCmp) VersionRange
|
||||||
deriving (Eq, GHC.Generic, Ord, Show)
|
deriving (Eq, GHC.Generic, Ord, Show)
|
||||||
|
|
||||||
|
instance NFData VersionRange
|
||||||
|
|
||||||
instance Pretty Versioning where
|
instance Pretty Versioning where
|
||||||
pPrint = text . T.unpack . prettyV
|
pPrint = text . T.unpack . prettyV
|
||||||
|
|
||||||
instance Pretty Version where
|
instance Pretty Version where
|
||||||
pPrint = text . T.unpack . prettyVer
|
pPrint = text . T.unpack . prettyVer
|
||||||
|
|
||||||
|
|
||||||
|
instance (Monad m, Alternative m) => Alternative (LoggingT m) where
|
||||||
|
empty = Trans.lift empty
|
||||||
|
{-# INLINE empty #-}
|
||||||
|
m <|> n = LoggingT $ \ r -> runLoggingT m r <|> runLoggingT n r
|
||||||
|
{-# INLINE (<|>) #-}
|
||||||
|
|
||||||
|
|
||||||
|
instance MonadLogger m => MonadLogger (Excepts e m) where
|
||||||
|
monadLoggerLog a b c d = Trans.lift $ monadLoggerLog a b c d
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ Copyright : (c) Julian Ospald, 2020
|
|||||||
License : LGPL-3.0
|
License : LGPL-3.0
|
||||||
Maintainer : hasufell@hasufell.de
|
Maintainer : hasufell@hasufell.de
|
||||||
Stability : experimental
|
Stability : experimental
|
||||||
Portability : POSIX
|
Portability : portable
|
||||||
-}
|
-}
|
||||||
module GHCup.Types.JSON where
|
module GHCup.Types.JSON where
|
||||||
|
|
||||||
@@ -33,38 +33,27 @@ import Data.List.NonEmpty ( NonEmpty(..) )
|
|||||||
import Data.Text.Encoding as E
|
import Data.Text.Encoding as E
|
||||||
import Data.Versions
|
import Data.Versions
|
||||||
import Data.Void
|
import Data.Void
|
||||||
import Data.Word8
|
|
||||||
import HPath
|
|
||||||
import URI.ByteString
|
import URI.ByteString
|
||||||
import Text.Casing
|
import Text.Casing
|
||||||
|
|
||||||
import qualified Data.ByteString as BS
|
|
||||||
import qualified Data.List.NonEmpty as NE
|
import qualified Data.List.NonEmpty as NE
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import qualified Graphics.Vty as Vty
|
|
||||||
import qualified Text.Megaparsec as MP
|
import qualified Text.Megaparsec as MP
|
||||||
import qualified Text.Megaparsec.Char as MPC
|
import qualified Text.Megaparsec.Char as MPC
|
||||||
|
|
||||||
|
|
||||||
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } { fieldLabelModifier = removeLensFieldLabel } ''Architecture
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } { fieldLabelModifier = removeLensFieldLabel } ''Architecture
|
||||||
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''LinuxDistro
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''LinuxDistro
|
||||||
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''Mess
|
|
||||||
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''MChunk
|
|
||||||
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''Platform
|
|
||||||
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''SemVer
|
|
||||||
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''Tool
|
|
||||||
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''VSep
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''VSep
|
||||||
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''VUnit
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''VUnit
|
||||||
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''VersionInfo
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''MChunk
|
||||||
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''DownloadInfo
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''Platform
|
||||||
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''GHCupInfo
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''Mess
|
||||||
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''Requirements
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''SemVer
|
||||||
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''Tool
|
||||||
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''GlobalTool
|
||||||
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''KeepDirs
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''KeepDirs
|
||||||
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''Downloader
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''Downloader
|
||||||
deriveJSON defaultOptions { sumEncoding = ObjectWithSingleField } ''URLSource
|
|
||||||
deriveJSON defaultOptions { fieldLabelModifier = \str' -> maybe str' T.unpack . T.stripPrefix (T.pack "u-") . T.pack . kebab $ str' } ''UserSettings
|
|
||||||
deriveJSON defaultOptions { fieldLabelModifier = \str' -> maybe str' T.unpack . T.stripPrefix (T.pack "k-") . T.pack . kebab $ str' } ''UserKeyBindings
|
|
||||||
deriveJSON defaultOptions { sumEncoding = ObjectWithSingleField } ''Vty.Key
|
|
||||||
|
|
||||||
instance ToJSON Tag where
|
instance ToJSON Tag where
|
||||||
toJSON Latest = String "Latest"
|
toJSON Latest = String "Latest"
|
||||||
@@ -128,11 +117,13 @@ instance ToJSONKey Platform where
|
|||||||
Darwin -> T.pack "Darwin"
|
Darwin -> T.pack "Darwin"
|
||||||
FreeBSD -> T.pack "FreeBSD"
|
FreeBSD -> T.pack "FreeBSD"
|
||||||
Linux d -> T.pack ("Linux_" <> show d)
|
Linux d -> T.pack ("Linux_" <> show d)
|
||||||
|
Windows -> T.pack "Windows"
|
||||||
|
|
||||||
instance FromJSONKey Platform where
|
instance FromJSONKey Platform where
|
||||||
fromJSONKey = FromJSONKeyTextParser $ \t -> if
|
fromJSONKey = FromJSONKeyTextParser $ \t -> if
|
||||||
| T.pack "Darwin" == t -> pure Darwin
|
| T.pack "Darwin" == t -> pure Darwin
|
||||||
| T.pack "FreeBSD" == t -> pure FreeBSD
|
| T.pack "FreeBSD" == t -> pure FreeBSD
|
||||||
|
| T.pack "Windows" == t -> pure Windows
|
||||||
| T.pack "Linux_" `T.isPrefixOf` t -> case
|
| T.pack "Linux_" `T.isPrefixOf` t -> case
|
||||||
T.stripPrefix (T.pack "Linux_") t
|
T.stripPrefix (T.pack "Linux_") t
|
||||||
of
|
of
|
||||||
@@ -199,19 +190,11 @@ instance ToJSONKey Tool where
|
|||||||
instance FromJSONKey Tool where
|
instance FromJSONKey Tool where
|
||||||
fromJSONKey = genericFromJSONKey defaultJSONKeyOptions
|
fromJSONKey = genericFromJSONKey defaultJSONKeyOptions
|
||||||
|
|
||||||
instance ToJSON (Path Rel) where
|
instance ToJSONKey GlobalTool where
|
||||||
toJSON p = case and . fmap isAscii . BS.unpack $ fp of
|
toJSONKey = genericToJSONKey defaultJSONKeyOptions
|
||||||
True -> toJSON . decUTF8Safe $ fp
|
|
||||||
False -> String "/not/a/valid/path"
|
|
||||||
where fp = toFilePath p
|
|
||||||
|
|
||||||
instance FromJSON (Path Rel) where
|
|
||||||
parseJSON = withText "HPath Rel" $ \t -> do
|
|
||||||
let d = encodeUtf8 t
|
|
||||||
case parseRel d of
|
|
||||||
Right x -> pure x
|
|
||||||
Left e -> fail $ "Failure in HPath Rel (FromJSON)" <> show e
|
|
||||||
|
|
||||||
|
instance FromJSONKey GlobalTool where
|
||||||
|
fromJSONKey = genericFromJSONKey defaultJSONKeyOptions
|
||||||
|
|
||||||
instance ToJSON TarDir where
|
instance ToJSON TarDir where
|
||||||
toJSON (RealDir p) = toJSON p
|
toJSON (RealDir p) = toJSON p
|
||||||
@@ -322,3 +305,14 @@ instance FromJSONKey (Maybe VersionRange) where
|
|||||||
just t = case MP.parse versionRangeP "" t of
|
just t = case MP.parse versionRangeP "" t of
|
||||||
Right x -> pure $ Just x
|
Right x -> pure $ Just x
|
||||||
Left e -> fail $ "Failure in (Maybe VersionRange) (FromJSONKey)" <> MP.errorBundlePretty e
|
Left e -> fail $ "Failure in (Maybe VersionRange) (FromJSONKey)" <> MP.errorBundlePretty e
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''Requirements
|
||||||
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''DownloadInfo
|
||||||
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''VersionInfo
|
||||||
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''GHCupInfo
|
||||||
|
deriveJSON defaultOptions { sumEncoding = ObjectWithSingleField } ''URLSource
|
||||||
|
deriveJSON defaultOptions { sumEncoding = ObjectWithSingleField } ''Key
|
||||||
|
deriveJSON defaultOptions { fieldLabelModifier = \str' -> maybe str' T.unpack . T.stripPrefix (T.pack "k-") . T.pack . kebab $ str' } ''UserKeyBindings
|
||||||
|
deriveJSON defaultOptions { fieldLabelModifier = \str' -> maybe str' T.unpack . T.stripPrefix (T.pack "u-") . T.pack . kebab $ str' } ''UserSettings
|
||||||
|
|||||||
@@ -1,4 +1,11 @@
|
|||||||
{-# LANGUAGE TemplateHaskell #-}
|
{-# OPTIONS_GHC -Wno-orphans #-}
|
||||||
|
{-# LANGUAGE TemplateHaskell #-}
|
||||||
|
{-# LANGUAGE ConstraintKinds #-}
|
||||||
|
{-# LANGUAGE DataKinds #-}
|
||||||
|
{-# LANGUAGE DuplicateRecordFields #-}
|
||||||
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
|
{-# LANGUAGE AllowAmbiguousTypes #-}
|
||||||
|
{-# LANGUAGE MultiParamTypeClasses #-}
|
||||||
|
|
||||||
{-|
|
{-|
|
||||||
Module : GHCup.Types.Optics
|
Module : GHCup.Types.Optics
|
||||||
@@ -7,12 +14,13 @@ Copyright : (c) Julian Ospald, 2020
|
|||||||
License : LGPL-3.0
|
License : LGPL-3.0
|
||||||
Maintainer : hasufell@hasufell.de
|
Maintainer : hasufell@hasufell.de
|
||||||
Stability : experimental
|
Stability : experimental
|
||||||
Portability : POSIX
|
Portability : portable
|
||||||
-}
|
-}
|
||||||
module GHCup.Types.Optics where
|
module GHCup.Types.Optics where
|
||||||
|
|
||||||
import GHCup.Types
|
import GHCup.Types
|
||||||
|
|
||||||
|
import Control.Monad.Reader
|
||||||
import Data.ByteString ( ByteString )
|
import Data.ByteString ( ByteString )
|
||||||
import Optics
|
import Optics
|
||||||
import URI.ByteString
|
import URI.ByteString
|
||||||
@@ -58,3 +66,85 @@ pathL' = lensVL pathL
|
|||||||
|
|
||||||
queryL' :: Lens' (URIRef a) Query
|
queryL' :: Lens' (URIRef a) Query
|
||||||
queryL' = lensVL queryL
|
queryL' = lensVL queryL
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
----------------------
|
||||||
|
--[ Lens utilities ]--
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
|
||||||
|
gets :: forall f a env m . (MonadReader env m, LabelOptic' f A_Lens env a)
|
||||||
|
=> m a
|
||||||
|
gets = asks (^. labelOptic @f)
|
||||||
|
|
||||||
|
|
||||||
|
getAppState :: MonadReader AppState m => m AppState
|
||||||
|
getAppState = ask
|
||||||
|
|
||||||
|
|
||||||
|
getLeanAppState :: ( MonadReader env m
|
||||||
|
, LabelOptic' "settings" A_Lens env Settings
|
||||||
|
, LabelOptic' "dirs" A_Lens env Dirs
|
||||||
|
, LabelOptic' "keyBindings" A_Lens env KeyBindings
|
||||||
|
)
|
||||||
|
=> m LeanAppState
|
||||||
|
getLeanAppState = do
|
||||||
|
s <- gets @"settings"
|
||||||
|
d <- gets @"dirs"
|
||||||
|
k <- gets @"keyBindings"
|
||||||
|
pure (LeanAppState s d k)
|
||||||
|
|
||||||
|
|
||||||
|
getSettings :: ( MonadReader env m
|
||||||
|
, LabelOptic' "settings" A_Lens env Settings
|
||||||
|
)
|
||||||
|
=> m Settings
|
||||||
|
getSettings = gets @"settings"
|
||||||
|
|
||||||
|
|
||||||
|
getDirs :: ( MonadReader env m
|
||||||
|
, LabelOptic' "dirs" A_Lens env Dirs
|
||||||
|
)
|
||||||
|
=> m Dirs
|
||||||
|
getDirs = gets @"dirs"
|
||||||
|
|
||||||
|
|
||||||
|
getKeyBindings :: ( MonadReader env m
|
||||||
|
, LabelOptic' "keyBindings" A_Lens env KeyBindings
|
||||||
|
)
|
||||||
|
=> m KeyBindings
|
||||||
|
getKeyBindings = gets @"keyBindings"
|
||||||
|
|
||||||
|
|
||||||
|
getGHCupInfo :: ( MonadReader env m
|
||||||
|
, LabelOptic' "ghcupInfo" A_Lens env GHCupInfo
|
||||||
|
)
|
||||||
|
=> m GHCupInfo
|
||||||
|
getGHCupInfo = gets @"ghcupInfo"
|
||||||
|
|
||||||
|
|
||||||
|
getPlatformReq :: ( MonadReader env m
|
||||||
|
, LabelOptic' "pfreq" A_Lens env PlatformRequest
|
||||||
|
)
|
||||||
|
=> m PlatformRequest
|
||||||
|
getPlatformReq = gets @"pfreq"
|
||||||
|
|
||||||
|
|
||||||
|
type HasSettings env = (LabelOptic' "settings" A_Lens env Settings)
|
||||||
|
type HasDirs env = (LabelOptic' "dirs" A_Lens env Dirs)
|
||||||
|
type HasKeyBindings env = (LabelOptic' "keyBindings" A_Lens env KeyBindings)
|
||||||
|
type HasGHCupInfo env = (LabelOptic' "ghcupInfo" A_Lens env GHCupInfo)
|
||||||
|
type HasPlatformReq env = (LabelOptic' "pfreq" A_Lens env PlatformRequest)
|
||||||
|
|
||||||
|
|
||||||
|
getCache :: (MonadReader env m, HasSettings env) => m Bool
|
||||||
|
getCache = getSettings <&> cache
|
||||||
|
|
||||||
|
|
||||||
|
getDownloader :: (MonadReader env m, HasSettings env) => m Downloader
|
||||||
|
getDownloader = getSettings <&> downloader
|
||||||
|
|
||||||
|
|
||||||
|
instance LabelOptic "dirs" A_Lens Dirs Dirs Dirs Dirs where
|
||||||
|
labelOptic = lens id (\_ d -> d)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
4
lib/GHCup/Utils.hs-boot
Normal file
4
lib/GHCup/Utils.hs-boot
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
module GHCup.Utils where
|
||||||
|
|
||||||
|
getLinkTarget :: FilePath -> IO FilePath
|
||||||
|
pathIsLink :: FilePath -> IO Bool
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
|
{-# LANGUAGE CPP #-}
|
||||||
{-# LANGUAGE DataKinds #-}
|
{-# LANGUAGE DataKinds #-}
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
{-# LANGUAGE FlexibleContexts #-}
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
{-# LANGUAGE QuasiQuotes #-}
|
{-# LANGUAGE QuasiQuotes #-}
|
||||||
{-# LANGUAGE ViewPatterns #-}
|
{-# LANGUAGE ViewPatterns #-}
|
||||||
|
{-# LANGUAGE TemplateHaskell #-}
|
||||||
|
|
||||||
{-|
|
{-|
|
||||||
Module : GHCup.Utils.Dirs
|
Module : GHCup.Utils.Dirs
|
||||||
@@ -11,17 +13,24 @@ Copyright : (c) Julian Ospald, 2020
|
|||||||
License : LGPL-3.0
|
License : LGPL-3.0
|
||||||
Maintainer : hasufell@hasufell.de
|
Maintainer : hasufell@hasufell.de
|
||||||
Stability : experimental
|
Stability : experimental
|
||||||
Portability : POSIX
|
Portability : portable
|
||||||
-}
|
-}
|
||||||
module GHCup.Utils.Dirs
|
module GHCup.Utils.Dirs
|
||||||
( getDirs
|
( getAllDirs
|
||||||
|
, ghcupBaseDir
|
||||||
, ghcupConfigFile
|
, ghcupConfigFile
|
||||||
|
, ghcupCacheDir
|
||||||
, ghcupGHCBaseDir
|
, ghcupGHCBaseDir
|
||||||
, ghcupGHCDir
|
, ghcupGHCDir
|
||||||
, mkGhcupTmpDir
|
, mkGhcupTmpDir
|
||||||
, parseGHCupGHCDir
|
, parseGHCupGHCDir
|
||||||
, relativeSymlink
|
, relativeSymlink
|
||||||
, withGHCupTmpDir
|
, withGHCupTmpDir
|
||||||
|
, getConfigFilePath
|
||||||
|
#if !defined(IS_WINDOWS)
|
||||||
|
, useXDG
|
||||||
|
#endif
|
||||||
|
, cleanupTrash
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
@@ -29,39 +38,33 @@ where
|
|||||||
import GHCup.Errors
|
import GHCup.Errors
|
||||||
import GHCup.Types
|
import GHCup.Types
|
||||||
import GHCup.Types.JSON ( )
|
import GHCup.Types.JSON ( )
|
||||||
|
import GHCup.Types.Optics
|
||||||
import GHCup.Utils.MegaParsec
|
import GHCup.Utils.MegaParsec
|
||||||
import GHCup.Utils.Prelude
|
import GHCup.Utils.Prelude
|
||||||
|
|
||||||
import Control.Applicative
|
|
||||||
import Control.Exception.Safe
|
import Control.Exception.Safe
|
||||||
import Control.Monad
|
import Control.Monad
|
||||||
|
import Control.Monad.IO.Unlift
|
||||||
|
import Control.Monad.Logger
|
||||||
import Control.Monad.Reader
|
import Control.Monad.Reader
|
||||||
import Control.Monad.Trans.Resource
|
import Control.Monad.Trans.Resource hiding (throwM)
|
||||||
import Data.Bifunctor
|
import Data.Bifunctor
|
||||||
import Data.ByteString ( ByteString )
|
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
|
import Data.String.Interpolate
|
||||||
import GHC.IO.Exception ( IOErrorType(NoSuchThing) )
|
import GHC.IO.Exception ( IOErrorType(NoSuchThing) )
|
||||||
import Haskus.Utils.Variant.Excepts
|
import Haskus.Utils.Variant.Excepts
|
||||||
import HPath
|
|
||||||
import HPath.IO
|
|
||||||
import Optics
|
import Optics
|
||||||
import Prelude hiding ( abs
|
import System.Directory
|
||||||
, readFile
|
import System.DiskSpace
|
||||||
, writeFile
|
import System.Environment
|
||||||
)
|
import System.FilePath
|
||||||
import System.Posix.Env.ByteString ( getEnv
|
import System.IO.Temp
|
||||||
, getEnvDefault
|
|
||||||
)
|
|
||||||
import System.Posix.FilePath hiding ( (</>) )
|
|
||||||
import System.Posix.Temp.ByteString ( mkdtemp )
|
|
||||||
|
|
||||||
import qualified Data.ByteString.Lazy as L
|
import qualified Data.ByteString as BS
|
||||||
import qualified Data.ByteString.UTF8 as UTF8
|
import qualified Data.Text as T
|
||||||
import qualified Data.Text.Encoding as E
|
|
||||||
import qualified Data.Yaml as Y
|
import qualified Data.Yaml as Y
|
||||||
import qualified System.Posix.FilePath as FP
|
|
||||||
import qualified System.Posix.User as PU
|
|
||||||
import qualified Text.Megaparsec as MP
|
import qualified Text.Megaparsec as MP
|
||||||
|
import Control.Concurrent (threadDelay)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -74,105 +77,134 @@ import qualified Text.Megaparsec as MP
|
|||||||
--
|
--
|
||||||
-- If 'GHCUP_USE_XDG_DIRS' is set (to anything),
|
-- If 'GHCUP_USE_XDG_DIRS' is set (to anything),
|
||||||
-- then uses 'XDG_DATA_HOME/ghcup' as per xdg spec.
|
-- then uses 'XDG_DATA_HOME/ghcup' as per xdg spec.
|
||||||
ghcupBaseDir :: IO (Path Abs)
|
ghcupBaseDir :: IO FilePath
|
||||||
ghcupBaseDir = do
|
ghcupBaseDir = do
|
||||||
|
#if defined(IS_WINDOWS)
|
||||||
|
bdir <- fromMaybe "C:\\" <$> lookupEnv "GHCUP_INSTALL_BASE_PREFIX"
|
||||||
|
pure (bdir </> "ghcup")
|
||||||
|
#else
|
||||||
xdg <- useXDG
|
xdg <- useXDG
|
||||||
if xdg
|
if xdg
|
||||||
then do
|
then do
|
||||||
bdir <- getEnv "XDG_DATA_HOME" >>= \case
|
bdir <- lookupEnv "XDG_DATA_HOME" >>= \case
|
||||||
Just r -> parseAbs r
|
Just r -> pure r
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
home <- liftIO getHomeDirectory
|
home <- liftIO getHomeDirectory
|
||||||
pure (home </> [rel|.local/share|])
|
pure (home </> ".local" </> "share")
|
||||||
pure (bdir </> [rel|ghcup|])
|
pure (bdir </> "ghcup")
|
||||||
else do
|
else do
|
||||||
bdir <- getEnv "GHCUP_INSTALL_BASE_PREFIX" >>= \case
|
bdir <- lookupEnv "GHCUP_INSTALL_BASE_PREFIX" >>= \case
|
||||||
Just r -> parseAbs r
|
Just r -> pure r
|
||||||
Nothing -> liftIO getHomeDirectory
|
Nothing -> liftIO getHomeDirectory
|
||||||
pure (bdir </> [rel|.ghcup|])
|
pure (bdir </> ".ghcup")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
-- | ~/.ghcup by default
|
-- | ~/.ghcup by default
|
||||||
--
|
--
|
||||||
-- If 'GHCUP_USE_XDG_DIRS' is set (to anything),
|
-- If 'GHCUP_USE_XDG_DIRS' is set (to anything),
|
||||||
-- then uses 'XDG_CONFIG_HOME/ghcup' as per xdg spec.
|
-- then uses 'XDG_CONFIG_HOME/ghcup' as per xdg spec.
|
||||||
ghcupConfigDir :: IO (Path Abs)
|
ghcupConfigDir :: IO FilePath
|
||||||
ghcupConfigDir = do
|
ghcupConfigDir = do
|
||||||
|
#if defined(IS_WINDOWS)
|
||||||
|
ghcupBaseDir
|
||||||
|
#else
|
||||||
xdg <- useXDG
|
xdg <- useXDG
|
||||||
if xdg
|
if xdg
|
||||||
then do
|
then do
|
||||||
bdir <- getEnv "XDG_CONFIG_HOME" >>= \case
|
bdir <- lookupEnv "XDG_CONFIG_HOME" >>= \case
|
||||||
Just r -> parseAbs r
|
Just r -> pure r
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
home <- liftIO getHomeDirectory
|
home <- liftIO getHomeDirectory
|
||||||
pure (home </> [rel|.config|])
|
pure (home </> ".config")
|
||||||
pure (bdir </> [rel|ghcup|])
|
pure (bdir </> "ghcup")
|
||||||
else do
|
else do
|
||||||
bdir <- getEnv "GHCUP_INSTALL_BASE_PREFIX" >>= \case
|
bdir <- lookupEnv "GHCUP_INSTALL_BASE_PREFIX" >>= \case
|
||||||
Just r -> parseAbs r
|
Just r -> pure r
|
||||||
Nothing -> liftIO getHomeDirectory
|
Nothing -> liftIO getHomeDirectory
|
||||||
pure (bdir </> [rel|.ghcup|])
|
pure (bdir </> ".ghcup")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
-- | If 'GHCUP_USE_XDG_DIRS' is set (to anything),
|
-- | If 'GHCUP_USE_XDG_DIRS' is set (to anything),
|
||||||
-- then uses 'XDG_BIN_HOME' env var or defaults to '~/.local/bin'
|
-- then uses 'XDG_BIN_HOME' env var or defaults to '~/.local/bin'
|
||||||
-- (which, sadly is not strictly xdg spec).
|
-- (which, sadly is not strictly xdg spec).
|
||||||
ghcupBinDir :: IO (Path Abs)
|
ghcupBinDir :: IO FilePath
|
||||||
ghcupBinDir = do
|
ghcupBinDir = do
|
||||||
|
#if defined(IS_WINDOWS)
|
||||||
|
ghcupBaseDir <&> (</> "bin")
|
||||||
|
#else
|
||||||
xdg <- useXDG
|
xdg <- useXDG
|
||||||
if xdg
|
if xdg
|
||||||
then do
|
then do
|
||||||
getEnv "XDG_BIN_HOME" >>= \case
|
lookupEnv "XDG_BIN_HOME" >>= \case
|
||||||
Just r -> parseAbs r
|
Just r -> pure r
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
home <- liftIO getHomeDirectory
|
home <- liftIO getHomeDirectory
|
||||||
pure (home </> [rel|.local/bin|])
|
pure (home </> ".local" </> "bin")
|
||||||
else ghcupBaseDir <&> (</> [rel|bin|])
|
else ghcupBaseDir <&> (</> "bin")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
-- | Defaults to '~/.ghcup/cache'.
|
-- | Defaults to '~/.ghcup/cache'.
|
||||||
--
|
--
|
||||||
-- If 'GHCUP_USE_XDG_DIRS' is set (to anything),
|
-- If 'GHCUP_USE_XDG_DIRS' is set (to anything),
|
||||||
-- then uses 'XDG_CACHE_HOME/ghcup' as per xdg spec.
|
-- then uses 'XDG_CACHE_HOME/ghcup' as per xdg spec.
|
||||||
ghcupCacheDir :: IO (Path Abs)
|
ghcupCacheDir :: IO FilePath
|
||||||
ghcupCacheDir = do
|
ghcupCacheDir = do
|
||||||
|
#if defined(IS_WINDOWS)
|
||||||
|
ghcupBaseDir <&> (</> "cache")
|
||||||
|
#else
|
||||||
xdg <- useXDG
|
xdg <- useXDG
|
||||||
if xdg
|
if xdg
|
||||||
then do
|
then do
|
||||||
bdir <- getEnv "XDG_CACHE_HOME" >>= \case
|
bdir <- lookupEnv "XDG_CACHE_HOME" >>= \case
|
||||||
Just r -> parseAbs r
|
Just r -> pure r
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
home <- liftIO getHomeDirectory
|
home <- liftIO getHomeDirectory
|
||||||
pure (home </> [rel|.cache|])
|
pure (home </> ".cache")
|
||||||
pure (bdir </> [rel|ghcup|])
|
pure (bdir </> "ghcup")
|
||||||
else ghcupBaseDir <&> (</> [rel|cache|])
|
else ghcupBaseDir <&> (</> "cache")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
-- | Defaults to '~/.ghcup/logs'.
|
-- | Defaults to '~/.ghcup/logs'.
|
||||||
--
|
--
|
||||||
-- If 'GHCUP_USE_XDG_DIRS' is set (to anything),
|
-- If 'GHCUP_USE_XDG_DIRS' is set (to anything),
|
||||||
-- then uses 'XDG_CACHE_HOME/ghcup/logs' as per xdg spec.
|
-- then uses 'XDG_CACHE_HOME/ghcup/logs' as per xdg spec.
|
||||||
ghcupLogsDir :: IO (Path Abs)
|
ghcupLogsDir :: IO FilePath
|
||||||
ghcupLogsDir = do
|
ghcupLogsDir = do
|
||||||
|
#if defined(IS_WINDOWS)
|
||||||
|
ghcupBaseDir <&> (</> "logs")
|
||||||
|
#else
|
||||||
xdg <- useXDG
|
xdg <- useXDG
|
||||||
if xdg
|
if xdg
|
||||||
then do
|
then do
|
||||||
bdir <- getEnv "XDG_CACHE_HOME" >>= \case
|
bdir <- lookupEnv "XDG_CACHE_HOME" >>= \case
|
||||||
Just r -> parseAbs r
|
Just r -> pure r
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
home <- liftIO getHomeDirectory
|
home <- liftIO getHomeDirectory
|
||||||
pure (home </> [rel|.cache|])
|
pure (home </> ".cache")
|
||||||
pure (bdir </> [rel|ghcup/logs|])
|
pure (bdir </> "ghcup" </> "logs")
|
||||||
else ghcupBaseDir <&> (</> [rel|logs|])
|
else ghcupBaseDir <&> (</> "logs")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
getDirs :: IO Dirs
|
-- | '~/.ghcup/trash'.
|
||||||
getDirs = do
|
-- Mainly used on windows to improve file removal operations
|
||||||
baseDir <- ghcupBaseDir
|
ghcupRecycleDir :: IO FilePath
|
||||||
binDir <- ghcupBinDir
|
ghcupRecycleDir = ghcupBaseDir <&> (</> "trash")
|
||||||
cacheDir <- ghcupCacheDir
|
|
||||||
logsDir <- ghcupLogsDir
|
|
||||||
confDir <- ghcupConfigDir
|
|
||||||
|
getAllDirs :: IO Dirs
|
||||||
|
getAllDirs = do
|
||||||
|
baseDir <- ghcupBaseDir
|
||||||
|
binDir <- ghcupBinDir
|
||||||
|
cacheDir <- ghcupCacheDir
|
||||||
|
logsDir <- ghcupLogsDir
|
||||||
|
confDir <- ghcupConfigDir
|
||||||
|
recycleDir <- ghcupRecycleDir
|
||||||
pure Dirs { .. }
|
pure Dirs { .. }
|
||||||
|
|
||||||
|
|
||||||
@@ -181,16 +213,19 @@ getDirs = do
|
|||||||
--[ GHCup files ]--
|
--[ GHCup files ]--
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
|
getConfigFilePath :: (MonadIO m) => m FilePath
|
||||||
|
getConfigFilePath = do
|
||||||
|
confDir <- liftIO ghcupConfigDir
|
||||||
|
pure $ confDir </> "config.yaml"
|
||||||
|
|
||||||
ghcupConfigFile :: (MonadIO m)
|
ghcupConfigFile :: (MonadIO m)
|
||||||
=> Excepts '[JSONError] m UserSettings
|
=> Excepts '[JSONError] m UserSettings
|
||||||
ghcupConfigFile = do
|
ghcupConfigFile = do
|
||||||
confDir <- liftIO ghcupConfigDir
|
filepath <- getConfigFilePath
|
||||||
let file = confDir </> [rel|config.yaml|]
|
contents <- liftIO $ handleIO' NoSuchThing (\_ -> pure Nothing) $ Just <$> BS.readFile filepath
|
||||||
bs <- liftIO $ handleIO' NoSuchThing (\_ -> pure Nothing) $ Just <$> readFile file
|
case contents of
|
||||||
case bs of
|
|
||||||
Nothing -> pure defaultUserSettings
|
Nothing -> pure defaultUserSettings
|
||||||
Just bs' -> lE' JSONDecodeError . first show . Y.decodeEither' . L.toStrict $ bs'
|
Just contents' -> lE' JSONDecodeError . first show . Y.decodeEither' $ contents'
|
||||||
|
|
||||||
|
|
||||||
-------------------------
|
-------------------------
|
||||||
@@ -199,41 +234,79 @@ ghcupConfigFile = do
|
|||||||
|
|
||||||
|
|
||||||
-- | ~/.ghcup/ghc by default.
|
-- | ~/.ghcup/ghc by default.
|
||||||
ghcupGHCBaseDir :: (MonadReader AppState m) => m (Path Abs)
|
ghcupGHCBaseDir :: (MonadReader env m, HasDirs env) => m FilePath
|
||||||
ghcupGHCBaseDir = do
|
ghcupGHCBaseDir = do
|
||||||
AppState { dirs = Dirs {..} } <- ask
|
Dirs {..} <- getDirs
|
||||||
pure (baseDir </> [rel|ghc|])
|
pure (baseDir </> "ghc")
|
||||||
|
|
||||||
|
|
||||||
-- | Gets '~/.ghcup/ghc/<ghcupGHCDir>'.
|
-- | Gets '~/.ghcup/ghc/<ghcupGHCDir>'.
|
||||||
-- The dir may be of the form
|
-- The dir may be of the form
|
||||||
-- * armv7-unknown-linux-gnueabihf-8.8.3
|
-- * armv7-unknown-linux-gnueabihf-8.8.3
|
||||||
-- * 8.8.4
|
-- * 8.8.4
|
||||||
ghcupGHCDir :: (MonadReader AppState m, MonadThrow m)
|
ghcupGHCDir :: (MonadReader env m, HasDirs env, MonadThrow m)
|
||||||
=> GHCTargetVersion
|
=> GHCTargetVersion
|
||||||
-> m (Path Abs)
|
-> m FilePath
|
||||||
ghcupGHCDir ver = do
|
ghcupGHCDir ver = do
|
||||||
ghcbasedir <- ghcupGHCBaseDir
|
ghcbasedir <- ghcupGHCBaseDir
|
||||||
verdir <- parseRel $ E.encodeUtf8 (tVerToText ver)
|
let verdir = T.unpack $ tVerToText ver
|
||||||
pure (ghcbasedir </> verdir)
|
pure (ghcbasedir </> verdir)
|
||||||
|
|
||||||
|
|
||||||
-- | See 'ghcupToolParser'.
|
-- | See 'ghcupToolParser'.
|
||||||
parseGHCupGHCDir :: MonadThrow m => Path Rel -> m GHCTargetVersion
|
parseGHCupGHCDir :: MonadThrow m => FilePath -> m GHCTargetVersion
|
||||||
parseGHCupGHCDir (toFilePath -> f) = do
|
parseGHCupGHCDir (T.pack -> fp) =
|
||||||
fp <- throwEither $ E.decodeUtf8' f
|
|
||||||
throwEither $ MP.parse ghcTargetVerP "" fp
|
throwEither $ MP.parse ghcTargetVerP "" fp
|
||||||
|
|
||||||
|
|
||||||
mkGhcupTmpDir :: (MonadThrow m, MonadIO m) => m (Path Abs)
|
mkGhcupTmpDir :: ( MonadReader env m
|
||||||
|
, HasDirs env
|
||||||
|
, MonadUnliftIO m
|
||||||
|
, MonadLogger m
|
||||||
|
, MonadCatch m
|
||||||
|
, MonadThrow m
|
||||||
|
, MonadMask m
|
||||||
|
, MonadIO m)
|
||||||
|
=> m FilePath
|
||||||
mkGhcupTmpDir = do
|
mkGhcupTmpDir = do
|
||||||
tmpdir <- liftIO $ getEnvDefault "TMPDIR" "/tmp"
|
tmpdir <- liftIO getCanonicalTemporaryDirectory
|
||||||
tmp <- liftIO $ mkdtemp (tmpdir FP.</> "ghcup-")
|
|
||||||
parseAbs tmp
|
let minSpace = 5000 -- a rough guess, aight?
|
||||||
|
space <- handleIO (\_ -> pure Nothing) $ fmap Just $ liftIO $ getAvailSpace tmpdir
|
||||||
|
when (maybe False (toBytes minSpace >) space) $ do
|
||||||
|
$(logWarn) [i|Possibly insufficient disk space on #{tmpdir}. At least #{minSpace} MB are recommended, but only #{toMB (fromJust space)} are free. Consider freeing up disk space or setting TMPDIR env variable.|]
|
||||||
|
$(logWarn)
|
||||||
|
"...waiting for 10 seconds before continuing anyway, you can still abort..."
|
||||||
|
liftIO $ threadDelay 10000000 -- give the user a sec to intervene
|
||||||
|
|
||||||
|
liftIO $ createTempDirectory tmpdir "ghcup"
|
||||||
|
where
|
||||||
|
toBytes mb = mb * 1024 * 1024
|
||||||
|
toMB b = show (truncate' (fromIntegral b / (1024 * 1024) :: Double) 2)
|
||||||
|
truncate' :: Double -> Int -> Double
|
||||||
|
truncate' x n = fromIntegral (floor (x * t) :: Integer) / t
|
||||||
|
where t = 10^n
|
||||||
|
|
||||||
|
|
||||||
withGHCupTmpDir :: (MonadResource m, MonadThrow m, MonadIO m) => m (Path Abs)
|
withGHCupTmpDir :: ( MonadReader env m
|
||||||
withGHCupTmpDir = snd <$> allocate mkGhcupTmpDir deleteDirRecursive
|
, HasDirs env
|
||||||
|
, MonadUnliftIO m
|
||||||
|
, MonadLogger 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) [i|Resource cleanup failed for "#{fp}", error was: #{displayException e}|])
|
||||||
|
. rmPathForcibly
|
||||||
|
$ fp))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -243,31 +316,39 @@ withGHCupTmpDir = snd <$> allocate mkGhcupTmpDir deleteDirRecursive
|
|||||||
--------------
|
--------------
|
||||||
|
|
||||||
|
|
||||||
getHomeDirectory :: IO (Path Abs)
|
#if !defined(IS_WINDOWS)
|
||||||
getHomeDirectory = do
|
|
||||||
e <- getEnv "HOME"
|
|
||||||
case e of
|
|
||||||
Just fp -> parseAbs fp
|
|
||||||
Nothing -> do
|
|
||||||
h <- PU.homeDirectory <$> (PU.getEffectiveUserID >>= PU.getUserEntryForID)
|
|
||||||
parseAbs $ UTF8.fromString h -- this is a guess
|
|
||||||
|
|
||||||
|
|
||||||
useXDG :: IO Bool
|
useXDG :: IO Bool
|
||||||
useXDG = isJust <$> getEnv "GHCUP_USE_XDG_DIRS"
|
useXDG = isJust <$> lookupEnv "GHCUP_USE_XDG_DIRS"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
relativeSymlink :: Path Abs -- ^ the path in which to create the symlink
|
relativeSymlink :: FilePath -- ^ the path in which to create the symlink
|
||||||
-> Path Abs -- ^ the symlink destination
|
-> FilePath -- ^ the symlink destination
|
||||||
-> ByteString
|
-> FilePath
|
||||||
relativeSymlink (toFilePath -> p1) (toFilePath -> p2) =
|
relativeSymlink p1 p2 =
|
||||||
let d1 = splitDirectories p1
|
let d1 = splitDirectories p1
|
||||||
d2 = splitDirectories p2
|
d2 = splitDirectories p2
|
||||||
common = takeWhile (\(x, y) -> x == y) $ zip d1 d2
|
common = takeWhile (\(x, y) -> x == y) $ zip d1 d2
|
||||||
cPrefix = drop (length common) d1
|
cPrefix = drop (length common) d1
|
||||||
in joinPath (replicate (length cPrefix) "..")
|
in joinPath (replicate (length cPrefix) "..")
|
||||||
<> joinPath ("/" : drop (length common) d2)
|
<> joinPath ([pathSeparator] : drop (length common) d2)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cleanupTrash :: ( MonadIO m
|
||||||
|
, MonadMask m
|
||||||
|
, MonadLogger m
|
||||||
|
, MonadReader env m
|
||||||
|
, HasDirs env
|
||||||
|
)
|
||||||
|
=> m ()
|
||||||
|
cleanupTrash = do
|
||||||
|
Dirs { recycleDir } <- getDirs
|
||||||
|
contents <- liftIO $ listDirectory recycleDir
|
||||||
|
if null contents
|
||||||
|
then pure ()
|
||||||
|
else do
|
||||||
|
$(logWarn) [i|Removing leftover files in #{recycleDir}|]
|
||||||
|
forM_ contents (\fp -> handleIO (\e ->
|
||||||
|
$(logDebug) [i|Resource cleanup failed for "#{fp}", error was: #{displayException e}|]
|
||||||
|
) $ liftIO $ removePathForcibly (recycleDir </> fp))
|
||||||
|
|
||||||
|
|||||||
@@ -1,494 +1,17 @@
|
|||||||
{-# LANGUAGE QuasiQuotes #-}
|
{-# LANGUAGE CPP #-}
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
|
||||||
{-# LANGUAGE FlexibleContexts #-}
|
module GHCup.Utils.File (
|
||||||
{-# LANGUAGE TemplateHaskell #-}
|
module GHCup.Utils.File.Common,
|
||||||
{-# LANGUAGE ViewPatterns #-}
|
#if IS_WINDOWS
|
||||||
|
module GHCup.Utils.File.Windows
|
||||||
{-|
|
#else
|
||||||
Module : GHCup.Utils.File
|
module GHCup.Utils.File.Posix
|
||||||
Description : File and unix APIs
|
#endif
|
||||||
Copyright : (c) Julian Ospald, 2020
|
) where
|
||||||
License : LGPL-3.0
|
|
||||||
Maintainer : hasufell@hasufell.de
|
import GHCup.Utils.File.Common
|
||||||
Stability : experimental
|
#if IS_WINDOWS
|
||||||
Portability : POSIX
|
import GHCup.Utils.File.Windows
|
||||||
|
#else
|
||||||
This module handles file and executable handling.
|
import GHCup.Utils.File.Posix
|
||||||
Some of these functions use sophisticated logging.
|
#endif
|
||||||
-}
|
|
||||||
module GHCup.Utils.File where
|
|
||||||
|
|
||||||
import GHCup.Utils.Prelude
|
|
||||||
import GHCup.Types
|
|
||||||
|
|
||||||
import Control.Concurrent
|
|
||||||
import Control.Concurrent.Async
|
|
||||||
import Control.Exception ( evaluate )
|
|
||||||
import Control.Exception.Safe
|
|
||||||
import Control.Monad
|
|
||||||
import Control.Monad.Logger
|
|
||||||
import Control.Monad.Reader
|
|
||||||
import Control.Monad.Trans.State.Strict
|
|
||||||
import Data.ByteString ( ByteString )
|
|
||||||
import Data.Foldable
|
|
||||||
import Data.Functor
|
|
||||||
import Data.IORef
|
|
||||||
import Data.Maybe
|
|
||||||
import Data.Sequence ( Seq, (|>) )
|
|
||||||
import Data.String.Interpolate
|
|
||||||
import Data.Text ( Text )
|
|
||||||
import Data.Void
|
|
||||||
import Data.Word8
|
|
||||||
import GHC.IO.Exception
|
|
||||||
import HPath
|
|
||||||
import HPath.IO hiding ( hideError )
|
|
||||||
import Optics hiding ((<|), (|>))
|
|
||||||
import System.Console.Pretty hiding ( Pretty )
|
|
||||||
import System.Console.Regions
|
|
||||||
import System.IO.Error
|
|
||||||
import System.Posix.Directory.ByteString
|
|
||||||
import System.Posix.FD as FD
|
|
||||||
import System.Posix.FilePath hiding ( (</>) )
|
|
||||||
import System.Posix.Files.ByteString
|
|
||||||
import System.Posix.Foreign ( oExcl )
|
|
||||||
import "unix" System.Posix.IO.ByteString
|
|
||||||
hiding ( openFd )
|
|
||||||
import System.Posix.Process ( ProcessStatus(..) )
|
|
||||||
import System.Posix.Types
|
|
||||||
import Text.PrettyPrint.HughesPJClass hiding ( (<>) )
|
|
||||||
import Text.Regex.Posix
|
|
||||||
|
|
||||||
|
|
||||||
import qualified Control.Exception as EX
|
|
||||||
import qualified Data.Sequence as Sq
|
|
||||||
import qualified Data.Text as T
|
|
||||||
import qualified Data.Text.Encoding as E
|
|
||||||
import qualified System.Posix.Process.ByteString
|
|
||||||
as SPPB
|
|
||||||
import Streamly.External.Posix.DirStream
|
|
||||||
import qualified Streamly.Prelude as S
|
|
||||||
import qualified Text.Megaparsec as MP
|
|
||||||
import qualified Data.ByteString as BS
|
|
||||||
import qualified "unix-bytestring" System.Posix.IO.ByteString
|
|
||||||
as SPIB
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
data ProcessError = NonZeroExit Int ByteString [ByteString]
|
|
||||||
| PTerminated ByteString [ByteString]
|
|
||||||
| PStopped ByteString [ByteString]
|
|
||||||
| NoSuchPid ByteString [ByteString]
|
|
||||||
deriving Show
|
|
||||||
|
|
||||||
instance Pretty ProcessError where
|
|
||||||
pPrint (NonZeroExit e exe args) =
|
|
||||||
text [i|Process "#{decUTF8Safe exe}" with arguments #{fmap decUTF8Safe args} failed with exit code #{e}.|]
|
|
||||||
pPrint (PTerminated exe args) =
|
|
||||||
text [i|Process "#{decUTF8Safe exe}" with arguments #{fmap decUTF8Safe args} terminated.|]
|
|
||||||
pPrint (PStopped exe args) =
|
|
||||||
text [i|Process "#{decUTF8Safe exe}" with arguments #{fmap decUTF8Safe args} stopped.|]
|
|
||||||
pPrint (NoSuchPid exe args) =
|
|
||||||
text [i|Could not find PID for process running "#{decUTF8Safe exe}" with arguments #{fmap decUTF8Safe args}.|]
|
|
||||||
|
|
||||||
data CapturedProcess = CapturedProcess
|
|
||||||
{ _exitCode :: ExitCode
|
|
||||||
, _stdOut :: ByteString
|
|
||||||
, _stdErr :: ByteString
|
|
||||||
}
|
|
||||||
deriving (Eq, Show)
|
|
||||||
|
|
||||||
makeLenses ''CapturedProcess
|
|
||||||
|
|
||||||
|
|
||||||
-- | Find the given executable by searching all *absolute* PATH components.
|
|
||||||
-- Relative paths in PATH are ignored.
|
|
||||||
--
|
|
||||||
-- This shouldn't throw IO exceptions, unless getting the environment variable
|
|
||||||
-- PATH does.
|
|
||||||
findExecutable :: Path Rel -> IO (Maybe (Path Abs))
|
|
||||||
findExecutable ex = do
|
|
||||||
sPaths <- fmap (catMaybes . fmap parseAbs) getSearchPath
|
|
||||||
-- We don't want exceptions to mess up our result. If we can't
|
|
||||||
-- figure out if a file exists, then treat it as a negative result.
|
|
||||||
asum $ fmap
|
|
||||||
(handleIO (\_ -> pure Nothing)
|
|
||||||
-- asum for short-circuiting behavior
|
|
||||||
. (\s' -> (isExecutable (s' </> ex) >>= guard) $> Just (s' </> ex))
|
|
||||||
)
|
|
||||||
sPaths
|
|
||||||
|
|
||||||
|
|
||||||
-- | Execute the given command and collect the stdout, stderr and the exit code.
|
|
||||||
-- The command is run in a subprocess.
|
|
||||||
executeOut :: Path b -- ^ command as filename, e.g. 'ls'
|
|
||||||
-> [ByteString] -- ^ arguments to the command
|
|
||||||
-> Maybe (Path Abs) -- ^ chdir to this path
|
|
||||||
-> IO CapturedProcess
|
|
||||||
executeOut path args chdir = captureOutStreams $ do
|
|
||||||
maybe (pure ()) (changeWorkingDirectory . toFilePath) chdir
|
|
||||||
SPPB.executeFile (toFilePath path) True args Nothing
|
|
||||||
|
|
||||||
|
|
||||||
execLogged :: (MonadReader AppState m, MonadIO m, MonadThrow m)
|
|
||||||
=> ByteString -- ^ thing to execute
|
|
||||||
-> Bool -- ^ whether to search PATH for the thing
|
|
||||||
-> [ByteString] -- ^ args for the thing
|
|
||||||
-> Path Rel -- ^ log filename
|
|
||||||
-> Maybe (Path Abs) -- ^ optionally chdir into this
|
|
||||||
-> Maybe [(ByteString, ByteString)] -- ^ optional environment
|
|
||||||
-> m (Either ProcessError ())
|
|
||||||
execLogged exe spath args lfile chdir env = do
|
|
||||||
AppState { settings = Settings {..}, dirs = Dirs {..} } <- ask
|
|
||||||
logfile <- (logsDir </>) <$> parseRel (toFilePath lfile <> ".log")
|
|
||||||
liftIO $ bracket (createFile (toFilePath logfile) newFilePerms)
|
|
||||||
closeFd
|
|
||||||
(action verbose)
|
|
||||||
where
|
|
||||||
action verbose fd = do
|
|
||||||
actionWithPipes $ \(stdoutRead, stdoutWrite) -> do
|
|
||||||
-- start the thread that logs to stdout
|
|
||||||
pState <- newEmptyMVar
|
|
||||||
done <- newEmptyMVar
|
|
||||||
void
|
|
||||||
$ forkIO
|
|
||||||
$ EX.handle (\(_ :: IOException) -> pure ())
|
|
||||||
$ EX.finally
|
|
||||||
(if verbose
|
|
||||||
then tee fd stdoutRead
|
|
||||||
else printToRegion fd stdoutRead 6 pState
|
|
||||||
)
|
|
||||||
(putMVar done ())
|
|
||||||
|
|
||||||
-- fork the subprocess
|
|
||||||
pid <- SPPB.forkProcess $ do
|
|
||||||
void $ dupTo stdoutWrite stdOutput
|
|
||||||
void $ dupTo stdoutWrite stdError
|
|
||||||
closeFd stdoutRead
|
|
||||||
closeFd stdoutWrite
|
|
||||||
|
|
||||||
-- execute the action
|
|
||||||
maybe (pure ()) (changeWorkingDirectory . toFilePath) chdir
|
|
||||||
void $ SPPB.executeFile exe spath args env
|
|
||||||
|
|
||||||
closeFd stdoutWrite
|
|
||||||
|
|
||||||
-- wait for the subprocess to finish
|
|
||||||
e <- toProcessError exe args <$!> SPPB.getProcessStatus True True pid
|
|
||||||
putMVar pState (either (const False) (const True) e)
|
|
||||||
|
|
||||||
void $ race (takeMVar done) (threadDelay (1000000 * 3))
|
|
||||||
closeFd stdoutRead
|
|
||||||
|
|
||||||
pure e
|
|
||||||
|
|
||||||
tee :: Fd -> Fd -> IO ()
|
|
||||||
tee fileFd fdIn = readTilEOF lineAction fdIn
|
|
||||||
|
|
||||||
where
|
|
||||||
lineAction :: ByteString -> IO ()
|
|
||||||
lineAction bs' = do
|
|
||||||
void $ SPIB.fdWrite fileFd (bs' <> "\n")
|
|
||||||
void $ SPIB.fdWrite stdOutput (bs' <> "\n")
|
|
||||||
|
|
||||||
-- Reads fdIn and logs the output in a continous scrolling area
|
|
||||||
-- of 'size' terminal lines. Also writes to a log file.
|
|
||||||
printToRegion :: Fd -> Fd -> Int -> MVar Bool -> IO ()
|
|
||||||
printToRegion fileFd fdIn size pState = do
|
|
||||||
void $ displayConsoleRegions $ do
|
|
||||||
rs <-
|
|
||||||
liftIO
|
|
||||||
. fmap Sq.fromList
|
|
||||||
. sequence
|
|
||||||
. replicate size
|
|
||||||
. openConsoleRegion
|
|
||||||
$ Linear
|
|
||||||
flip runStateT mempty
|
|
||||||
$ handle
|
|
||||||
(\(ex :: SomeException) -> do
|
|
||||||
ps <- liftIO $ takeMVar pState
|
|
||||||
when ps (forM_ rs (liftIO . closeConsoleRegion))
|
|
||||||
throw ex
|
|
||||||
)
|
|
||||||
$ readTilEOF (lineAction rs) fdIn
|
|
||||||
|
|
||||||
where
|
|
||||||
-- action to perform line by line
|
|
||||||
-- TODO: do this with vty for efficiency
|
|
||||||
lineAction :: (MonadMask m, MonadIO m)
|
|
||||||
=> Seq ConsoleRegion
|
|
||||||
-> ByteString
|
|
||||||
-> StateT (Seq ByteString) m ()
|
|
||||||
lineAction rs = \bs' -> do
|
|
||||||
void $ liftIO $ SPIB.fdWrite fileFd (bs' <> "\n")
|
|
||||||
modify (swapRegs bs')
|
|
||||||
regs <- get
|
|
||||||
liftIO $ forM_ (Sq.zip regs rs) $ \(bs, r) -> setConsoleRegion r $ do
|
|
||||||
w <- consoleWidth
|
|
||||||
return
|
|
||||||
. T.pack
|
|
||||||
. color Blue
|
|
||||||
. T.unpack
|
|
||||||
. decUTF8Safe
|
|
||||||
. trim w
|
|
||||||
. (\b -> "[ " <> toFilePath lfile <> " ] " <> b)
|
|
||||||
$ bs
|
|
||||||
|
|
||||||
swapRegs :: a -> Seq a -> Seq a
|
|
||||||
swapRegs bs = \regs -> if
|
|
||||||
| Sq.length regs < size -> regs |> bs
|
|
||||||
| otherwise -> Sq.drop 1 regs |> bs
|
|
||||||
|
|
||||||
-- trim output line to terminal width
|
|
||||||
trim :: Int -> ByteString -> ByteString
|
|
||||||
trim w = \bs -> if
|
|
||||||
| BS.length bs > w && w > 5 -> BS.take (w - 4) bs <> "..."
|
|
||||||
| otherwise -> bs
|
|
||||||
|
|
||||||
-- Consecutively read from Fd in 512 chunks until we hit
|
|
||||||
-- newline or EOF.
|
|
||||||
readLine :: MonadIO m
|
|
||||||
=> Fd -- ^ input file descriptor
|
|
||||||
-> ByteString -- ^ rest buffer (read across newline)
|
|
||||||
-> m (ByteString, ByteString, Bool) -- ^ (full line, rest, eof)
|
|
||||||
readLine fd = go
|
|
||||||
where
|
|
||||||
go inBs = do
|
|
||||||
-- if buffer is not empty, process it first
|
|
||||||
mbs <- if BS.length inBs == 0
|
|
||||||
-- otherwise attempt read
|
|
||||||
then liftIO
|
|
||||||
$ handleIO (\e -> if isEOFError e then pure Nothing else ioError e)
|
|
||||||
$ fmap Just
|
|
||||||
$ SPIB.fdRead fd 512
|
|
||||||
else pure $ Just inBs
|
|
||||||
case mbs of
|
|
||||||
Nothing -> pure ("", "", True)
|
|
||||||
Just bs -> do
|
|
||||||
-- split on newline
|
|
||||||
let (line, rest) = BS.span (/= _lf) bs
|
|
||||||
if
|
|
||||||
| BS.length rest /= 0 -> pure (line, BS.tail rest, False)
|
|
||||||
-- if rest is empty, then there was no newline, process further
|
|
||||||
| otherwise -> (\(l, r, b) -> (line <> l, r, b)) <$!> go mempty
|
|
||||||
|
|
||||||
readTilEOF :: MonadIO m => (ByteString -> m a) -> Fd -> m ()
|
|
||||||
readTilEOF ~action' fd' = go mempty
|
|
||||||
where
|
|
||||||
go bs' = do
|
|
||||||
(bs, rest, eof) <- readLine fd' bs'
|
|
||||||
if eof
|
|
||||||
then liftIO $ ioError (mkIOError eofErrorType "" Nothing Nothing)
|
|
||||||
else void (action' bs) >> go rest
|
|
||||||
|
|
||||||
|
|
||||||
-- | Capture the stdout and stderr of the given action, which
|
|
||||||
-- is run in a subprocess. Stdin is closed. You might want to
|
|
||||||
-- 'race' this to make sure it terminates.
|
|
||||||
captureOutStreams :: IO a
|
|
||||||
-- ^ the action to execute in a subprocess
|
|
||||||
-> IO CapturedProcess
|
|
||||||
captureOutStreams action = do
|
|
||||||
actionWithPipes $ \(parentStdoutRead, childStdoutWrite) ->
|
|
||||||
actionWithPipes $ \(parentStderrRead, childStderrWrite) -> do
|
|
||||||
pid <- SPPB.forkProcess $ do
|
|
||||||
-- dup stdout
|
|
||||||
void $ dupTo childStdoutWrite stdOutput
|
|
||||||
closeFd childStdoutWrite
|
|
||||||
closeFd parentStdoutRead
|
|
||||||
|
|
||||||
-- dup stderr
|
|
||||||
void $ dupTo childStderrWrite stdError
|
|
||||||
closeFd childStderrWrite
|
|
||||||
closeFd parentStderrRead
|
|
||||||
|
|
||||||
-- execute the action
|
|
||||||
a <- action
|
|
||||||
void $ evaluate a
|
|
||||||
|
|
||||||
-- close everything we don't need
|
|
||||||
closeFd childStdoutWrite
|
|
||||||
closeFd childStderrWrite
|
|
||||||
|
|
||||||
-- start thread that writes the output
|
|
||||||
refOut <- newIORef BS.empty
|
|
||||||
refErr <- newIORef BS.empty
|
|
||||||
done <- newEmptyMVar
|
|
||||||
_ <-
|
|
||||||
forkIO
|
|
||||||
$ EX.handle (\(_ :: IOException) -> pure ())
|
|
||||||
$ flip EX.finally (putMVar done ())
|
|
||||||
$ writeStds parentStdoutRead parentStderrRead refOut refErr
|
|
||||||
|
|
||||||
status <- SPPB.getProcessStatus True True pid
|
|
||||||
void $ race (takeMVar done) (threadDelay (1000000 * 3))
|
|
||||||
|
|
||||||
case status of
|
|
||||||
-- readFd will take care of closing the fd
|
|
||||||
Just (SPPB.Exited es) -> do
|
|
||||||
stdout' <- readIORef refOut
|
|
||||||
stderr' <- readIORef refErr
|
|
||||||
pure $ CapturedProcess { _exitCode = es
|
|
||||||
, _stdOut = stdout'
|
|
||||||
, _stdErr = stderr'
|
|
||||||
}
|
|
||||||
|
|
||||||
_ -> throwIO $ userError ("No such PID " ++ show pid)
|
|
||||||
|
|
||||||
where
|
|
||||||
writeStds pout perr rout rerr = do
|
|
||||||
doneOut <- newEmptyMVar
|
|
||||||
void
|
|
||||||
$ forkIO
|
|
||||||
$ hideError eofErrorType
|
|
||||||
$ flip EX.finally (putMVar doneOut ())
|
|
||||||
$ readTilEOF (\x -> modifyIORef' rout (<> x)) pout
|
|
||||||
doneErr <- newEmptyMVar
|
|
||||||
void
|
|
||||||
$ forkIO
|
|
||||||
$ hideError eofErrorType
|
|
||||||
$ flip EX.finally (putMVar doneErr ())
|
|
||||||
$ readTilEOF (\x -> modifyIORef' rerr (<> x)) perr
|
|
||||||
takeMVar doneOut
|
|
||||||
takeMVar doneErr
|
|
||||||
|
|
||||||
readTilEOF ~action' fd' = do
|
|
||||||
bs <- SPIB.fdRead fd' 512
|
|
||||||
void $ action' bs
|
|
||||||
readTilEOF action' fd'
|
|
||||||
|
|
||||||
|
|
||||||
actionWithPipes :: ((Fd, Fd) -> IO b) -> IO b
|
|
||||||
actionWithPipes a =
|
|
||||||
createPipe >>= \(p1, p2) -> flip finally (cleanup [p1, p2]) $ a (p1, p2)
|
|
||||||
|
|
||||||
cleanup :: [Fd] -> IO ()
|
|
||||||
cleanup fds = for_ fds $ \fd -> handleIO (\_ -> pure ()) $ closeFd fd
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- | Create a new regular file in write-only mode. The file must not exist.
|
|
||||||
createRegularFileFd :: FileMode -> Path b -> IO Fd
|
|
||||||
createRegularFileFd fm dest =
|
|
||||||
FD.openFd (toFilePath dest) WriteOnly [oExcl] (Just fm)
|
|
||||||
|
|
||||||
|
|
||||||
-- | Thin wrapper around `executeFile`.
|
|
||||||
exec :: ByteString -- ^ thing to execute
|
|
||||||
-> Bool -- ^ whether to search PATH for the thing
|
|
||||||
-> [ByteString] -- ^ args for the thing
|
|
||||||
-> Maybe (Path Abs) -- ^ optionally chdir into this
|
|
||||||
-> Maybe [(ByteString, ByteString)] -- ^ optional environment
|
|
||||||
-> IO (Either ProcessError ())
|
|
||||||
exec exe spath args chdir env = do
|
|
||||||
pid <- SPPB.forkProcess $ do
|
|
||||||
maybe (pure ()) (changeWorkingDirectory . toFilePath) chdir
|
|
||||||
SPPB.executeFile exe spath args env
|
|
||||||
|
|
||||||
fmap (toProcessError exe args) $ SPPB.getProcessStatus True True pid
|
|
||||||
|
|
||||||
|
|
||||||
toProcessError :: ByteString
|
|
||||||
-> [ByteString]
|
|
||||||
-> Maybe ProcessStatus
|
|
||||||
-> Either ProcessError ()
|
|
||||||
toProcessError exe args mps = case mps of
|
|
||||||
Just (SPPB.Exited (ExitFailure xi)) -> Left $ NonZeroExit xi exe args
|
|
||||||
Just (SPPB.Exited ExitSuccess ) -> Right ()
|
|
||||||
Just (Terminated _ _ ) -> Left $ PTerminated exe args
|
|
||||||
Just (Stopped _ ) -> Left $ PStopped exe args
|
|
||||||
Nothing -> Left $ NoSuchPid exe args
|
|
||||||
|
|
||||||
|
|
||||||
-- | Search for a file in the search paths.
|
|
||||||
--
|
|
||||||
-- Catches `PermissionDenied` and `NoSuchThing` and returns `Nothing`.
|
|
||||||
searchPath :: [Path Abs] -> Path Rel -> IO (Maybe (Path Abs))
|
|
||||||
searchPath paths needle = go paths
|
|
||||||
where
|
|
||||||
go [] = pure Nothing
|
|
||||||
go (x : xs) =
|
|
||||||
hideErrorDefM [InappropriateType, PermissionDenied, NoSuchThing] (go xs)
|
|
||||||
$ do
|
|
||||||
dirStream <- openDirStream (toFilePath x)
|
|
||||||
S.findM (\(_, p) -> isMatch x p) (dirContentsStream dirStream)
|
|
||||||
>>= \case
|
|
||||||
Just _ -> pure $ Just (x </> needle)
|
|
||||||
Nothing -> go xs
|
|
||||||
isMatch basedir p = do
|
|
||||||
if p == toFilePath needle
|
|
||||||
then isExecutable (basedir </> needle)
|
|
||||||
else pure False
|
|
||||||
|
|
||||||
|
|
||||||
-- | Check wether a binary is shadowed by another one that comes before
|
|
||||||
-- it in PATH. Returns the path to said binary, if any.
|
|
||||||
isShadowed :: Path Abs -> IO (Maybe (Path Abs))
|
|
||||||
isShadowed p = do
|
|
||||||
let dir = dirname p
|
|
||||||
fn <- basename p
|
|
||||||
spaths <- catMaybes . fmap parseAbs <$> liftIO getSearchPath
|
|
||||||
if dir `elem` spaths
|
|
||||||
then do
|
|
||||||
let shadowPaths = takeWhile (/= dir) spaths
|
|
||||||
searchPath shadowPaths fn
|
|
||||||
else pure Nothing
|
|
||||||
|
|
||||||
|
|
||||||
-- | Check whether the binary is in PATH. This returns only `True`
|
|
||||||
-- if the directory containing the binary is part of PATH.
|
|
||||||
isInPath :: Path Abs -> IO Bool
|
|
||||||
isInPath p = do
|
|
||||||
let dir = dirname p
|
|
||||||
fn <- basename p
|
|
||||||
spaths <- catMaybes . fmap parseAbs <$> liftIO getSearchPath
|
|
||||||
if dir `elem` spaths
|
|
||||||
then isJust <$> searchPath [dir] fn
|
|
||||||
else pure False
|
|
||||||
|
|
||||||
|
|
||||||
findFiles :: Path Abs -> Regex -> IO [Path Rel]
|
|
||||||
findFiles path regex = do
|
|
||||||
dirStream <- openDirStream (toFilePath path)
|
|
||||||
f <-
|
|
||||||
(fmap . fmap) snd
|
|
||||||
. S.toList
|
|
||||||
. S.filter (\(_, p) -> match regex p)
|
|
||||||
$ dirContentsStream dirStream
|
|
||||||
pure $ parseRel =<< f
|
|
||||||
|
|
||||||
|
|
||||||
findFiles' :: Path Abs -> MP.Parsec Void Text () -> IO [Path Rel]
|
|
||||||
findFiles' path parser = do
|
|
||||||
dirStream <- openDirStream (toFilePath path)
|
|
||||||
f <-
|
|
||||||
(fmap . fmap) snd
|
|
||||||
. S.toList
|
|
||||||
. S.filter (\(_, p) -> case E.decodeUtf8' p of
|
|
||||||
Left _ -> False
|
|
||||||
Right p' -> isJust $ MP.parseMaybe parser p')
|
|
||||||
$ dirContentsStream dirStream
|
|
||||||
pure $ parseRel =<< f
|
|
||||||
|
|
||||||
|
|
||||||
isBrokenSymlink :: Path Abs -> IO Bool
|
|
||||||
isBrokenSymlink p =
|
|
||||||
handleIO
|
|
||||||
(\e -> if ioeGetErrorType e == NoSuchThing then pure True else throwIO e)
|
|
||||||
$ do
|
|
||||||
_ <- canonicalizePath p
|
|
||||||
pure False
|
|
||||||
|
|
||||||
|
|
||||||
chmod_755 :: (MonadLogger m, MonadIO m) => Path a -> m ()
|
|
||||||
chmod_755 (toFilePath -> fp) = do
|
|
||||||
let exe_mode =
|
|
||||||
nullFileMode
|
|
||||||
`unionFileModes` ownerExecuteMode
|
|
||||||
`unionFileModes` ownerReadMode
|
|
||||||
`unionFileModes` ownerWriteMode
|
|
||||||
`unionFileModes` groupExecuteMode
|
|
||||||
`unionFileModes` groupReadMode
|
|
||||||
`unionFileModes` otherExecuteMode
|
|
||||||
`unionFileModes` otherReadMode
|
|
||||||
$(logDebug) [i|chmod 755 #{fp}|]
|
|
||||||
liftIO $ setFileMode fp exe_mode
|
|
||||||
|
|||||||
106
lib/GHCup/Utils/File/Common.hs
Normal file
106
lib/GHCup/Utils/File/Common.hs
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
{-# LANGUAGE QuasiQuotes #-}
|
||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
|
{-# LANGUAGE TemplateHaskell #-}
|
||||||
|
{-# LANGUAGE ViewPatterns #-}
|
||||||
|
|
||||||
|
module GHCup.Utils.File.Common where
|
||||||
|
|
||||||
|
import GHCup.Utils.Prelude
|
||||||
|
|
||||||
|
import Control.Monad.Extra
|
||||||
|
import Control.Monad.Reader
|
||||||
|
import Data.Maybe
|
||||||
|
import Data.String.Interpolate
|
||||||
|
import GHC.IO.Exception
|
||||||
|
import Optics hiding ((<|), (|>))
|
||||||
|
import System.Directory
|
||||||
|
import System.FilePath
|
||||||
|
import Text.PrettyPrint.HughesPJClass hiding ( (<>) )
|
||||||
|
import Text.Regex.Posix
|
||||||
|
|
||||||
|
import qualified Data.ByteString.Lazy as BL
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
data ProcessError = NonZeroExit Int FilePath [String]
|
||||||
|
| PTerminated FilePath [String]
|
||||||
|
| PStopped FilePath [String]
|
||||||
|
| NoSuchPid FilePath [String]
|
||||||
|
deriving Show
|
||||||
|
|
||||||
|
instance Pretty ProcessError where
|
||||||
|
pPrint (NonZeroExit e exe args) =
|
||||||
|
text [i|Process "#{exe}" with arguments #{args} failed with exit code #{e}.|]
|
||||||
|
pPrint (PTerminated exe args) =
|
||||||
|
text [i|Process "#{exe}" with arguments #{args} terminated.|]
|
||||||
|
pPrint (PStopped exe args) =
|
||||||
|
text [i|Process "#{exe}" with arguments #{args} stopped.|]
|
||||||
|
pPrint (NoSuchPid exe args) =
|
||||||
|
text [i|Could not find PID for process running "#{exe}" with arguments #{args}.|]
|
||||||
|
|
||||||
|
data CapturedProcess = CapturedProcess
|
||||||
|
{ _exitCode :: ExitCode
|
||||||
|
, _stdOut :: BL.ByteString
|
||||||
|
, _stdErr :: BL.ByteString
|
||||||
|
}
|
||||||
|
deriving (Eq, Show)
|
||||||
|
|
||||||
|
makeLenses ''CapturedProcess
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- | Search for a file in the search paths.
|
||||||
|
--
|
||||||
|
-- Catches `PermissionDenied` and `NoSuchThing` and returns `Nothing`.
|
||||||
|
searchPath :: [FilePath] -> FilePath -> IO (Maybe FilePath)
|
||||||
|
searchPath paths needle = go paths
|
||||||
|
where
|
||||||
|
go [] = pure Nothing
|
||||||
|
go (x : xs) =
|
||||||
|
hideErrorDefM [InappropriateType, PermissionDenied, NoSuchThing] (go xs)
|
||||||
|
$ do
|
||||||
|
contents <- listDirectory x
|
||||||
|
findM (isMatch x) contents >>= \case
|
||||||
|
Just _ -> pure $ Just (x </> needle)
|
||||||
|
Nothing -> go xs
|
||||||
|
isMatch basedir p = do
|
||||||
|
if p == needle
|
||||||
|
then isExecutable (basedir </> needle)
|
||||||
|
else pure False
|
||||||
|
|
||||||
|
isExecutable :: FilePath -> IO Bool
|
||||||
|
isExecutable file = executable <$> getPermissions file
|
||||||
|
|
||||||
|
|
||||||
|
-- | Check wether a binary is shadowed by another one that comes before
|
||||||
|
-- it in PATH. Returns the path to said binary, if any.
|
||||||
|
isShadowed :: FilePath -> IO (Maybe FilePath)
|
||||||
|
isShadowed p = do
|
||||||
|
let dir = takeDirectory p
|
||||||
|
let fn = takeFileName p
|
||||||
|
spaths <- liftIO getSearchPath
|
||||||
|
if dir `elem` spaths
|
||||||
|
then do
|
||||||
|
let shadowPaths = takeWhile (/= dir) spaths
|
||||||
|
searchPath shadowPaths fn
|
||||||
|
else pure Nothing
|
||||||
|
|
||||||
|
|
||||||
|
-- | Check whether the binary is in PATH. This returns only `True`
|
||||||
|
-- if the directory containing the binary is part of PATH.
|
||||||
|
isInPath :: FilePath -> IO Bool
|
||||||
|
isInPath p = do
|
||||||
|
let dir = takeDirectory p
|
||||||
|
let fn = takeFileName p
|
||||||
|
spaths <- liftIO getSearchPath
|
||||||
|
if dir `elem` spaths
|
||||||
|
then isJust <$> searchPath [dir] fn
|
||||||
|
else pure False
|
||||||
|
|
||||||
|
|
||||||
|
findFiles :: FilePath -> Regex -> IO [FilePath]
|
||||||
|
findFiles path regex = do
|
||||||
|
contents <- listDirectory path
|
||||||
|
pure $ filter (match regex) contents
|
||||||
|
|
||||||
392
lib/GHCup/Utils/File/Posix.hs
Normal file
392
lib/GHCup/Utils/File/Posix.hs
Normal file
@@ -0,0 +1,392 @@
|
|||||||
|
{-# LANGUAGE QuasiQuotes #-}
|
||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
|
{-# LANGUAGE TemplateHaskell #-}
|
||||||
|
{-# LANGUAGE ViewPatterns #-}
|
||||||
|
|
||||||
|
{-|
|
||||||
|
Module : GHCup.Utils.File.Posix
|
||||||
|
Description : File and unix APIs
|
||||||
|
Copyright : (c) Julian Ospald, 2020
|
||||||
|
License : LGPL-3.0
|
||||||
|
Maintainer : hasufell@hasufell.de
|
||||||
|
Stability : experimental
|
||||||
|
Portability : POSIX
|
||||||
|
|
||||||
|
This module handles file and executable handling.
|
||||||
|
Some of these functions use sophisticated logging.
|
||||||
|
-}
|
||||||
|
module GHCup.Utils.File.Posix where
|
||||||
|
|
||||||
|
import GHCup.Utils.File.Common
|
||||||
|
import GHCup.Utils.Prelude
|
||||||
|
import GHCup.Types
|
||||||
|
import GHCup.Types.Optics
|
||||||
|
|
||||||
|
import Control.Concurrent
|
||||||
|
import Control.Concurrent.Async
|
||||||
|
import Control.Exception ( evaluate )
|
||||||
|
import Control.Exception.Safe
|
||||||
|
import Control.Monad
|
||||||
|
import Control.Monad.Logger
|
||||||
|
import Control.Monad.Reader
|
||||||
|
import Control.Monad.Trans.State.Strict
|
||||||
|
import Data.ByteString ( ByteString )
|
||||||
|
import Data.Foldable
|
||||||
|
import Data.IORef
|
||||||
|
import Data.Sequence ( Seq, (|>) )
|
||||||
|
import Data.String.Interpolate
|
||||||
|
import Data.List
|
||||||
|
import Data.Word8
|
||||||
|
import GHC.IO.Exception
|
||||||
|
import System.Console.Pretty hiding ( Pretty )
|
||||||
|
import System.Console.Regions
|
||||||
|
import System.IO.Error
|
||||||
|
import System.FilePath
|
||||||
|
import System.Directory
|
||||||
|
import System.Posix.Directory
|
||||||
|
import System.Posix.Files
|
||||||
|
import System.Posix.IO
|
||||||
|
import System.Posix.Process ( ProcessStatus(..) )
|
||||||
|
import System.Posix.Types
|
||||||
|
|
||||||
|
|
||||||
|
import qualified Control.Exception as EX
|
||||||
|
import qualified Data.Sequence as Sq
|
||||||
|
import qualified Data.Text as T
|
||||||
|
import qualified Data.Text.Encoding as E
|
||||||
|
import qualified System.Posix.Process as SPP
|
||||||
|
import qualified Data.ByteString as BS
|
||||||
|
import qualified Data.ByteString.Lazy as BL
|
||||||
|
import qualified "unix-bytestring" System.Posix.IO.ByteString
|
||||||
|
as SPIB
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- | Execute the given command and collect the stdout, stderr and the exit code.
|
||||||
|
-- The command is run in a subprocess.
|
||||||
|
executeOut :: MonadIO m
|
||||||
|
=> FilePath -- ^ command as filename, e.g. 'ls'
|
||||||
|
-> [String] -- ^ arguments to the command
|
||||||
|
-> Maybe FilePath -- ^ chdir to this path
|
||||||
|
-> m CapturedProcess
|
||||||
|
executeOut path args chdir = liftIO $ captureOutStreams $ do
|
||||||
|
maybe (pure ()) changeWorkingDirectory chdir
|
||||||
|
SPP.executeFile path True args Nothing
|
||||||
|
|
||||||
|
|
||||||
|
execLogged :: ( MonadReader env m
|
||||||
|
, HasSettings env
|
||||||
|
, HasDirs env
|
||||||
|
, MonadIO m
|
||||||
|
, MonadThrow m)
|
||||||
|
=> FilePath -- ^ thing to execute
|
||||||
|
-> [String] -- ^ args for the thing
|
||||||
|
-> Maybe FilePath -- ^ optionally chdir into this
|
||||||
|
-> FilePath -- ^ log filename (opened in append mode)
|
||||||
|
-> Maybe [(String, String)] -- ^ optional environment
|
||||||
|
-> m (Either ProcessError ())
|
||||||
|
execLogged exe args chdir lfile env = do
|
||||||
|
Settings {..} <- getSettings
|
||||||
|
Dirs {..} <- getDirs
|
||||||
|
let logfile = logsDir </> lfile <> ".log"
|
||||||
|
liftIO $ bracket (openFd logfile WriteOnly (Just newFilePerms) defaultFileFlags{ append = True })
|
||||||
|
closeFd
|
||||||
|
(action verbose)
|
||||||
|
where
|
||||||
|
action verbose fd = do
|
||||||
|
actionWithPipes $ \(stdoutRead, stdoutWrite) -> do
|
||||||
|
-- start the thread that logs to stdout
|
||||||
|
pState <- newEmptyMVar
|
||||||
|
done <- newEmptyMVar
|
||||||
|
void
|
||||||
|
$ forkIO
|
||||||
|
$ EX.handle (\(_ :: IOException) -> pure ())
|
||||||
|
$ EX.finally
|
||||||
|
(if verbose
|
||||||
|
then tee fd stdoutRead
|
||||||
|
else printToRegion fd stdoutRead 6 pState
|
||||||
|
)
|
||||||
|
(putMVar done ())
|
||||||
|
|
||||||
|
-- fork the subprocess
|
||||||
|
pid <- SPP.forkProcess $ do
|
||||||
|
void $ dupTo stdoutWrite stdOutput
|
||||||
|
void $ dupTo stdoutWrite stdError
|
||||||
|
closeFd stdoutRead
|
||||||
|
closeFd stdoutWrite
|
||||||
|
|
||||||
|
-- execute the action
|
||||||
|
maybe (pure ()) changeWorkingDirectory chdir
|
||||||
|
void $ SPP.executeFile exe (not ("./" `isPrefixOf` exe)) args env
|
||||||
|
|
||||||
|
closeFd stdoutWrite
|
||||||
|
|
||||||
|
-- wait for the subprocess to finish
|
||||||
|
e <- toProcessError exe args <$!> SPP.getProcessStatus True True pid
|
||||||
|
putMVar pState (either (const False) (const True) e)
|
||||||
|
|
||||||
|
void $ race (takeMVar done) (threadDelay (1000000 * 3))
|
||||||
|
closeFd stdoutRead
|
||||||
|
|
||||||
|
pure e
|
||||||
|
|
||||||
|
tee :: Fd -> Fd -> IO ()
|
||||||
|
tee fileFd fdIn = readTilEOF lineAction fdIn
|
||||||
|
|
||||||
|
where
|
||||||
|
lineAction :: ByteString -> IO ()
|
||||||
|
lineAction bs' = do
|
||||||
|
void $ SPIB.fdWrite fileFd (bs' <> "\n")
|
||||||
|
void $ SPIB.fdWrite stdOutput (bs' <> "\n")
|
||||||
|
|
||||||
|
-- Reads fdIn and logs the output in a continous scrolling area
|
||||||
|
-- of 'size' terminal lines. Also writes to a log file.
|
||||||
|
printToRegion :: Fd -> Fd -> Int -> MVar Bool -> IO ()
|
||||||
|
printToRegion fileFd fdIn size pState = do
|
||||||
|
void $ displayConsoleRegions $ do
|
||||||
|
rs <-
|
||||||
|
liftIO
|
||||||
|
. fmap Sq.fromList
|
||||||
|
. sequence
|
||||||
|
. replicate size
|
||||||
|
. openConsoleRegion
|
||||||
|
$ Linear
|
||||||
|
flip runStateT mempty
|
||||||
|
$ handle
|
||||||
|
(\(ex :: SomeException) -> do
|
||||||
|
ps <- liftIO $ takeMVar pState
|
||||||
|
when ps (forM_ rs (liftIO . closeConsoleRegion))
|
||||||
|
throw ex
|
||||||
|
)
|
||||||
|
$ readTilEOF (lineAction rs) fdIn
|
||||||
|
|
||||||
|
where
|
||||||
|
-- action to perform line by line
|
||||||
|
-- TODO: do this with vty for efficiency
|
||||||
|
lineAction :: (MonadMask m, MonadIO m)
|
||||||
|
=> Seq ConsoleRegion
|
||||||
|
-> ByteString
|
||||||
|
-> StateT (Seq ByteString) m ()
|
||||||
|
lineAction rs = \bs' -> do
|
||||||
|
void $ liftIO $ SPIB.fdWrite fileFd (bs' <> "\n")
|
||||||
|
modify (swapRegs bs')
|
||||||
|
regs <- get
|
||||||
|
liftIO $ forM_ (Sq.zip regs rs) $ \(bs, r) -> setConsoleRegion r $ do
|
||||||
|
w <- consoleWidth
|
||||||
|
return
|
||||||
|
. T.pack
|
||||||
|
. color Blue
|
||||||
|
. T.unpack
|
||||||
|
. decUTF8Safe
|
||||||
|
. trim w
|
||||||
|
. (\b -> "[ " <> E.encodeUtf8 (T.pack lfile) <> " ] " <> b)
|
||||||
|
$ bs
|
||||||
|
|
||||||
|
swapRegs :: a -> Seq a -> Seq a
|
||||||
|
swapRegs bs = \regs -> if
|
||||||
|
| Sq.length regs < size -> regs |> bs
|
||||||
|
| otherwise -> Sq.drop 1 regs |> bs
|
||||||
|
|
||||||
|
-- trim output line to terminal width
|
||||||
|
trim :: Int -> ByteString -> ByteString
|
||||||
|
trim w = \bs -> if
|
||||||
|
| BS.length bs > w && w > 5 -> BS.take (w - 4) bs <> "..."
|
||||||
|
| otherwise -> bs
|
||||||
|
|
||||||
|
-- Consecutively read from Fd in 512 chunks until we hit
|
||||||
|
-- newline or EOF.
|
||||||
|
readLine :: MonadIO m
|
||||||
|
=> Fd -- ^ input file descriptor
|
||||||
|
-> ByteString -- ^ rest buffer (read across newline)
|
||||||
|
-> m (ByteString, ByteString, Bool) -- ^ (full line, rest, eof)
|
||||||
|
readLine fd = go
|
||||||
|
where
|
||||||
|
go inBs = do
|
||||||
|
-- if buffer is not empty, process it first
|
||||||
|
mbs <- if BS.length inBs == 0
|
||||||
|
-- otherwise attempt read
|
||||||
|
then liftIO
|
||||||
|
$ handleIO (\e -> if isEOFError e then pure Nothing else ioError e)
|
||||||
|
$ fmap Just
|
||||||
|
$ SPIB.fdRead fd 512
|
||||||
|
else pure $ Just inBs
|
||||||
|
case mbs of
|
||||||
|
Nothing -> pure ("", "", True)
|
||||||
|
Just bs -> do
|
||||||
|
-- split on newline
|
||||||
|
let (line, rest) = BS.span (/= _lf) bs
|
||||||
|
if
|
||||||
|
| BS.length rest /= 0 -> pure (line, BS.tail rest, False)
|
||||||
|
-- if rest is empty, then there was no newline, process further
|
||||||
|
| otherwise -> (\(l, r, b) -> (line <> l, r, b)) <$!> go mempty
|
||||||
|
|
||||||
|
readTilEOF :: MonadIO m => (ByteString -> m a) -> Fd -> m ()
|
||||||
|
readTilEOF ~action' fd' = go mempty
|
||||||
|
where
|
||||||
|
go bs' = do
|
||||||
|
(bs, rest, eof) <- readLine fd' bs'
|
||||||
|
if eof
|
||||||
|
then liftIO $ ioError (mkIOError eofErrorType "" Nothing Nothing)
|
||||||
|
else void (action' bs) >> go rest
|
||||||
|
|
||||||
|
|
||||||
|
-- | Capture the stdout and stderr of the given action, which
|
||||||
|
-- is run in a subprocess. Stdin is closed. You might want to
|
||||||
|
-- 'race' this to make sure it terminates.
|
||||||
|
captureOutStreams :: IO a
|
||||||
|
-- ^ the action to execute in a subprocess
|
||||||
|
-> IO CapturedProcess
|
||||||
|
captureOutStreams action = do
|
||||||
|
actionWithPipes $ \(parentStdoutRead, childStdoutWrite) ->
|
||||||
|
actionWithPipes $ \(parentStderrRead, childStderrWrite) -> do
|
||||||
|
pid <- SPP.forkProcess $ do
|
||||||
|
-- dup stdout
|
||||||
|
void $ dupTo childStdoutWrite stdOutput
|
||||||
|
closeFd childStdoutWrite
|
||||||
|
closeFd parentStdoutRead
|
||||||
|
|
||||||
|
-- dup stderr
|
||||||
|
void $ dupTo childStderrWrite stdError
|
||||||
|
closeFd childStderrWrite
|
||||||
|
closeFd parentStderrRead
|
||||||
|
|
||||||
|
-- execute the action
|
||||||
|
a <- action
|
||||||
|
void $ evaluate a
|
||||||
|
|
||||||
|
-- close everything we don't need
|
||||||
|
closeFd childStdoutWrite
|
||||||
|
closeFd childStderrWrite
|
||||||
|
|
||||||
|
-- start thread that writes the output
|
||||||
|
refOut <- newIORef BL.empty
|
||||||
|
refErr <- newIORef BL.empty
|
||||||
|
done <- newEmptyMVar
|
||||||
|
_ <-
|
||||||
|
forkIO
|
||||||
|
$ EX.handle (\(_ :: IOException) -> pure ())
|
||||||
|
$ flip EX.finally (putMVar done ())
|
||||||
|
$ writeStds parentStdoutRead parentStderrRead refOut refErr
|
||||||
|
|
||||||
|
status <- SPP.getProcessStatus True True pid
|
||||||
|
void $ race (takeMVar done) (threadDelay (1000000 * 3))
|
||||||
|
|
||||||
|
case status of
|
||||||
|
-- readFd will take care of closing the fd
|
||||||
|
Just (SPP.Exited es) -> do
|
||||||
|
stdout' <- readIORef refOut
|
||||||
|
stderr' <- readIORef refErr
|
||||||
|
pure $ CapturedProcess { _exitCode = es
|
||||||
|
, _stdOut = stdout'
|
||||||
|
, _stdErr = stderr'
|
||||||
|
}
|
||||||
|
|
||||||
|
_ -> throwIO $ userError ("No such PID " ++ show pid)
|
||||||
|
|
||||||
|
where
|
||||||
|
writeStds :: Fd -> Fd -> IORef BL.ByteString -> IORef BL.ByteString -> IO ()
|
||||||
|
writeStds pout perr rout rerr = do
|
||||||
|
doneOut <- newEmptyMVar
|
||||||
|
void
|
||||||
|
$ forkIO
|
||||||
|
$ hideError eofErrorType
|
||||||
|
$ flip EX.finally (putMVar doneOut ())
|
||||||
|
$ readTilEOF (\x -> modifyIORef' rout (<> BL.fromStrict x)) pout
|
||||||
|
doneErr <- newEmptyMVar
|
||||||
|
void
|
||||||
|
$ forkIO
|
||||||
|
$ hideError eofErrorType
|
||||||
|
$ flip EX.finally (putMVar doneErr ())
|
||||||
|
$ readTilEOF (\x -> modifyIORef' rerr (<> BL.fromStrict x)) perr
|
||||||
|
takeMVar doneOut
|
||||||
|
takeMVar doneErr
|
||||||
|
|
||||||
|
readTilEOF ~action' fd' = do
|
||||||
|
bs <- SPIB.fdRead fd' 512
|
||||||
|
void $ action' bs
|
||||||
|
readTilEOF action' fd'
|
||||||
|
|
||||||
|
|
||||||
|
actionWithPipes :: ((Fd, Fd) -> IO b) -> IO b
|
||||||
|
actionWithPipes a =
|
||||||
|
createPipe >>= \(p1, p2) -> flip finally (cleanup [p1, p2]) $ a (p1, p2)
|
||||||
|
|
||||||
|
cleanup :: [Fd] -> IO ()
|
||||||
|
cleanup fds = for_ fds $ \fd -> handleIO (\_ -> pure ()) $ closeFd fd
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- | Create a new regular file in write-only mode. The file must not exist.
|
||||||
|
createRegularFileFd :: FileMode -> FilePath -> IO Fd
|
||||||
|
createRegularFileFd fm dest =
|
||||||
|
openFd dest WriteOnly (Just fm) defaultFileFlags{ exclusive = True }
|
||||||
|
|
||||||
|
|
||||||
|
-- | Thin wrapper around `executeFile`.
|
||||||
|
exec :: MonadIO m
|
||||||
|
=> String -- ^ thing to execute
|
||||||
|
-> [String] -- ^ args for the thing
|
||||||
|
-> Maybe FilePath -- ^ optionally chdir into this
|
||||||
|
-> Maybe [(String, String)] -- ^ optional environment
|
||||||
|
-> m (Either ProcessError ())
|
||||||
|
exec exe args chdir env = liftIO $ do
|
||||||
|
pid <- SPP.forkProcess $ do
|
||||||
|
maybe (pure ()) changeWorkingDirectory chdir
|
||||||
|
SPP.executeFile exe (not ("./" `isPrefixOf` exe)) args env
|
||||||
|
|
||||||
|
fmap (toProcessError exe args) $ SPP.getProcessStatus True True pid
|
||||||
|
|
||||||
|
|
||||||
|
toProcessError :: FilePath
|
||||||
|
-> [String]
|
||||||
|
-> Maybe ProcessStatus
|
||||||
|
-> Either ProcessError ()
|
||||||
|
toProcessError exe args mps = case mps of
|
||||||
|
Just (SPP.Exited (ExitFailure xi)) -> Left $ NonZeroExit xi exe args
|
||||||
|
Just (SPP.Exited ExitSuccess ) -> Right ()
|
||||||
|
Just (Terminated _ _ ) -> Left $ PTerminated exe args
|
||||||
|
Just (Stopped _ ) -> Left $ PStopped exe args
|
||||||
|
Nothing -> Left $ NoSuchPid exe args
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
chmod_755 :: (MonadLogger m, MonadIO m) => FilePath -> m ()
|
||||||
|
chmod_755 fp = do
|
||||||
|
let exe_mode =
|
||||||
|
nullFileMode
|
||||||
|
`unionFileModes` ownerExecuteMode
|
||||||
|
`unionFileModes` ownerReadMode
|
||||||
|
`unionFileModes` ownerWriteMode
|
||||||
|
`unionFileModes` groupExecuteMode
|
||||||
|
`unionFileModes` groupReadMode
|
||||||
|
`unionFileModes` otherExecuteMode
|
||||||
|
`unionFileModes` otherReadMode
|
||||||
|
$(logDebug) [i|chmod 755 #{fp}|]
|
||||||
|
liftIO $ setFileMode fp exe_mode
|
||||||
|
|
||||||
|
|
||||||
|
-- |Default permissions for a new file.
|
||||||
|
newFilePerms :: FileMode
|
||||||
|
newFilePerms =
|
||||||
|
ownerWriteMode
|
||||||
|
`unionFileModes` ownerReadMode
|
||||||
|
`unionFileModes` groupWriteMode
|
||||||
|
`unionFileModes` groupReadMode
|
||||||
|
`unionFileModes` otherWriteMode
|
||||||
|
`unionFileModes` otherReadMode
|
||||||
|
|
||||||
|
|
||||||
|
-- | Checks whether the binary is a broken link.
|
||||||
|
isBrokenSymlink :: FilePath -> IO Bool
|
||||||
|
isBrokenSymlink fp = do
|
||||||
|
try (pathIsSymbolicLink fp) >>= \case
|
||||||
|
Right True -> do
|
||||||
|
let symDir = takeDirectory fp
|
||||||
|
tfp <- getSymbolicLinkTarget fp
|
||||||
|
not <$> doesPathExist
|
||||||
|
-- this drops 'symDir' if 'tfp' is absolute
|
||||||
|
(symDir </> tfp)
|
||||||
|
Right b -> pure b
|
||||||
|
Left e | isDoesNotExistError e -> pure False
|
||||||
|
| otherwise -> throwIO e
|
||||||
266
lib/GHCup/Utils/File/Windows.hs
Normal file
266
lib/GHCup/Utils/File/Windows.hs
Normal file
@@ -0,0 +1,266 @@
|
|||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
|
|
||||||
|
{-|
|
||||||
|
Module : GHCup.Utils.File.Windows
|
||||||
|
Description : File and windows APIs
|
||||||
|
Copyright : (c) Julian Ospald, 2020
|
||||||
|
License : LGPL-3.0
|
||||||
|
Maintainer : hasufell@hasufell.de
|
||||||
|
Stability : experimental
|
||||||
|
Portability : Windows
|
||||||
|
|
||||||
|
This module handles file and executable handling.
|
||||||
|
Some of these functions use sophisticated logging.
|
||||||
|
-}
|
||||||
|
module GHCup.Utils.File.Windows where
|
||||||
|
|
||||||
|
import {-# SOURCE #-} GHCup.Utils ( getLinkTarget, pathIsLink )
|
||||||
|
import GHCup.Utils.Dirs
|
||||||
|
import GHCup.Utils.File.Common
|
||||||
|
import GHCup.Types
|
||||||
|
import GHCup.Types.Optics
|
||||||
|
|
||||||
|
import Control.Concurrent
|
||||||
|
import Control.DeepSeq
|
||||||
|
import Control.Exception.Safe
|
||||||
|
import Control.Monad
|
||||||
|
import Control.Monad.Reader
|
||||||
|
import Data.List
|
||||||
|
import Foreign.C.Error
|
||||||
|
import GHC.IO.Exception
|
||||||
|
import GHC.IO.Handle
|
||||||
|
import System.Directory
|
||||||
|
import System.Environment
|
||||||
|
import System.FilePath
|
||||||
|
import System.IO
|
||||||
|
import System.Process
|
||||||
|
|
||||||
|
import qualified Control.Exception as EX
|
||||||
|
import qualified Data.ByteString as BS
|
||||||
|
import qualified Data.ByteString.Lazy as BL
|
||||||
|
import qualified Data.Map.Strict as Map
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
toProcessError :: FilePath
|
||||||
|
-> [FilePath]
|
||||||
|
-> ExitCode
|
||||||
|
-> Either ProcessError ()
|
||||||
|
toProcessError exe args exitcode = case exitcode of
|
||||||
|
(ExitFailure xi) -> Left $ NonZeroExit xi exe args
|
||||||
|
ExitSuccess -> Right ()
|
||||||
|
|
||||||
|
|
||||||
|
-- | @readCreateProcessWithExitCode@ works exactly like 'readProcessWithExitCode' except that it
|
||||||
|
-- lets you pass 'CreateProcess' giving better flexibility.
|
||||||
|
--
|
||||||
|
-- Note that @Handle@s provided for @std_in@, @std_out@, or @std_err@ via the CreateProcess
|
||||||
|
-- record will be ignored.
|
||||||
|
--
|
||||||
|
-- @since 1.2.3.0
|
||||||
|
readCreateProcessWithExitCodeBS
|
||||||
|
:: CreateProcess
|
||||||
|
-> BL.ByteString
|
||||||
|
-> IO (ExitCode, BL.ByteString, BL.ByteString) -- ^ exitcode, stdout, stderr
|
||||||
|
readCreateProcessWithExitCodeBS cp input = do
|
||||||
|
let cp_opts = cp {
|
||||||
|
std_in = CreatePipe,
|
||||||
|
std_out = CreatePipe,
|
||||||
|
std_err = CreatePipe
|
||||||
|
}
|
||||||
|
withCreateProcess_ "readCreateProcessWithExitCodeBS" cp_opts $
|
||||||
|
\mb_inh mb_outh mb_errh ph ->
|
||||||
|
case (mb_inh, mb_outh, mb_errh) of
|
||||||
|
(Just inh, Just outh, Just errh) -> do
|
||||||
|
|
||||||
|
out <- BS.hGetContents outh
|
||||||
|
err <- BS.hGetContents errh
|
||||||
|
|
||||||
|
-- fork off threads to start consuming stdout & stderr
|
||||||
|
withForkWait (EX.evaluate $ rnf out) $ \waitOut ->
|
||||||
|
withForkWait (EX.evaluate $ rnf err) $ \waitErr -> do
|
||||||
|
|
||||||
|
-- now write any input
|
||||||
|
unless (BL.null input) $
|
||||||
|
ignoreSigPipe $ BL.hPut inh input
|
||||||
|
-- hClose performs implicit hFlush, and thus may trigger a SIGPIPE
|
||||||
|
ignoreSigPipe $ hClose inh
|
||||||
|
|
||||||
|
-- wait on the output
|
||||||
|
waitOut
|
||||||
|
waitErr
|
||||||
|
|
||||||
|
hClose outh
|
||||||
|
hClose errh
|
||||||
|
|
||||||
|
-- wait on the process
|
||||||
|
ex <- waitForProcess ph
|
||||||
|
return (ex, BL.fromStrict out, BL.fromStrict err)
|
||||||
|
|
||||||
|
(Nothing,_,_) -> error "readCreateProcessWithExitCodeBS: Failed to get a stdin handle."
|
||||||
|
(_,Nothing,_) -> error "readCreateProcessWithExitCodeBS: Failed to get a stdout handle."
|
||||||
|
(_,_,Nothing) -> error "readCreateProcessWithExitCodeBS: Failed to get a stderr handle."
|
||||||
|
where
|
||||||
|
ignoreSigPipe :: IO () -> IO ()
|
||||||
|
ignoreSigPipe = EX.handle $ \e -> case e of
|
||||||
|
IOError { ioe_type = ResourceVanished
|
||||||
|
, ioe_errno = Just ioe }
|
||||||
|
| Errno ioe == ePIPE -> return ()
|
||||||
|
_ -> throwIO e
|
||||||
|
-- wrapper so we can get exceptions with the appropriate function name.
|
||||||
|
withCreateProcess_
|
||||||
|
:: String
|
||||||
|
-> CreateProcess
|
||||||
|
-> (Maybe Handle -> Maybe Handle -> Maybe Handle -> ProcessHandle -> IO a)
|
||||||
|
-> IO a
|
||||||
|
withCreateProcess_ fun c action =
|
||||||
|
EX.bracketOnError (createProcess_ fun c) cleanupProcess
|
||||||
|
(\(m_in, m_out, m_err, ph) -> action m_in m_out m_err ph)
|
||||||
|
|
||||||
|
-- | Fork a thread while doing something else, but kill it if there's an
|
||||||
|
-- exception.
|
||||||
|
--
|
||||||
|
-- This is important in the cases above because we want to kill the thread
|
||||||
|
-- that is holding the Handle lock, because when we clean up the process we
|
||||||
|
-- try to close that handle, which could otherwise deadlock.
|
||||||
|
--
|
||||||
|
withForkWait :: IO () -> (IO () -> IO a) -> IO a
|
||||||
|
withForkWait async' body = do
|
||||||
|
waitVar <- newEmptyMVar :: IO (MVar (Either SomeException ()))
|
||||||
|
mask $ \restore -> do
|
||||||
|
tid <- forkIO $ try (restore async') >>= putMVar waitVar
|
||||||
|
let wait' = takeMVar waitVar >>= either throwIO return
|
||||||
|
restore (body wait') `EX.onException` killThread tid
|
||||||
|
|
||||||
|
|
||||||
|
-- | Execute the given command and collect the stdout, stderr and the exit code.
|
||||||
|
-- The command is run in a subprocess.
|
||||||
|
executeOut :: MonadIO m
|
||||||
|
=> FilePath -- ^ command as filename, e.g. 'ls'
|
||||||
|
-> [String] -- ^ arguments to the command
|
||||||
|
-> Maybe FilePath -- ^ chdir to this path
|
||||||
|
-> m CapturedProcess
|
||||||
|
executeOut path args chdir = do
|
||||||
|
cp <- createProcessWithMingwPath ((proc path args){ cwd = chdir })
|
||||||
|
(exit, out, err) <- liftIO $ readCreateProcessWithExitCodeBS cp ""
|
||||||
|
pure $ CapturedProcess exit out err
|
||||||
|
|
||||||
|
|
||||||
|
execLogged :: ( MonadReader env m
|
||||||
|
, HasDirs env
|
||||||
|
, HasSettings env
|
||||||
|
, MonadIO m
|
||||||
|
, MonadThrow m)
|
||||||
|
=> FilePath -- ^ thing to execute
|
||||||
|
-> [String] -- ^ args for the thing
|
||||||
|
-> Maybe FilePath -- ^ optionally chdir into this
|
||||||
|
-> FilePath -- ^ log filename (opened in append mode)
|
||||||
|
-> Maybe [(String, String)] -- ^ optional environment
|
||||||
|
-> m (Either ProcessError ())
|
||||||
|
execLogged exe args chdir lfile env = do
|
||||||
|
Dirs {..} <- getDirs
|
||||||
|
let stdoutLogfile = logsDir </> lfile <> ".stdout.log"
|
||||||
|
stderrLogfile = logsDir </> lfile <> ".stderr.log"
|
||||||
|
cp <- createProcessWithMingwPath ((proc exe args)
|
||||||
|
{ cwd = chdir
|
||||||
|
, env = env
|
||||||
|
, std_in = CreatePipe
|
||||||
|
, std_out = CreatePipe
|
||||||
|
, std_err = CreatePipe
|
||||||
|
})
|
||||||
|
fmap (toProcessError exe args)
|
||||||
|
$ liftIO
|
||||||
|
$ withCreateProcess cp
|
||||||
|
$ \_ mout merr ph ->
|
||||||
|
case (mout, merr) of
|
||||||
|
(Just cStdout, Just cStderr) -> do
|
||||||
|
withForkWait (tee stdoutLogfile cStdout) $ \waitOut ->
|
||||||
|
withForkWait (tee stderrLogfile cStderr) $ \waitErr -> do
|
||||||
|
waitOut
|
||||||
|
waitErr
|
||||||
|
waitForProcess ph
|
||||||
|
_ -> fail "Could not acquire out/err handle"
|
||||||
|
|
||||||
|
where
|
||||||
|
tee :: FilePath -> Handle -> IO ()
|
||||||
|
tee logFile handle' = go
|
||||||
|
where
|
||||||
|
go = do
|
||||||
|
some <- BS.hGetSome handle' 512
|
||||||
|
if BS.null some
|
||||||
|
then pure ()
|
||||||
|
else do
|
||||||
|
void $ BS.appendFile logFile some
|
||||||
|
void $ BS.hPut stdout some
|
||||||
|
go
|
||||||
|
|
||||||
|
|
||||||
|
-- | Thin wrapper around `executeFile`.
|
||||||
|
exec :: MonadIO m
|
||||||
|
=> FilePath -- ^ thing to execute
|
||||||
|
-> [FilePath] -- ^ args for the thing
|
||||||
|
-> Maybe FilePath -- ^ optionally chdir into this
|
||||||
|
-> Maybe [(String, String)] -- ^ optional environment
|
||||||
|
-> m (Either ProcessError ())
|
||||||
|
exec exe args chdir env = do
|
||||||
|
cp <- createProcessWithMingwPath ((proc exe args) { cwd = chdir, env = env })
|
||||||
|
exit_code <- liftIO $ withCreateProcess cp $ \_ _ _ p -> waitForProcess p
|
||||||
|
pure $ toProcessError exe args exit_code
|
||||||
|
|
||||||
|
|
||||||
|
-- | Thin wrapper around `executeFile`.
|
||||||
|
execShell :: MonadIO m
|
||||||
|
=> FilePath -- ^ thing to execute
|
||||||
|
-> [FilePath] -- ^ args for the thing
|
||||||
|
-> Maybe FilePath -- ^ optionally chdir into this
|
||||||
|
-> Maybe [(String, String)] -- ^ optional environment
|
||||||
|
-> m (Either ProcessError ())
|
||||||
|
execShell exe args chdir env = do
|
||||||
|
let cmd = exe <> " " <> concatMap (' ':) args
|
||||||
|
cp <- createProcessWithMingwPath ((shell cmd) { cwd = chdir, env = env })
|
||||||
|
exit_code <- liftIO $ withCreateProcess cp $ \_ _ _ p -> waitForProcess p
|
||||||
|
pure $ toProcessError cmd [] exit_code
|
||||||
|
|
||||||
|
|
||||||
|
chmod_755 :: MonadIO m => FilePath -> m ()
|
||||||
|
chmod_755 fp =
|
||||||
|
let perm = setOwnerWritable True emptyPermissions
|
||||||
|
in liftIO $ setPermissions fp perm
|
||||||
|
|
||||||
|
|
||||||
|
createProcessWithMingwPath :: MonadIO m
|
||||||
|
=> CreateProcess
|
||||||
|
-> m CreateProcess
|
||||||
|
createProcessWithMingwPath cp = do
|
||||||
|
msys2Dir <- liftIO ghcupMsys2Dir
|
||||||
|
cEnv <- Map.fromList <$> maybe (liftIO getEnvironment) pure (env cp)
|
||||||
|
let mingWPaths = [msys2Dir </> "usr" </> "bin"
|
||||||
|
,msys2Dir </> "mingw64" </> "bin"]
|
||||||
|
paths = ["PATH", "Path"]
|
||||||
|
curPaths = (\x -> maybe [] splitSearchPath (Map.lookup x cEnv)) =<< paths
|
||||||
|
newPath = intercalate [searchPathSeparator] (mingWPaths ++ curPaths)
|
||||||
|
envWithoutPath = foldr (\x y -> Map.delete x y) cEnv paths
|
||||||
|
envWithNewPath = Map.insert "Path" newPath envWithoutPath
|
||||||
|
liftIO $ setEnv "Path" newPath
|
||||||
|
pure $ cp { env = Just $ Map.toList envWithNewPath }
|
||||||
|
|
||||||
|
ghcupMsys2Dir :: IO FilePath
|
||||||
|
ghcupMsys2Dir =
|
||||||
|
lookupEnv "GHCUP_MSYS2" >>= \case
|
||||||
|
Just fp -> pure fp
|
||||||
|
Nothing -> do
|
||||||
|
baseDir <- liftIO ghcupBaseDir
|
||||||
|
pure (baseDir </> "msys64")
|
||||||
|
|
||||||
|
-- | Checks whether the binary is a broken link.
|
||||||
|
isBrokenSymlink :: FilePath -> IO Bool
|
||||||
|
isBrokenSymlink fp = do
|
||||||
|
b <- pathIsLink fp
|
||||||
|
if b
|
||||||
|
then do
|
||||||
|
tfp <- getLinkTarget fp
|
||||||
|
not <$> doesPathExist
|
||||||
|
-- this drops 'symDir' if 'tfp' is absolute
|
||||||
|
(takeDirectory fp </> tfp)
|
||||||
|
else pure False
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
{-# LANGUAGE FlexibleContexts #-}
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
|
{-# LANGUAGE QuasiQuotes #-}
|
||||||
|
|
||||||
{-|
|
{-|
|
||||||
Module : GHCup.Utils.Logger
|
Module : GHCup.Utils.Logger
|
||||||
@@ -7,26 +8,31 @@ Copyright : (c) Julian Ospald, 2020
|
|||||||
License : LGPL-3.0
|
License : LGPL-3.0
|
||||||
Maintainer : hasufell@hasufell.de
|
Maintainer : hasufell@hasufell.de
|
||||||
Stability : experimental
|
Stability : experimental
|
||||||
Portability : POSIX
|
Portability : portable
|
||||||
|
|
||||||
Here we define our main logger.
|
Here we define our main logger.
|
||||||
-}
|
-}
|
||||||
module GHCup.Utils.Logger where
|
module GHCup.Utils.Logger where
|
||||||
|
|
||||||
import GHCup.Types
|
import GHCup.Types
|
||||||
import GHCup.Utils
|
import GHCup.Types.Optics
|
||||||
|
import GHCup.Utils.File
|
||||||
|
import GHCup.Utils.String.QQ
|
||||||
|
|
||||||
|
import Control.Exception.Safe
|
||||||
import Control.Monad
|
import Control.Monad
|
||||||
import Control.Monad.IO.Class
|
import Control.Monad.IO.Class
|
||||||
import Control.Monad.Reader
|
|
||||||
import Control.Monad.Logger
|
import Control.Monad.Logger
|
||||||
import HPath
|
import Control.Monad.Reader
|
||||||
import HPath.IO
|
import Data.Char ( ord )
|
||||||
import Prelude hiding ( appendFile )
|
import Prelude hiding ( appendFile )
|
||||||
import System.Console.Pretty
|
import System.Console.Pretty
|
||||||
|
import System.FilePath
|
||||||
import System.IO.Error
|
import System.IO.Error
|
||||||
|
import Text.Regex.Posix
|
||||||
|
|
||||||
import qualified Data.ByteString as B
|
import qualified Data.ByteString as B
|
||||||
|
import GHCup.Utils.Prelude
|
||||||
|
|
||||||
|
|
||||||
data LoggerConfig = LoggerConfig
|
data LoggerConfig = LoggerConfig
|
||||||
@@ -42,20 +48,33 @@ myLoggerT LoggerConfig {..} loggingt = runLoggingT loggingt mylogger
|
|||||||
mylogger :: Loc -> LogSource -> LogLevel -> LogStr -> IO ()
|
mylogger :: Loc -> LogSource -> LogLevel -> LogStr -> IO ()
|
||||||
mylogger _ _ level str' = do
|
mylogger _ _ level str' = do
|
||||||
-- color output
|
-- color output
|
||||||
|
let style' = case level of
|
||||||
|
LevelDebug -> style Bold . color Blue
|
||||||
|
LevelInfo -> style Bold . color Green
|
||||||
|
LevelWarn -> style Bold . color Yellow
|
||||||
|
LevelError -> style Bold . color Red
|
||||||
|
LevelOther _ -> id
|
||||||
let l = case level of
|
let l = case level of
|
||||||
LevelDebug -> toLogStr (style Bold $ color Blue "[ Debug ]")
|
LevelDebug -> toLogStr (style' "[ Debug ]")
|
||||||
LevelInfo -> toLogStr (style Bold $ color Green "[ Info ]")
|
LevelInfo -> toLogStr (style' "[ Info ]")
|
||||||
LevelWarn -> toLogStr (style Bold $ color Yellow "[ Warn ]")
|
LevelWarn -> toLogStr (style' "[ Warn ]")
|
||||||
LevelError -> toLogStr (style Bold $ color Red "[ Error ]")
|
LevelError -> toLogStr (style' "[ Error ]")
|
||||||
LevelOther t -> toLogStr "[ " <> toLogStr t <> toLogStr " ]"
|
LevelOther t -> toLogStr "[ " <> toLogStr t <> toLogStr " ]"
|
||||||
let out = fromLogStr (l <> toLogStr " " <> str' <> toLogStr "\n")
|
let strs = fmap toLogStr . B.split (fromIntegral $ ord '\n') . fromLogStr $ str'
|
||||||
|
let out = case strs of
|
||||||
|
[] -> B.empty
|
||||||
|
(x:xs) -> fromLogStr
|
||||||
|
. foldr (\a b -> a <> toLogStr "\n" <> b) mempty
|
||||||
|
. ((l <> toLogStr " " <> x) :)
|
||||||
|
. fmap (\line' -> toLogStr (style' "[ ... ] ") <> line' )
|
||||||
|
$ xs
|
||||||
|
|
||||||
when (lcPrintDebug || (not lcPrintDebug && (level /= LevelDebug)))
|
when (lcPrintDebug || (not lcPrintDebug && (level /= LevelDebug)))
|
||||||
$ colorOutter out
|
$ colorOutter out
|
||||||
|
|
||||||
-- raw output
|
-- raw output
|
||||||
let lr = case level of
|
let lr = case level of
|
||||||
LevelDebug -> toLogStr "Debug: "
|
LevelDebug -> toLogStr "Debug:"
|
||||||
LevelInfo -> toLogStr "Info:"
|
LevelInfo -> toLogStr "Info:"
|
||||||
LevelWarn -> toLogStr "Warn:"
|
LevelWarn -> toLogStr "Warn:"
|
||||||
LevelError -> toLogStr "Error:"
|
LevelError -> toLogStr "Error:"
|
||||||
@@ -64,12 +83,21 @@ myLoggerT LoggerConfig {..} loggingt = runLoggingT loggingt mylogger
|
|||||||
rawOutter outr
|
rawOutter outr
|
||||||
|
|
||||||
|
|
||||||
initGHCupFileLogging :: (MonadIO m, MonadReader AppState m) => Path Rel -> m (Path Abs)
|
initGHCupFileLogging :: ( MonadReader env m
|
||||||
initGHCupFileLogging context = do
|
, HasDirs env
|
||||||
AppState {dirs = Dirs {..}} <- ask
|
, MonadIO m
|
||||||
let logfile = logsDir </> context
|
, MonadMask m
|
||||||
liftIO $ do
|
) => m FilePath
|
||||||
createDirRecursive' logsDir
|
initGHCupFileLogging = do
|
||||||
hideError doesNotExistErrorType $ deleteFile logfile
|
Dirs { logsDir } <- getDirs
|
||||||
createRegularFile newFilePerms logfile
|
let logfile = logsDir </> "ghcup.log"
|
||||||
pure logfile
|
logFiles <- liftIO $ findFiles
|
||||||
|
logsDir
|
||||||
|
(makeRegexOpts compExtended
|
||||||
|
execBlank
|
||||||
|
([s|^.*\.log$|] :: B.ByteString)
|
||||||
|
)
|
||||||
|
forM_ logFiles $ hideError doesNotExistErrorType . recycleFile . (logsDir </>)
|
||||||
|
|
||||||
|
liftIO $ writeFile logfile ""
|
||||||
|
pure logfile
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ Copyright : (c) Julian Ospald, 2020
|
|||||||
License : LGPL-3.0
|
License : LGPL-3.0
|
||||||
Maintainer : hasufell@hasufell.de
|
Maintainer : hasufell@hasufell.de
|
||||||
Stability : experimental
|
Stability : experimental
|
||||||
Portability : POSIX
|
Portability : portable
|
||||||
-}
|
-}
|
||||||
module GHCup.Utils.MegaParsec where
|
module GHCup.Utils.MegaParsec where
|
||||||
|
|
||||||
@@ -23,6 +23,7 @@ import Data.Maybe
|
|||||||
import Data.Text ( Text )
|
import Data.Text ( Text )
|
||||||
import Data.Versions
|
import Data.Versions
|
||||||
import Data.Void
|
import Data.Void
|
||||||
|
import System.FilePath
|
||||||
|
|
||||||
import qualified Data.List.NonEmpty as NE
|
import qualified Data.List.NonEmpty as NE
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
@@ -67,6 +68,15 @@ ghcTargetBinP t =
|
|||||||
<*> (MP.chunk t <* MP.eof)
|
<*> (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.
|
-- | Extracts target triple and version from e.g.
|
||||||
-- * armv7-unknown-linux-gnueabihf-8.8.3
|
-- * armv7-unknown-linux-gnueabihf-8.8.3
|
||||||
-- * armv7-unknown-linux-gnueabihf-8.8.3
|
-- * armv7-unknown-linux-gnueabihf-8.8.3
|
||||||
@@ -108,3 +118,7 @@ verP suffix = do
|
|||||||
v <- versioning'
|
v <- versioning'
|
||||||
MP.setInput rest
|
MP.setInput rest
|
||||||
pure v
|
pure v
|
||||||
|
|
||||||
|
|
||||||
|
pathSep :: MP.Parsec Void Text Char
|
||||||
|
pathSep = MP.oneOf pathSeparators
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
{-# LANGUAGE CPP #-}
|
||||||
{-# LANGUAGE DataKinds #-}
|
{-# LANGUAGE DataKinds #-}
|
||||||
{-# LANGUAGE FlexibleContexts #-}
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
{-# LANGUAGE FlexibleInstances #-}
|
{-# LANGUAGE FlexibleInstances #-}
|
||||||
@@ -12,19 +13,26 @@ Copyright : (c) Julian Ospald, 2020
|
|||||||
License : LGPL-3.0
|
License : LGPL-3.0
|
||||||
Maintainer : hasufell@hasufell.de
|
Maintainer : hasufell@hasufell.de
|
||||||
Stability : experimental
|
Stability : experimental
|
||||||
Portability : POSIX
|
Portability : portable
|
||||||
|
|
||||||
GHCup specific prelude. Lots of Excepts functionality.
|
GHCup specific prelude. Lots of Excepts functionality.
|
||||||
-}
|
-}
|
||||||
module GHCup.Utils.Prelude where
|
module GHCup.Utils.Prelude where
|
||||||
|
|
||||||
|
#if defined(IS_WINDOWS)
|
||||||
|
import GHCup.Types
|
||||||
|
#endif
|
||||||
|
import GHCup.Types.Optics
|
||||||
|
|
||||||
import Control.Applicative
|
import Control.Applicative
|
||||||
import Control.Exception.Safe
|
import Control.Exception.Safe
|
||||||
import Control.Monad
|
import Control.Monad
|
||||||
import Control.Monad.IO.Class
|
import Control.Monad.IO.Class
|
||||||
import Control.Monad.Trans.Class ( lift )
|
import Control.Monad.Reader
|
||||||
import Data.Bifunctor
|
import Data.Bifunctor
|
||||||
import Data.ByteString ( ByteString )
|
import Data.ByteString ( ByteString )
|
||||||
|
import Data.List ( nub, intercalate )
|
||||||
|
import Data.Foldable
|
||||||
import Data.String
|
import Data.String
|
||||||
import Data.Text ( Text )
|
import Data.Text ( Text )
|
||||||
import Data.Versions
|
import Data.Versions
|
||||||
@@ -32,11 +40,22 @@ import Data.Word8
|
|||||||
import Haskus.Utils.Types.List
|
import Haskus.Utils.Types.List
|
||||||
import Haskus.Utils.Variant.Excepts
|
import Haskus.Utils.Variant.Excepts
|
||||||
import System.IO.Error
|
import System.IO.Error
|
||||||
import System.Posix.Env.ByteString ( getEnvironment )
|
#if defined(IS_WINDOWS)
|
||||||
|
import System.IO.Temp
|
||||||
|
#endif
|
||||||
|
import System.IO.Unsafe
|
||||||
|
import System.Directory
|
||||||
|
import System.FilePath
|
||||||
|
|
||||||
|
#if defined(IS_WINDOWS)
|
||||||
|
import Control.Retry
|
||||||
|
import GHC.IO.Exception
|
||||||
|
#endif
|
||||||
|
|
||||||
import qualified Data.ByteString as B
|
import qualified Data.ByteString as B
|
||||||
import qualified Data.ByteString.Lazy as L
|
import qualified Data.ByteString.Lazy as L
|
||||||
import qualified Data.Strict.Maybe as S
|
import qualified Data.Strict.Maybe as S
|
||||||
|
import qualified Data.List.Split as Split
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import qualified Data.Text.Encoding as E
|
import qualified Data.Text.Encoding as E
|
||||||
import qualified Data.Text.Encoding.Error as E
|
import qualified Data.Text.Encoding.Error as E
|
||||||
@@ -44,6 +63,9 @@ import qualified Data.Text.Lazy as TL
|
|||||||
import qualified Data.Text.Lazy.Builder as B
|
import qualified Data.Text.Lazy.Builder as B
|
||||||
import qualified Data.Text.Lazy.Builder.Int as B
|
import qualified Data.Text.Lazy.Builder.Int as B
|
||||||
import qualified Data.Text.Lazy.Encoding as TLE
|
import qualified Data.Text.Lazy.Encoding as TLE
|
||||||
|
#if defined(IS_WINDOWS)
|
||||||
|
import qualified System.Win32.File as Win32
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -180,14 +202,14 @@ hideError :: (MonadIO m, MonadCatch m) => IOErrorType -> m () -> m ()
|
|||||||
hideError err = handleIO (\e -> if err == ioeGetErrorType e then pure () else liftIO . ioError $ e)
|
hideError err = handleIO (\e -> if err == ioeGetErrorType e then pure () else liftIO . ioError $ e)
|
||||||
|
|
||||||
|
|
||||||
hideErrorDef :: [IOErrorType] -> a -> IO a -> IO a
|
hideErrorDef :: (MonadIO m, MonadCatch m) => [IOErrorType] -> a -> m a -> m a
|
||||||
hideErrorDef errs def =
|
hideErrorDef errs def =
|
||||||
handleIO (\e -> if ioeGetErrorType e `elem` errs then pure def else ioError e)
|
handleIO (\e -> if ioeGetErrorType e `elem` errs then pure def else liftIO $ ioError e)
|
||||||
|
|
||||||
|
|
||||||
hideErrorDefM :: [IOErrorType] -> IO a -> IO a -> IO a
|
hideErrorDefM :: (MonadIO m, MonadCatch m) => [IOErrorType] -> m a -> m a -> m a
|
||||||
hideErrorDefM errs def =
|
hideErrorDefM errs def =
|
||||||
handleIO (\e -> if ioeGetErrorType e `elem` errs then def else ioError e)
|
handleIO (\e -> if ioeGetErrorType e `elem` errs then def else liftIO $ ioError e)
|
||||||
|
|
||||||
|
|
||||||
-- TODO: does this work?
|
-- TODO: does this work?
|
||||||
@@ -242,6 +264,8 @@ throwEither' e eth = case eth of
|
|||||||
verToBS :: Version -> ByteString
|
verToBS :: Version -> ByteString
|
||||||
verToBS = E.encodeUtf8 . prettyVer
|
verToBS = E.encodeUtf8 . prettyVer
|
||||||
|
|
||||||
|
verToS :: Version -> String
|
||||||
|
verToS = T.unpack . prettyVer
|
||||||
|
|
||||||
intToText :: Integral a => a -> T.Text
|
intToText :: Integral a => a -> T.Text
|
||||||
intToText = TL.toStrict . B.toLazyText . B.decimal
|
intToText = TL.toStrict . B.toLazyText . B.decimal
|
||||||
@@ -252,14 +276,6 @@ removeLensFieldLabel str' =
|
|||||||
maybe str' T.unpack . T.stripPrefix (T.pack "_") . T.pack $ str'
|
maybe str' T.unpack . T.stripPrefix (T.pack "_") . T.pack $ str'
|
||||||
|
|
||||||
|
|
||||||
addToCurrentEnv :: MonadIO m
|
|
||||||
=> [(ByteString, ByteString)]
|
|
||||||
-> m [(ByteString, ByteString)]
|
|
||||||
addToCurrentEnv adds = do
|
|
||||||
cEnv <- liftIO getEnvironment
|
|
||||||
pure (adds ++ cEnv)
|
|
||||||
|
|
||||||
|
|
||||||
pvpToVersion :: PVP -> Version
|
pvpToVersion :: PVP -> Version
|
||||||
pvpToVersion =
|
pvpToVersion =
|
||||||
either (\_ -> error "Couldn't convert PVP to Version") id
|
either (\_ -> error "Couldn't convert PVP to Version") id
|
||||||
@@ -284,3 +300,238 @@ escapeVerRex = B.pack . go . B.unpack . verToBS
|
|||||||
go (x : xs) | x == _period = [_backslash, _period] ++ go xs
|
go (x : xs) | x == _period = [_backslash, _period] ++ go xs
|
||||||
| otherwise = x : 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 = do
|
||||||
|
#if defined(IS_WINDOWS)
|
||||||
|
Dirs { recycleDir } <- getDirs
|
||||||
|
tmp <- liftIO $ createTempDirectory recycleDir "recyclePathForcibly"
|
||||||
|
let dest = tmp </> takeFileName fp
|
||||||
|
liftIO (Win32.moveFileEx fp (Just dest) 0)
|
||||||
|
`catch`
|
||||||
|
(\e -> if isPermissionError e {- EXDEV on windows -} then recover (liftIO $ removePathForcibly fp) else throwIO e)
|
||||||
|
`finally`
|
||||||
|
(liftIO $ handleIO (\_ -> pure ()) $ removePathForcibly tmp)
|
||||||
|
#else
|
||||||
|
liftIO $ removePathForcibly fp
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
rmPathForcibly :: ( MonadIO m
|
||||||
|
, MonadMask m
|
||||||
|
)
|
||||||
|
=> FilePath
|
||||||
|
-> m ()
|
||||||
|
rmPathForcibly fp =
|
||||||
|
#if defined(IS_WINDOWS)
|
||||||
|
recover (liftIO $ removePathForcibly fp)
|
||||||
|
#else
|
||||||
|
liftIO $ removePathForcibly fp
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
rmDirectory :: (MonadIO m, MonadMask m)
|
||||||
|
=> FilePath
|
||||||
|
-> m ()
|
||||||
|
rmDirectory fp =
|
||||||
|
#if defined(IS_WINDOWS)
|
||||||
|
recover (liftIO $ removeDirectory fp)
|
||||||
|
#else
|
||||||
|
liftIO $ removeDirectory fp
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
-- https://www.sqlite.org/src/info/89f1848d7f
|
||||||
|
-- https://github.com/haskell/directory/issues/96
|
||||||
|
recycleFile :: ( MonadIO m
|
||||||
|
, MonadMask m
|
||||||
|
, MonadReader env m
|
||||||
|
, HasDirs env
|
||||||
|
)
|
||||||
|
=> FilePath
|
||||||
|
-> m ()
|
||||||
|
recycleFile fp = do
|
||||||
|
#if defined(IS_WINDOWS)
|
||||||
|
Dirs { recycleDir } <- getDirs
|
||||||
|
liftIO $ whenM (doesDirectoryExist fp) $ ioError (IOError Nothing InappropriateType "recycleFile" "" Nothing (Just fp))
|
||||||
|
tmp <- liftIO $ createTempDirectory recycleDir "recycleFile"
|
||||||
|
let dest = tmp </> takeFileName fp
|
||||||
|
liftIO (Win32.moveFileEx fp (Just dest) 0)
|
||||||
|
`catch`
|
||||||
|
(\e -> if isPermissionError e {- EXDEV on windows -} then recover (liftIO $ removePathForcibly fp) else throwIO e)
|
||||||
|
`finally`
|
||||||
|
(liftIO $ handleIO (\_ -> pure ()) $ removePathForcibly tmp)
|
||||||
|
#else
|
||||||
|
liftIO $ removeFile fp
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
rmFile :: ( MonadIO m
|
||||||
|
, MonadMask m
|
||||||
|
)
|
||||||
|
=> FilePath
|
||||||
|
-> m ()
|
||||||
|
rmFile fp =
|
||||||
|
#if defined(IS_WINDOWS)
|
||||||
|
recover (liftIO $ removeFile fp)
|
||||||
|
#else
|
||||||
|
liftIO $ removeFile fp
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
rmDirectoryLink :: (MonadIO m, MonadMask m, MonadReader env m, HasDirs env)
|
||||||
|
=> FilePath
|
||||||
|
-> m ()
|
||||||
|
rmDirectoryLink fp =
|
||||||
|
#if defined(IS_WINDOWS)
|
||||||
|
recover (liftIO $ removeDirectoryLink fp)
|
||||||
|
#else
|
||||||
|
liftIO $ removeDirectoryLink fp
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(IS_WINDOWS)
|
||||||
|
recover :: (MonadIO m, MonadMask m) => m a -> m a
|
||||||
|
recover action =
|
||||||
|
recovering (fullJitterBackoff 25000 <> limitRetries 10)
|
||||||
|
[\_ -> Handler (\e -> pure $ isPermissionError e)
|
||||||
|
,\_ -> Handler (\e -> pure (ioeGetErrorType e == InappropriateType))
|
||||||
|
,\_ -> Handler (\e -> pure (ioeGetErrorType e == UnsatisfiedConstraints))
|
||||||
|
]
|
||||||
|
(\_ -> action)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
-- Gathering monoidal values
|
||||||
|
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 'ByteString's
|
||||||
|
stripNewline :: String -> String
|
||||||
|
stripNewline s
|
||||||
|
| null s = []
|
||||||
|
| head s `elem` "\n\r" = stripNewline (tail s)
|
||||||
|
| otherwise = head s : stripNewline (tail s)
|
||||||
|
|
||||||
|
|
||||||
|
-- | Strip @\\r@ and @\\n@ from 'ByteString's
|
||||||
|
stripNewline' :: T.Text -> T.Text
|
||||||
|
stripNewline' s
|
||||||
|
| T.null s = mempty
|
||||||
|
| T.head s `elem` "\n\r" = stripNewline' (T.tail s)
|
||||||
|
| otherwise = T.singleton (T.head s) <> stripNewline' (T.tail s)
|
||||||
|
|
||||||
|
|
||||||
|
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, "")
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ Copyright : (c) Audrey Tang <audreyt@audreyt.org> 2019, Julian Ospald <hasufel
|
|||||||
License : LGPL-3.0
|
License : LGPL-3.0
|
||||||
Maintainer : hasufell@hasufell.de
|
Maintainer : hasufell@hasufell.de
|
||||||
Stability : experimental
|
Stability : experimental
|
||||||
Portability : POSIX
|
Portability : portable
|
||||||
|
|
||||||
QuasiQuoter for non-interpolated strings, texts and bytestrings.
|
QuasiQuoter for non-interpolated strings, texts and bytestrings.
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ Copyright : (c) Julian Ospald, 2020
|
|||||||
License : LGPL-3.0
|
License : LGPL-3.0
|
||||||
Maintainer : hasufell@hasufell.de
|
Maintainer : hasufell@hasufell.de
|
||||||
Stability : experimental
|
Stability : experimental
|
||||||
Portability : POSIX
|
Portability : portable
|
||||||
-}
|
-}
|
||||||
module GHCup.Utils.Version.QQ where
|
module GHCup.Utils.Version.QQ where
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ Copyright : (c) Julian Ospald, 2020
|
|||||||
License : LGPL-3.0
|
License : LGPL-3.0
|
||||||
Maintainer : hasufell@hasufell.de
|
Maintainer : hasufell@hasufell.de
|
||||||
Stability : experimental
|
Stability : experimental
|
||||||
Portability : POSIX
|
Portability : portable
|
||||||
-}
|
-}
|
||||||
module GHCup.Version where
|
module GHCup.Version where
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ import qualified Data.Text as T
|
|||||||
|
|
||||||
-- | This reflects the API version of the YAML.
|
-- | This reflects the API version of the YAML.
|
||||||
ghcupURL :: URI
|
ghcupURL :: URI
|
||||||
ghcupURL = [uri|https://www.haskell.org/ghcup/data/ghcup-0.0.4.yaml|]
|
ghcupURL = [uri|https://www.haskell.org/ghcup/data/ghcup-0.0.6.yaml|]
|
||||||
|
|
||||||
-- | The current ghcup version.
|
-- | The current ghcup version.
|
||||||
ghcUpVer :: PVP
|
ghcUpVer :: PVP
|
||||||
|
|||||||
27
refreeze.sh
Executable file
27
refreeze.sh
Executable file
@@ -0,0 +1,27 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -xue
|
||||||
|
|
||||||
|
rm -f cabal.*.project
|
||||||
|
rm -f cabal.*.project.freeze
|
||||||
|
|
||||||
|
for ghc_ver in "$@" ; do
|
||||||
|
# shellcheck disable=SC3060
|
||||||
|
project_file=cabal.ghc${ghc_ver//./}.project
|
||||||
|
|
||||||
|
cp cabal.project "${project_file}"
|
||||||
|
case "$(uname -s)" in
|
||||||
|
MSYS*|MINGW*)
|
||||||
|
cabal freeze --project-file="${project_file}" -w "ghc-${ghc_ver}"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
cabal freeze --project-file="${project_file}" -w "ghc-${ghc_ver}" -ftui -finternal-downloader
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
|
||||||
|
echo "" >> "${project_file}"
|
||||||
|
echo "with-compiler: ghc-${ghc_ver}" >> "${project_file}"
|
||||||
|
|
||||||
|
sed -i -e '/ghcup/d' "${project_file}".freeze
|
||||||
|
done
|
||||||
9
scoop-better-shimexe/LICENSE-MIT
Normal file
9
scoop-better-shimexe/LICENSE-MIT
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2019 Grégoire Geis
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
10
scoop-better-shimexe/LICENSE-UNLICENSE
Normal file
10
scoop-better-shimexe/LICENSE-UNLICENSE
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
This is free and unencumbered software released into the public domain.
|
||||||
|
|
||||||
|
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means.
|
||||||
|
|
||||||
|
In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and
|
||||||
|
successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
For more information, please refer to <http://unlicense.org/>
|
||||||
71
scoop-better-shimexe/README.md
Normal file
71
scoop-better-shimexe/README.md
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
# `shim.c`
|
||||||
|
|
||||||
|
[`shim.c`](./shim.c) is a simple Windows program that, when started:
|
||||||
|
1. Looks for a file with the exact same name as the running program, but with
|
||||||
|
the extension `shim` (e.g. `C:\bin\foo.exe` will read the file `C:\bin\foo.shim`).
|
||||||
|
2. Reads and [parses](#shim-format) the files into a
|
||||||
|
[Scoop](https://github.com/lukesampson/scoop) shim format.
|
||||||
|
3. Executes the target executable with the given arguments.
|
||||||
|
|
||||||
|
`shim.c` was originally made to replace [Scoop](https://github.com/lukesampson/scoop)'s
|
||||||
|
[`shim.cs`](https://github.com/lukesampson/scoop/blob/96de9c14bb483f9278e4b0a9e22b1923ee752901/supporting/shimexe/shim.cs)
|
||||||
|
since it had several important flaws:
|
||||||
|
1. [It was made in C#](https://github.com/lukesampson/scoop/tree/96de9c14bb483f9278e4b0a9e22b1923ee752901/supporting/shimexe),
|
||||||
|
and thus required an instantiation of a .NET command line app everytime it was started,
|
||||||
|
which can make a command run much slower than if it had been ran directly;
|
||||||
|
2. [It](https://github.com/lukesampson/scoop/issues/2339) [did](https://github.com/lukesampson/scoop/issues/1896)
|
||||||
|
[not](https://github.com/felixse/FluentTerminal/issues/221) handle Ctrl+C and other
|
||||||
|
signals correctly, which could be quite infuriating (and essentially killing REPLs and long-running apps).
|
||||||
|
|
||||||
|
[`shim.c`](./shim.c) is:
|
||||||
|
- **Faster**, because it does not use the .NET Framework, and parses the `.shim` file in a simpler way.
|
||||||
|
- **More efficient**, because by the time the target of the shim is started, all allocated memory will have been freed.
|
||||||
|
- And more importantly, it **works better**:
|
||||||
|
- Signals originating from pressing `Ctrl+C` are ignored, and therefore handled directly by the spawned child.
|
||||||
|
Your processes and REPLs will no longer close when pressing `Ctrl+C`.
|
||||||
|
- Children are automatically killed when the shim process is killed. No more orphaned processes and weird behaviors.
|
||||||
|
|
||||||
|
> **Note**: This project is not affiliated with [Scoop](https://github.com/lukesampson/scoop).
|
||||||
|
|
||||||
|
|
||||||
|
## Installation for Scoop
|
||||||
|
|
||||||
|
- In a Visual Studio command prompt, run `cl /O1 shim.c`.
|
||||||
|
- Replace any `.exe` in `scoop\shims` by `shim.exe`.
|
||||||
|
|
||||||
|
An additional script, `repshims.bat`, is provided. It will replace all `.exe`s in the user's Scoop directory
|
||||||
|
by `shim.exe`.
|
||||||
|
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
Given the following shim `gs.shim`:
|
||||||
|
```
|
||||||
|
path = C:\Program Files\Git\git.exe
|
||||||
|
args = status -u
|
||||||
|
```
|
||||||
|
|
||||||
|
In this directory, where `gs.exe` is the compiled `shim.c`:
|
||||||
|
```
|
||||||
|
C:\Bin\
|
||||||
|
gs.exe
|
||||||
|
gs.shim
|
||||||
|
```
|
||||||
|
|
||||||
|
Then calling `gs -s` will run the program `C:\Program Files\Git\git.exe status -u -s`.
|
||||||
|
|
||||||
|
|
||||||
|
## Shim format
|
||||||
|
|
||||||
|
Shims follow the same format as Scoop's shims: line-separated `key = value` pairs.
|
||||||
|
```
|
||||||
|
path = C:\Program Files\Git\git.exe
|
||||||
|
args = status -uno
|
||||||
|
```
|
||||||
|
|
||||||
|
`path` is a required value, but `args` can be omitted. Also, do note that lines **must** end with a line feed.
|
||||||
|
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
`SPDX-License-Identifier: MIT OR Unlicense`
|
||||||
15
scoop-better-shimexe/repshims.bat
Normal file
15
scoop-better-shimexe/repshims.bat
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
@echo off
|
||||||
|
|
||||||
|
if not defined SCOOP set SCOOP=%USERPROFILE%\scoop
|
||||||
|
|
||||||
|
for %%x in ("%SCOOP%\shims\*.exe") do (
|
||||||
|
echo Replacing %%x by new shim.
|
||||||
|
copy /B /Y shim.exe "%%~x" >NUL
|
||||||
|
)
|
||||||
|
|
||||||
|
if not defined SCOOP_GLOBAL set SCOOP_GLOBAL=%ProgramData%\scoop
|
||||||
|
|
||||||
|
for %%x in ("%SCOOP_GLOBAL%\shims\*.exe") do (
|
||||||
|
echo Replacing %%x by new shim.
|
||||||
|
copy /B /Y shim.exe "%%~x" >NUL
|
||||||
|
)
|
||||||
256
scoop-better-shimexe/shim.c
Normal file
256
scoop-better-shimexe/shim.c
Normal file
@@ -0,0 +1,256 @@
|
|||||||
|
#pragma comment(lib, "SHELL32.LIB")
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
|
#ifndef ERROR_ELEVATION_REQUIRED
|
||||||
|
# define ERROR_ELEVATION_REQUIRED 740
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define MAX_FILENAME_SIZE 512
|
||||||
|
|
||||||
|
BOOL WINAPI ctrlhandler(DWORD fdwCtrlType)
|
||||||
|
{
|
||||||
|
switch (fdwCtrlType) {
|
||||||
|
// Ignore all events, and let the child process
|
||||||
|
// handle them.
|
||||||
|
case CTRL_C_EVENT:
|
||||||
|
case CTRL_CLOSE_EVENT:
|
||||||
|
case CTRL_LOGOFF_EVENT:
|
||||||
|
case CTRL_BREAK_EVENT:
|
||||||
|
case CTRL_SHUTDOWN_EVENT:
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int compute_program_length(const wchar_t* commandline)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
if (commandline[0] == L'"') {
|
||||||
|
// Wait till end of string
|
||||||
|
i++;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
wchar_t c = commandline[i++];
|
||||||
|
|
||||||
|
if (c == 0)
|
||||||
|
return i - 1;
|
||||||
|
else if (c == L'\\')
|
||||||
|
i++;
|
||||||
|
else if (c == L'"')
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (;;) {
|
||||||
|
wchar_t c = commandline[i++];
|
||||||
|
|
||||||
|
if (c == 0)
|
||||||
|
return i - 1;
|
||||||
|
else if (c == L'\\')
|
||||||
|
i++;
|
||||||
|
else if (c == L' ')
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
DWORD exit_code = 0;
|
||||||
|
|
||||||
|
wchar_t* path = NULL;
|
||||||
|
wchar_t* args = NULL;
|
||||||
|
wchar_t* cmd = NULL;
|
||||||
|
|
||||||
|
// Find filename of current executable.
|
||||||
|
wchar_t filename[MAX_FILENAME_SIZE + 2];
|
||||||
|
const unsigned int filename_size = GetModuleFileNameW(NULL, filename, MAX_FILENAME_SIZE);
|
||||||
|
|
||||||
|
if (filename_size >= MAX_FILENAME_SIZE) {
|
||||||
|
fprintf(stderr, "The filename of the program is too long to handle.\n");
|
||||||
|
|
||||||
|
exit_code = 1;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use filename of current executable to find .shim
|
||||||
|
filename[filename_size - 3] = L's';
|
||||||
|
filename[filename_size - 2] = L'h';
|
||||||
|
filename[filename_size - 1] = L'i';
|
||||||
|
filename[filename_size - 0] = L'm';
|
||||||
|
filename[filename_size + 1] = 0 ;
|
||||||
|
|
||||||
|
FILE* shim_file;
|
||||||
|
|
||||||
|
if ((shim_file = _wfsopen(filename, L"r,ccs=UTF-8", _SH_DENYNO)) == NULL) {
|
||||||
|
fprintf(stderr, "Cannot open shim file for read.\n");
|
||||||
|
|
||||||
|
exit_code = 1;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t command_length = 256;
|
||||||
|
size_t path_length;
|
||||||
|
size_t args_length;
|
||||||
|
|
||||||
|
// Read shim
|
||||||
|
wchar_t linebuf[8192];
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
const wchar_t* line = fgetws(linebuf, 8192, shim_file);
|
||||||
|
|
||||||
|
if (line == NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (line[4] != L' ' || line[5] != L'=' || line[6] != L' ')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const int linelen = wcslen(line);
|
||||||
|
const int len = linelen - 8 + (line[linelen - 1] != '\n');
|
||||||
|
|
||||||
|
if (line[0] == L'p' && line[1] == L'a' && line[2] == L't' && line[3] == L'h') {
|
||||||
|
// Reading path
|
||||||
|
path = calloc(len + 1, sizeof(wchar_t));
|
||||||
|
wmemcpy(path, line + 7, len);
|
||||||
|
|
||||||
|
command_length += len;
|
||||||
|
path_length = len;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line[0] == L'a' && line[1] == L'r' && line[2] == L'g' && line[3] == L's') {
|
||||||
|
// Reading args
|
||||||
|
args = calloc(len + 1, sizeof(wchar_t));
|
||||||
|
wmemcpy(args, line + 7, len);
|
||||||
|
|
||||||
|
command_length += len + 1;
|
||||||
|
args_length = len;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(shim_file);
|
||||||
|
|
||||||
|
if (path == NULL) {
|
||||||
|
fprintf(stderr, "Could not read shim file.\n");
|
||||||
|
|
||||||
|
exit_code = 1;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find length of command to run
|
||||||
|
wchar_t* given_cmd = GetCommandLineW();
|
||||||
|
const int program_length = compute_program_length(given_cmd);
|
||||||
|
|
||||||
|
given_cmd += program_length;
|
||||||
|
|
||||||
|
const int given_length = wcslen(given_cmd);
|
||||||
|
|
||||||
|
command_length += given_length;
|
||||||
|
|
||||||
|
// Start building command to run, using '[path] [args]', as given by shim.
|
||||||
|
cmd = calloc(command_length, sizeof(wchar_t));
|
||||||
|
int cmd_i = 0;
|
||||||
|
|
||||||
|
wmemcpy(cmd, path, path_length);
|
||||||
|
cmd[path_length] = ' ';
|
||||||
|
cmd_i += path_length + 1;
|
||||||
|
|
||||||
|
if (args != NULL) {
|
||||||
|
wmemcpy(cmd + path_length + 1, args, args_length);
|
||||||
|
cmd[path_length + args_length + 1] = ' ';
|
||||||
|
cmd_i += args_length + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy all given arguments to command
|
||||||
|
wmemcpy(cmd + cmd_i, given_cmd, given_length);
|
||||||
|
|
||||||
|
// Find out if the target program is a console app
|
||||||
|
SHFILEINFOW sfi = {0};
|
||||||
|
const BOOL is_windows_app = HIWORD(SHGetFileInfoW(path, -1, &sfi, sizeof(sfi), SHGFI_EXETYPE));
|
||||||
|
|
||||||
|
if (is_windows_app)
|
||||||
|
// Unfortunately, this technique will still show a window for a fraction of time,
|
||||||
|
// but there's just no workaround.
|
||||||
|
FreeConsole();
|
||||||
|
|
||||||
|
// Create job object, which can be attached to child processes
|
||||||
|
// to make sure they terminate when the parent terminates as well.
|
||||||
|
JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = {0};
|
||||||
|
HANDLE jobHandle = CreateJobObject(NULL, NULL);
|
||||||
|
|
||||||
|
jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE | JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK;
|
||||||
|
SetInformationJobObject(jobHandle, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli));
|
||||||
|
|
||||||
|
// Start subprocess
|
||||||
|
STARTUPINFOW si = {0};
|
||||||
|
PROCESS_INFORMATION pi = {0};
|
||||||
|
|
||||||
|
if (CreateProcessW(NULL, cmd, NULL, NULL, TRUE, CREATE_SUSPENDED, NULL, NULL, &si, &pi)) {
|
||||||
|
AssignProcessToJobObject(jobHandle, pi.hProcess);
|
||||||
|
ResumeThread(pi.hThread);
|
||||||
|
} else {
|
||||||
|
if (GetLastError() == ERROR_ELEVATION_REQUIRED) {
|
||||||
|
// We must elevate the process, which is (basically) impossible with
|
||||||
|
// CreateProcess, and therefore we fallback to ShellExecuteEx,
|
||||||
|
// which CAN create elevated processes, at the cost of opening a new separate
|
||||||
|
// window.
|
||||||
|
// Theorically, this could be fixed (or rather, worked around) using pipes
|
||||||
|
// and IPC, but... this is a question for another day.
|
||||||
|
SHELLEXECUTEINFOW sei = {0};
|
||||||
|
|
||||||
|
sei.cbSize = sizeof(SHELLEXECUTEINFOW);
|
||||||
|
sei.fMask = SEE_MASK_NOCLOSEPROCESS;
|
||||||
|
sei.lpFile = path;
|
||||||
|
sei.lpParameters = cmd + path_length + 1;
|
||||||
|
sei.nShow = SW_SHOW;
|
||||||
|
|
||||||
|
if (!ShellExecuteExW(&sei)) {
|
||||||
|
fprintf(stderr, "Unable to create elevated process: error %li.", GetLastError());
|
||||||
|
|
||||||
|
exit_code = 1;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
pi.hProcess = sei.hProcess;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Could not create process with command '%ls'.\n", cmd);
|
||||||
|
|
||||||
|
exit_code = 1;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore Ctrl-C and other signals
|
||||||
|
if (!SetConsoleCtrlHandler(ctrlhandler, TRUE))
|
||||||
|
fprintf(stderr, "Could not set control handler; Ctrl-C behavior may be invalid.\n");
|
||||||
|
|
||||||
|
// Wait till end of process
|
||||||
|
WaitForSingleObject(pi.hProcess, INFINITE);
|
||||||
|
|
||||||
|
GetExitCodeProcess(pi.hProcess, &exit_code);
|
||||||
|
|
||||||
|
// Dispose of everything
|
||||||
|
CloseHandle(pi.hThread);
|
||||||
|
CloseHandle(pi.hProcess);
|
||||||
|
CloseHandle(jobHandle);
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
|
||||||
|
// Free obsolete buffers
|
||||||
|
free(path);
|
||||||
|
free(args);
|
||||||
|
free(cmd);
|
||||||
|
|
||||||
|
return (int)exit_code;
|
||||||
|
}
|
||||||
37
stack.yaml
37
stack.yaml
@@ -1,4 +1,4 @@
|
|||||||
resolver: lts-17.4
|
resolver: lts-18.2
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
- .
|
- .
|
||||||
@@ -7,8 +7,15 @@ extra-deps:
|
|||||||
- git: https://github.com/hasufell/text-conversions.git
|
- git: https://github.com/hasufell/text-conversions.git
|
||||||
commit: 9abf0e5e5664a3178367597c32db19880477a53c
|
commit: 9abf0e5e5664a3178367597c32db19880477a53c
|
||||||
|
|
||||||
|
- git: https://github.com/Bodigrim/tar
|
||||||
|
commit: ac197ec7ea4838dc2b4e22b9b888b080cedf29cf
|
||||||
|
|
||||||
|
- git: https://github.com/jtdaugherty/brick.git
|
||||||
|
commit: b3b96cfe66dfd398d338e3feb2b6855e66a35190
|
||||||
|
|
||||||
- IfElse-0.85@sha256:6939b94acc6a55f545f63a168a349dd2fbe4b9a7cca73bf60282db5cc6aa47d2,445
|
- IfElse-0.85@sha256:6939b94acc6a55f545f63a168a349dd2fbe4b9a7cca73bf60282db5cc6aa47d2,445
|
||||||
- ascii-string-1.0.1.4@sha256:fa34f1d9ba57e8e89c0d4c9cef5e01ba32cb2d4373d13f92dcc0b531a6c6749b,2582
|
- ascii-string-1.0.1.4@sha256:fa34f1d9ba57e8e89c0d4c9cef5e01ba32cb2d4373d13f92dcc0b531a6c6749b,2582
|
||||||
|
- base16-bytestring-0.1.1.7@sha256:0021256a9628971c08da95cb8f4d0d72192f3bb8a7b30b55c080562d17c43dd3,2231
|
||||||
- brotli-0.0.0.0@sha256:2bf383a4cd308745740986be0b18381c5a0784393fe69b91456aacb2d603de46,2964
|
- brotli-0.0.0.0@sha256:2bf383a4cd308745740986be0b18381c5a0784393fe69b91456aacb2d603de46,2964
|
||||||
- brotli-streams-0.0.0.0@sha256:1af1e22f67b8bfd6ad0d05e61825e7a178d738f689ebbb21c1aab5f1bbcae176,2331
|
- brotli-streams-0.0.0.0@sha256:1af1e22f67b8bfd6ad0d05e61825e7a178d738f689ebbb21c1aab5f1bbcae176,2331
|
||||||
- chs-cabal-0.1.1.0@sha256:20ec6a9fb5ab6991f1a4adf157c537bd5d3b98d08d3c09c387c954c7c50bd011,1153
|
- chs-cabal-0.1.1.0@sha256:20ec6a9fb5ab6991f1a4adf157c537bd5d3b98d08d3c09c387c954c7c50bd011,1153
|
||||||
@@ -17,21 +24,28 @@ extra-deps:
|
|||||||
- haskus-utils-data-1.3@sha256:f62c4e49021b463185d043f7b69c727b63af641a71d7edd582d9f4f98e80e500,1466
|
- haskus-utils-data-1.3@sha256:f62c4e49021b463185d043f7b69c727b63af641a71d7edd582d9f4f98e80e500,1466
|
||||||
- haskus-utils-types-1.5.1@sha256:991c472f4e751e2f0d7aab6ad4220ef151d6160876dcf0511bbf876bbd432020,1298
|
- haskus-utils-types-1.5.1@sha256:991c472f4e751e2f0d7aab6ad4220ef151d6160876dcf0511bbf876bbd432020,1298
|
||||||
- haskus-utils-variant-3.0@sha256:8d51e45d3b664e61ccc25a58b37c0ccc4ee7537138b9fee21cd15c356906dd34,2159
|
- haskus-utils-variant-3.0@sha256:8d51e45d3b664e61ccc25a58b37c0ccc4ee7537138b9fee21cd15c356906dd34,2159
|
||||||
- hpath-0.11.0@sha256:12b8405bee13d0007d644a888ef8407069ce7bbbd76970f8746b801447124ade,1440
|
|
||||||
- hpath-directory-0.14.1@sha256:548ac1321222c34caa843a41a2379a77d961141082a4695bb37cc4731e91b2c7,5312
|
|
||||||
- hpath-filepath-0.10.4@sha256:e9e44fb5fdbade7f30b5b5451257dbee15b6ef1aae4060034d73008bb3b5d878,1269
|
- hpath-filepath-0.10.4@sha256:e9e44fb5fdbade7f30b5b5451257dbee15b6ef1aae4060034d73008bb3b5d878,1269
|
||||||
- hpath-io-0.14.1@sha256:d91373cd81483eb370a1c683e4add6182250dccce32f9b682bb1104f7765c750,1522
|
- hpath-posix-0.13.3@sha256:abe472cf16bccd3a8b8814865ed3551a728fde0f3a2baea2acc03023bec6c565,1615
|
||||||
- hpath-posix-0.13.2@sha256:eec4ff2b00dc86be847aca0f409fc8f6212ffd2170ec36a17dc9a52b46562392,1615
|
- hspec-2.7.10@sha256:c9e82c90086acebac576552a06f3cabd249bba048edd1667c7fae0b1313d5bce,1712
|
||||||
|
- hspec-core-2.7.10@sha256:2aba6ea126442b29e8183ab27f1c811706b19b1d83b02f193a896f6fc1589d13,4621
|
||||||
|
- hspec-discover-2.7.10@sha256:d08bf5dd785629f589571477d9beb7cd91529471bd89f39517c1cb4b9b38160f,2184
|
||||||
|
- hspec-golden-aeson-0.9.0.0@sha256:aa17274114026661ba4dfc9c60c230673c8f408bd86482fd611d2d5cb6aff996,2179
|
||||||
- http-io-streams-0.1.6.0@sha256:53f5bab177efb52cd65ec396fd04ed59b93e5f919fb3700cd7dacd6cfce6f06d,3582
|
- http-io-streams-0.1.6.0@sha256:53f5bab177efb52cd65ec396fd04ed59b93e5f919fb3700cd7dacd6cfce6f06d,3582
|
||||||
- lzma-static-5.2.5.2@sha256:ac38dcad9ab423342a72ba48415bd75f62234e9c9e11831495b75603b5a060f6,7184
|
|
||||||
- libarchive-3.0.2.1@sha256:40ebf2a278e585802427bc58826867208bb33822f63d56107a1fcc3ca04d691d,10990
|
- libarchive-3.0.2.1@sha256:40ebf2a278e585802427bc58826867208bb33822f63d56107a1fcc3ca04d691d,10990
|
||||||
|
- lzma-static-5.2.5.3@sha256:2758ee58c35992fcf7db78e98684c357a16a82fa2a4e7c352a6c210c08c555d8,7308
|
||||||
- os-release-1.0.1@sha256:1281c62081f438fc3f0874d3bae6a4887d5964ac25261ba06e29d368ab173467,2716
|
- os-release-1.0.1@sha256:1281c62081f438fc3f0874d3bae6a4887d5964ac25261ba06e29d368ab173467,2716
|
||||||
- primitive-0.7.0.1@sha256:a381571c36edc7dca28b77fe8159b43c14c640087ec5946adacf949feec64231,3433
|
- optics-0.4@sha256:9fb69bf0195b8d8f1f8cd0098000946868b8a3c3ffb51e5b64f79fc600c3eb4c,6568
|
||||||
|
- optics-core-0.4@sha256:59e04aebca536bd011ae50c781937f45af4c1456af1eb9fb578f9a69eee293cd,4995
|
||||||
|
- optics-extra-0.4@sha256:b9914f38aa7d5c92f231060d9168447f9f5a367c07df9bf47a003e3e786d5e05,3432
|
||||||
|
- optics-th-0.4@sha256:7c838b5b1d6998133bf8f0641c36197ed6cb468dc69515e1952f33f0bbe8e11d,2009
|
||||||
|
- primitive-0.7.1.0@sha256:29de6bfd0cf8ba023ceb806203dfbec0e51e3524e75ffe41056f70b4229c6f0f,2728
|
||||||
|
- regex-posix-clib-2.7
|
||||||
- streamly-0.7.3@sha256:ad2a488fe802692ed47cab9fd0416c2904aac9e51cf2d8aafd1c3a40064c42f5,27421
|
- streamly-0.7.3@sha256:ad2a488fe802692ed47cab9fd0416c2904aac9e51cf2d8aafd1c3a40064c42f5,27421
|
||||||
- streamly-bytestring-0.1.2@sha256:cc828f41d1c714c711d38fb213b4ed186febabba598ab080e13255f69c20b13c,2469
|
- streamly-bytestring-0.1.2@sha256:cc828f41d1c714c711d38fb213b4ed186febabba598ab080e13255f69c20b13c,2469
|
||||||
- streamly-posix-0.1.0.1@sha256:5d89b806281035d34020387ed99dde1ddab282c7ed66df3b7cd010b38fd3517b,2138
|
- streamly-posix-0.1.0.1@sha256:5d89b806281035d34020387ed99dde1ddab282c7ed66df3b7cd010b38fd3517b,2138
|
||||||
- strict-base-0.4.0.0@sha256:2ff4e43cb95eedf2995558d7fc34d19362846413dd39e6aa6a5b3ea8228fef9f,1248
|
- strict-base-0.4.0.0@sha256:2ff4e43cb95eedf2995558d7fc34d19362846413dd39e6aa6a5b3ea8228fef9f,1248
|
||||||
- xor-0.0.1.0@sha256:f8362b4a68562b9afbcd727ff64c1a303970df3a032e0033d2f4c094c3501df3,2243
|
- xor-0.0.1.0@sha256:f8362b4a68562b9afbcd727ff64c1a303970df3a032e0033d2f4c094c3501df3,2243
|
||||||
|
- zip-1.7.1@sha256:0ce03d0fbffba47c1ab6fbb9166f8ba5373d828d78587df21b7e9d7bb150f929,3918
|
||||||
|
|
||||||
flags:
|
flags:
|
||||||
http-io-streams:
|
http-io-streams:
|
||||||
@@ -40,13 +54,8 @@ flags:
|
|||||||
libarchive:
|
libarchive:
|
||||||
system-libarchive: false
|
system-libarchive: false
|
||||||
|
|
||||||
ghcup:
|
regex-posix:
|
||||||
tui: true
|
_regex-posix-clib: true
|
||||||
internal-downloader: true
|
|
||||||
|
|
||||||
system-ghc: true
|
|
||||||
compiler: ghc-8.10.4
|
|
||||||
compiler-check: match-exact
|
|
||||||
|
|
||||||
ghc-options:
|
ghc-options:
|
||||||
"$locals": -O2
|
"$locals": -O2
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import GHCup.Types
|
|||||||
import Data.ByteString ( ByteString )
|
import Data.ByteString ( ByteString )
|
||||||
import Data.Versions
|
import Data.Versions
|
||||||
import Data.List.NonEmpty
|
import Data.List.NonEmpty
|
||||||
import HPath
|
|
||||||
import Test.QuickCheck
|
import Test.QuickCheck
|
||||||
import Test.QuickCheck.Arbitrary.ADT ( ToADTArbitrary )
|
import Test.QuickCheck.Arbitrary.ADT ( ToADTArbitrary )
|
||||||
import Test.QuickCheck.Arbitrary.Generic
|
import Test.QuickCheck.Arbitrary.Generic
|
||||||
@@ -164,11 +163,6 @@ instance Arbitrary VersionCmp where
|
|||||||
arbitrary = genericArbitrary
|
arbitrary = genericArbitrary
|
||||||
shrink = genericShrink
|
shrink = genericShrink
|
||||||
|
|
||||||
instance Arbitrary (Path Rel) where
|
|
||||||
arbitrary =
|
|
||||||
either (error . show) id . parseRel . E.encodeUtf8 . T.pack
|
|
||||||
<$> listOf1 (elements ['a' .. 'z'])
|
|
||||||
|
|
||||||
instance Arbitrary TarDir where
|
instance Arbitrary TarDir where
|
||||||
arbitrary = genericArbitrary
|
arbitrary = genericArbitrary
|
||||||
shrink = genericShrink
|
shrink = genericShrink
|
||||||
@@ -177,6 +171,10 @@ instance Arbitrary Tool where
|
|||||||
arbitrary = genericArbitrary
|
arbitrary = genericArbitrary
|
||||||
shrink = genericShrink
|
shrink = genericShrink
|
||||||
|
|
||||||
|
instance Arbitrary GlobalTool where
|
||||||
|
arbitrary = genericArbitrary
|
||||||
|
shrink = genericShrink
|
||||||
|
|
||||||
instance Arbitrary GHCupInfo where
|
instance Arbitrary GHCupInfo where
|
||||||
arbitrary = genericArbitrary
|
arbitrary = genericArbitrary
|
||||||
shrink = genericShrink
|
shrink = genericShrink
|
||||||
|
|||||||
@@ -132,13 +132,17 @@ hr {
|
|||||||
margin-bottom: 2em;
|
margin-bottom: 2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
#platform-instructions-linux > div > pre,
|
span.code {
|
||||||
#platform-instructions-mac > div > pre,
|
font-family: 'Lucida Console', monospace;
|
||||||
#platform-instructions-freebsd > div > pre,
|
}
|
||||||
#platform-instructions-win32 > div > pre,
|
|
||||||
#platform-instructions-win64 > div > pre,
|
#platform-instructions-linux div > pre,
|
||||||
#platform-instructions-default > div > div > pre,
|
#platform-instructions-mac div > pre,
|
||||||
#platform-instructions-unknown > div > div > pre {
|
#platform-instructions-freebsd div > pre,
|
||||||
|
#platform-instructions-win32 div > pre,
|
||||||
|
#platform-instructions-win64 div > pre,
|
||||||
|
#platform-instructions-default div > div > pre,
|
||||||
|
#platform-instructions-unknown div > div > pre {
|
||||||
background-color: #515151;
|
background-color: #515151;
|
||||||
color: white;
|
color: white;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
|
|||||||
@@ -158,8 +158,8 @@ function copyToClipboard() {
|
|||||||
document.body.removeChild(el);
|
document.body.removeChild(el);
|
||||||
}
|
}
|
||||||
|
|
||||||
function copyToClipboardSilicon() {
|
function copyToClipboardPowershell() {
|
||||||
const text = document.getElementById("ghcup-command-silicon").innerText;
|
const text = document.getElementById("ghcup-command-powershell").innerText;
|
||||||
const el = document.createElement('textarea');
|
const el = document.createElement('textarea');
|
||||||
el.value = text;
|
el.value = text;
|
||||||
document.body.appendChild(el);
|
document.body.appendChild(el);
|
||||||
|
|||||||
107
www/index.html
107
www/index.html
@@ -14,7 +14,6 @@
|
|||||||
|
|
||||||
<body id="idx">
|
<body id="idx">
|
||||||
|
|
||||||
<script id='html-content' type="text/html">
|
|
||||||
<a id="platform-button" style="display: none;" href="#">
|
<a id="platform-button" style="display: none;" href="#">
|
||||||
click or press "n" to cycle platforms
|
click or press "n" to cycle platforms
|
||||||
</a>
|
</a>
|
||||||
@@ -32,10 +31,7 @@
|
|||||||
|
|
||||||
<div id="platform-instructions-mac" class="instructions" style="display: none;">
|
<div id="platform-instructions-mac" class="instructions" style="display: none;">
|
||||||
<p>Run the following in your terminal (as a user other than root), then follow the onscreen instructions.</p>
|
<p>Run the following in your terminal (as a user other than root), then follow the onscreen instructions.</p>
|
||||||
<p>On Intel:</p>
|
|
||||||
<div class="command-button"><pre><span class='ghcup-command' id="ghcup-command-normal">curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh</span></pre><button class="tooltip" onclick="copyToClipboard()"><img src="copy.svg" alt="" /><span class="tooltiptext">Copy to clipboard</span></button></div>
|
<div class="command-button"><pre><span class='ghcup-command' id="ghcup-command-normal">curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh</span></pre><button class="tooltip" onclick="copyToClipboard()"><img src="copy.svg" alt="" /><span class="tooltiptext">Copy to clipboard</span></button></div>
|
||||||
<p>On Apple Silicon:</p>
|
|
||||||
<div class="command-button"><pre><span class='ghcup-command' id="ghcup-command-silicon">curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | arch -x86_64 /bin/bash</span></pre><button class="tooltip" onclick="copyToClipboardSilicon()"><img src="copy.svg" alt="" /><span class="tooltiptext">Copy to clipboard</span></button></div>
|
|
||||||
<p class="other-help">If you don't like curl | sh, see <a href="https://gitlab.haskell.org/haskell/ghcup-hs#manual-install">other installation methods</a>.<br/>You appear to be running macOS. If not, <a class="default-platform-button" href="#">display all supported installers</a>.</p>
|
<p class="other-help">If you don't like curl | sh, see <a href="https://gitlab.haskell.org/haskell/ghcup-hs#manual-install">other installation methods</a>.<br/>You appear to be running macOS. If not, <a class="default-platform-button" href="#">display all supported installers</a>.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -47,24 +43,41 @@
|
|||||||
|
|
||||||
<div id="platform-instructions-win32" class="instructions">
|
<div id="platform-instructions-win32" class="instructions">
|
||||||
<p>
|
<p>
|
||||||
To install Haskell, follow the instructions on
|
To install Haskell,<br/>run the following in a powershell session (as a non-admin user).
|
||||||
<a class="windows-download" href="https://www.haskell.org/platform/#windows">Haskell Platform</a>
|
<div>
|
||||||
<p>If you're a Windows Subsystem for Linux user run the following in your terminal, then follow the onscreen instructions to install Haskell.
|
<div class="command-button"><pre><span class='ghcup-command' id="ghcup-command-powershell">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></span></pre><button class="tooltip" onclick="copyToClipboardPowershell()"><img src="copy.svg" alt="" /><span class="tooltiptext">Copy to clipboard</span></button>
|
||||||
|
</div>
|
||||||
|
<p class="other-help">If you want to run a non-interactive installation, change <span class='code'>$true</span> to <span class='code'>$false</span> at the end of the script.</p>
|
||||||
|
</div>
|
||||||
|
<p>If you're a Windows Subsystem 2 for Linux user run the following in your terminal, then follow the onscreen instructions to install Haskell.
|
||||||
</p>
|
</p>
|
||||||
<div class="command-button"><pre><span class='ghcup-command'>curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh</span></pre><button class="tooltip" onclick="copyToClipboard()"><img src="copy.svg" alt="" /><span class="tooltiptext">Copy to clipboard</span></button></div>
|
<div>
|
||||||
|
<div class="command-button"><pre><span class='ghcup-command'>curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh</span></pre><button class="tooltip" onclick="copyToClipboard()"><img src="copy.svg" alt="" /><span class="tooltiptext">Copy to clipboard</span></button>
|
||||||
|
</div>
|
||||||
|
<p class="other-help">WSL1 does not work with ghcup, follow <a href="https://docs.microsoft.com/en-us/windows/wsl/install-win10">the instructions here</a> to upgrade to WSL2 if needed.</p>
|
||||||
|
</div>
|
||||||
</p>
|
</p>
|
||||||
<p class="other-help">You appear to be running Windows 32-bit. If not, <a class="default-platform-button" href="#">display all supported installers</a>.</p>
|
<hr/>
|
||||||
|
<p class="other-help">You appear to be running Windows 32-bit. If not, <a class="default-platform-button" href="#">display all supported installers</a>.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="platform-instructions-win64" class="instructions" style="display: none;">
|
<div id="platform-instructions-win64" class="instructions" style="display: none;">
|
||||||
<p>
|
<p>
|
||||||
To install Haskell, follow the instructions on
|
To install Haskell,<br/>run the following in a powershell session (as a non-admin user).
|
||||||
<a class="windows-download" href="https://www.haskell.org/platform/#windows">Haskell Platform</a>
|
<div>
|
||||||
|
<div class="command-button"><pre><span class='ghcup-command'>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></span></pre><button class="tooltip" onclick="copyToClipboardPowershell()"><img src="copy.svg" alt="" /><span class="tooltiptext">Copy to clipboard</span></button>
|
||||||
|
</div>
|
||||||
|
<p class="other-help">If you want to run an non-interactive installation, change <span class='code'>$true</span> to <span class='code'>$false</span> at the end of the script.</p>
|
||||||
|
</div>
|
||||||
</p>
|
</p>
|
||||||
<p>If you're a Windows Subsystem for Linux user run the following in your terminal, then follow the onscreen instructions to install Haskell.
|
<p>If you're a Windows Subsystem 2 for Linux user run the following in your terminal, then follow the onscreen instructions to install Haskell.
|
||||||
</p>
|
</p>
|
||||||
<div class="command-button"><pre><span class='ghcup-command'>curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh</span></pre><button class="tooltip" onclick="copyToClipboard()"><img src="copy.svg" alt="" /><span class="tooltiptext">Copy to clipboard</span></button></div>
|
<div>
|
||||||
<p class="other-help">You appear to be running Windows 64-bit. If not, <a class="default-platform-button" href="#">display all supported installers</a>.</p>
|
<div class="command-button"><pre><span class='ghcup-command'>curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh</span></pre><button class="tooltip" onclick="copyToClipboard()"><img src="copy.svg" alt="" /><span class="tooltiptext">Copy to clipboard</span></button>
|
||||||
|
</div>
|
||||||
|
<p class="other-help">WSL1 does not work with ghcup, follow <a href="https://docs.microsoft.com/en-us/windows/wsl/install-win10">the instructions here</a> to upgrade to WSL2 if needed.</p>
|
||||||
|
</div>
|
||||||
|
<p class="other-help">You appear to be running Windows 64-bit. If not, <a class="default-platform-button" href="#">display all supported installers</a>.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="platform-instructions-unknown" class="instructions" style="display: none;">
|
<div id="platform-instructions-unknown" class="instructions" style="display: none;">
|
||||||
@@ -86,7 +99,7 @@
|
|||||||
|
|
||||||
<!-- duplicate the default cross-platform instructions -->
|
<!-- duplicate the default cross-platform instructions -->
|
||||||
<div>
|
<div>
|
||||||
<p>If you are running Linux, macOS, FreeBSD or Windows Subsystem for Linux, run the following in your terminal (as a user other than root), then follow the onscreen instructions.</p>
|
<p>If you are running Linux, macOS, FreeBSD or Windows Subsystem 2 for Linux, run the following in your terminal (as a user other than root), then follow the onscreen instructions.</p>
|
||||||
<div class="command-button"><pre><span class='ghcup-command'>curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh</span></pre><button class="tooltip" onclick="copyToClipboard()"><img src="copy.svg" alt="" /><span class="tooltiptext">Copy to clipboard</span></button></div>
|
<div class="command-button"><pre><span class='ghcup-command'>curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh</span></pre><button class="tooltip" onclick="copyToClipboard()"><img src="copy.svg" alt="" /><span class="tooltiptext">Copy to clipboard</span></button></div>
|
||||||
<p class="other-help">If you don't like curl | sh, see <a href="https://gitlab.haskell.org/haskell/ghcup-hs#manual-install">other installation methods</a>.</p>
|
<p class="other-help">If you don't like curl | sh, see <a href="https://gitlab.haskell.org/haskell/ghcup-hs#manual-install">other installation methods</a>.</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -95,8 +108,8 @@
|
|||||||
|
|
||||||
<div>
|
<div>
|
||||||
<p>
|
<p>
|
||||||
If you are running Windows,<br/>follow the instructions on
|
If you are running Windows,<br/>run the following in a powershell session (as a non-admin user).
|
||||||
<a class="windows-download" href="https://www.haskell.org/platform/#windows">Haskell Platform</a>
|
<div class="command-button"><pre><span class='ghcup-command'>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</span></span></pre><button class="tooltip" onclick="copyToClipboardPowershell()"><img src="copy.svg" alt="" /><span class="tooltiptext">Copy to clipboard</span></button></div>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -104,11 +117,9 @@
|
|||||||
|
|
||||||
<div id="platform-instructions-default" class="instructions">
|
<div id="platform-instructions-default" class="instructions">
|
||||||
<div>
|
<div>
|
||||||
<p>To install Haskell, if you are running Linux, macOS (on Intel), FreeBSD or Windows Subsystem for Linux, run the following
|
<p>To install Haskell, if you are running Linux, macOS, FreeBSD or Windows Subsystem 2 for Linux, run the following
|
||||||
in your terminal (as a user other than root), then follow the onscreen instructions.</p>
|
in your terminal (as a user other than root), then follow the onscreen instructions.</p>
|
||||||
<div class="command-button"><pre><span class='ghcup-command'>curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh</span></pre><button class="tooltip" onclick="copyToClipboard()"><img src="copy.svg" alt="" /><span class="tooltiptext">Copy to clipboard</span></button></div>
|
<div class="command-button"><pre><span class='ghcup-command'>curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh</span></pre><button class="tooltip" onclick="copyToClipboard()"><img src="copy.svg" alt="" /><span class="tooltiptext">Copy to clipboard</span></button></div>
|
||||||
<p>For macOS on Apple Silicon, run this instead:</p>
|
|
||||||
<div class="command-button"><pre><span class='ghcup-command'>curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | arch -x86_64 /bin/bash</span></pre><button class="tooltip" onclick="copyToClipboardSilicon()"><img src="copy.svg" alt="" /><span class="tooltiptext">Copy to clipboard</span></button></div>
|
|
||||||
<p class="other-help">If you don't like curl | sh, see <a href="https://gitlab.haskell.org/haskell/ghcup-hs#manual-install">other installation methods</a>.</p>
|
<p class="other-help">If you don't like curl | sh, see <a href="https://gitlab.haskell.org/haskell/ghcup-hs#manual-install">other installation methods</a>.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -116,15 +127,18 @@
|
|||||||
|
|
||||||
<div>
|
<div>
|
||||||
<p>
|
<p>
|
||||||
If you are running Windows,<br/>follow the instructions on
|
If you are running Windows,<br/>run the following in a powershell session (as a non-admin user).
|
||||||
<a class="windows-download" href="https://www.haskell.org/platform/#windows">Haskell Platform</a>
|
<div class="command-button"><pre><span class='ghcup-command'>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></span></pre><button class="tooltip" onclick="copyToClipboardPowershell()"><img src="copy.svg" alt="" /><span class="tooltiptext">Copy to clipboard</span></button>
|
||||||
|
</div>
|
||||||
|
<p class="other-help">If you want to run a non-interactive installation, change <span class='code'>$true</span> to <span class='code'>$false</span> at the end of the script.</p>
|
||||||
|
</div>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Need help? <a href="http://webchat.freenode.net/?randomnick=1&channels=%23haskell&uio=d4">Ask on #haskell</a> or <a href="https://gitlab.haskell.org/haskell/ghcup-hs/issues">report a bug</a>.
|
Need help? Ask on <a href="https://kiwiirc.com/nextclient/irc.libera.chat/#haskell-ghcup">#haskell-ghcup</a>, <a href="https://kiwiirc.com/nextclient/irc.libera.chat/#haskell">#haskell</a> or <a href="https://gitlab.haskell.org/haskell/ghcup-hs/issues">report a bug</a>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p id="about">
|
<p id="about">
|
||||||
@@ -137,54 +151,7 @@
|
|||||||
·
|
·
|
||||||
<a href="https://github.com/rust-lang/rustup.rs/tree/master/www">web design from rustup</a>
|
<a href="https://github.com/rust-lang/rustup.rs/tree/master/www">web design from rustup</a>
|
||||||
</p>
|
</p>
|
||||||
</script>
|
|
||||||
<script>
|
|
||||||
document.write(document.getElementById("html-content").innerHTML);
|
|
||||||
</script>
|
|
||||||
<script type="text/javascript" src="ghcup.js"></script>
|
<script type="text/javascript" src="ghcup.js"></script>
|
||||||
|
|
||||||
<noscript>
|
|
||||||
<p id="pitch">
|
|
||||||
<em>ghcup</em> is an installer for<br/>
|
|
||||||
the general purpose language <a href="https://www.haskell.org/">Haskell</a>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div id="platform-instructions-default" class="instructions">
|
|
||||||
<div>
|
|
||||||
<p>To install Haskell, if you are running Linux, macOS (on Intel), FreeBSD or Windows Subsystem for Linux, run the following
|
|
||||||
in your terminal (as a user other than root), then follow the onscreen instructions.</p>
|
|
||||||
<pre><span class='ghcup-command'>curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh</span></pre>
|
|
||||||
<p>For macOS on Apple Silicon, run this instead:</p>
|
|
||||||
<div class="command-button"><pre><span class='ghcup-command'>curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | arch -x86_64 /bin/bash</span></pre><button class="tooltip" onclick="copyToClipboardSilicon()"><img src="copy.svg" alt="" /><span class="tooltiptext">Copy to clipboard</span></button></div>
|
|
||||||
<p class="other-help">If you don't like curl | sh, see <a href="https://gitlab.haskell.org/haskell/ghcup-hs#manual-install">other installation methods</a>.</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<hr/>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<p>
|
|
||||||
If you are running Windows,<br/>follow the instructions on
|
|
||||||
<a class="windows-download" href="https://www.haskell.org/platform/#windows">Haskell Platform</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Need help? <a href="http://webchat.freenode.net/?randomnick=1&channels=%23haskell&uio=d4">Ask on #haskell</a>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p id="about">
|
|
||||||
<img src="haskell-logo.svg" alt="" />
|
|
||||||
ghcup is a haskell.org hosted project.
|
|
||||||
<br/>
|
|
||||||
<a href="https://www.haskell.org/downloads/">other installation options</a>
|
|
||||||
·
|
|
||||||
<a href="https://gitlab.haskell.org/haskell/ghcup-hs">about ghcup</a>
|
|
||||||
·
|
|
||||||
<a href="https://github.com/rust-lang/rustup.rs/tree/master/www">web design from rustup</a>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</noscript>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user