Skip to content

Commit 7ef4a1a

Browse files
committed
Version bump, CI fixes
1 parent ef83bb3 commit 7ef4a1a

12 files changed

Lines changed: 191 additions & 36 deletions

File tree

.github/workflows/build-linux-arm64.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,15 @@ jobs:
2020
if_key_exists: replace
2121
- uses: actions/checkout@v3
2222
- run: echo "${HOME}/.local/bin" >> $GITHUB_PATH
23+
- name: Create cache directory
24+
run: mkdir -p ${{ github.workspace }}/user-build-cache/linux-arm64
25+
- name: Cache Cabal/Stack build artifacts
26+
uses: actions/cache@v4
27+
with:
28+
path: ${{ github.workspace }}/user-build-cache/linux-arm64
29+
key: linux-arm64-cabal-${{ hashFiles('cabal.project.freeze') }}
30+
restore-keys: |
31+
linux-arm64-cabal-
2332
- name: Install git submodules
2433
run: git submodule update --init --recursive
2534
- name: Run distribution script

.github/workflows/build-linux-x86_64.yml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ name: Build Linux x86_64
99
jobs:
1010
build:
1111
name: Build Linux x86_64
12-
runs-on: lamdera-community-linux-x86_64
12+
runs-on: ubuntu-latest
1313
steps:
1414
- name: Install SSH key
1515
uses: shimataro/ssh-key-action@v2
@@ -20,6 +20,15 @@ jobs:
2020
if_key_exists: replace
2121
- uses: actions/checkout@v3
2222
- run: echo "${HOME}/.local/bin" >> $GITHUB_PATH
23+
- name: Create cache directory
24+
run: mkdir -p ${{ github.workspace }}/user-build-cache/linux-x86_64
25+
- name: Cache Cabal/Stack build artifacts
26+
uses: actions/cache@v4
27+
with:
28+
path: ${{ github.workspace }}/user-build-cache/linux-x86_64
29+
key: linux-x86_64-cabal-${{ hashFiles('cabal.project.freeze') }}
30+
restore-keys: |
31+
linux-x86_64-cabal-
2332
- name: Run distribution script
2433
run: |
2534
cd distribution

.github/workflows/build-windows-x86_64.yml

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,12 @@ jobs:
9494
with:
9595
timeout_minutes: 5
9696
max_attempts: 4
97-
shell: bash # otherwise defaults to powershell on windows
97+
shell: bash
9898
# https://gitlab.haskell.org/ghc/ghc/-/issues/20878
9999
# https://gitlab.haskell.org/ghc/ghc/-/issues/20010#note_359766
100-
command: stack install --ghc-options '-optl"-Wl,-Bstatic,-lstdc++,-lgcc_s,-lwinpthread,-Bdynamic"'
100+
command: |
101+
export LANG=C.UTF-8
102+
stack install --ghc-options '-optl"-Wl,-Bstatic,-lstdc++,-lgcc_s,-lwinpthread,-Bdynamic"'
101103
102104
- name: Copy binary files, dlls & check
103105
run: |
@@ -114,18 +116,18 @@ jobs:
114116
dest: lamdera.zip
115117

116118
- name: Archive lamdera.zip artifact
117-
uses: actions/upload-artifact@v4
119+
uses: actions/upload-artifact@v6
118120
with:
119121
name: lamdera-next.zip
120122
path: lamdera.zip
121123

122124
upload:
123125
needs: install
124126
name: Upload lamdera-next.zip to SFTP
125-
runs-on: lamdera-community-linux-x86_64
127+
runs-on: ubuntu-latest
126128
steps:
127129
- name: Download artifacts
128-
uses: actions/download-artifact@v3
130+
uses: actions/download-artifact@v6
129131
with:
130132
name: lamdera-next.zip
131133

distribution/build-linux-arm64-musl.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ compilerRoot="$scriptDir/.."
1414

1515
if [ "$GITHUB_ACTIONS" == "true" ]; then
1616
mountRoot="$compilerRoot"
17-
cacheRoot="/home/github/user-build-cache/linux-arm64"
17+
cacheRoot="$GITHUB_WORKSPACE/user-build-cache/linux-arm64"
1818
rsyncCompilerPath=""
1919
dockerHost=""
2020
elif [ "$LOCAL_DOCKER" == "true" ]; then
@@ -58,6 +58,7 @@ build_binary_docker() {
5858
local groupId="$4"
5959
local compilerRoot="/root/compiler"
6060
cd $compilerRoot
61+
export GITHUB_ACTIONS=$actions
6162

6263
cleanup() {
6364
echo "trap cleanup: build failed with exit code $?"

distribution/build-linux-x86_64-musl.sh

Lines changed: 95 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,108 @@ arch="x86_64"
77

88
buildTag="lamdera-$version-$os-$arch"
99
dist=distribution/dist
10-
mkdir -p $dist
1110
bin=$dist/$buildTag
11+
1212
scriptDir=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
13+
compilerRoot="$scriptDir/.."
14+
15+
if [ "$GITHUB_ACTIONS" == "true" ]; then
16+
mountRoot="$compilerRoot"
17+
cacheRoot="$GITHUB_WORKSPACE/user-build-cache/linux-x86_64"
18+
dockerHost=""
19+
elif [ "$LOCAL_DOCKER" == "true" ]; then
20+
mountRoot="$compilerRoot"
21+
cacheRoot="$HOME/.docker/user-build-cache/linux-x86_64"
22+
dockerHost=""
23+
else
24+
mountRoot="$compilerRoot"
25+
cacheRoot="$HOME/.docker/user-build-cache/linux-x86_64"
26+
dockerHost=""
27+
fi
1328

14-
cd "$scriptDir/.." # Move into the project root
29+
cd "$compilerRoot" # Move into the project root
1530
git submodule init && git submodule update
1631

17-
# Build in Docker
32+
mkdir -p "$cacheRoot" || true
33+
34+
# GOAL: build the base image with GHC, Cabal, and system deps (this layer caches well)
1835
docker build --progress=plain --platform linux/amd64 \
19-
-t "$buildTag:latest" \
20-
-f distribution/docker/$arch-musl.dockerfile .
36+
-t "lamdera-x86_64-musl-base:latest" \
37+
-f distribution/docker/x86_64-musl-base.dockerfile .
38+
39+
40+
build_binary_docker() {
41+
set -ex
42+
local bin="$1"
43+
local actions="$2"
44+
local userId="$3"
45+
local groupId="$4"
46+
local compilerRoot="/root/compiler"
47+
cd $compilerRoot
48+
export GITHUB_ACTIONS=$actions
49+
50+
cleanup() {
51+
echo "trap cleanup: build failed with exit code $?"
52+
# Work around ownership issues that prevent GH actions from managing the files later
53+
[ "$actions" == "true" ] && chown -R "$userId:$groupId" ./* || true
54+
}
55+
trap cleanup EXIT
56+
57+
git config --global --add safe.directory /root/compiler
58+
59+
# GOAL: get the cabal caches into the mounted folder so they persist outside the Docker run lifetime and we don't needlessly rebuild hundreds of super expensive deps repeatedly forever
60+
# This is documented but doesn't seem to work https://cabal.readthedocs.io/en/3.6/installing-packages.html#environment-variables
61+
export CABAL_DIR=/root/cache/cabal
62+
export STACK_ROOT=/root/cache/stack
63+
export STACK_WORK=/root/cache/stack-work
64+
65+
mkdir -p /root/cache/cabal || true
66+
ln -sf /root/cache/cabal ~/.cabal
67+
68+
cabal update
2169

22-
mkdir -p distribution/dist # Ensure the dist directory is present
70+
# GOAL: pin our dependencies so we can build them one by one
71+
# We do this once outside of the build script, see distribution/sync-cabal-freeze.sh
72+
# We have to freeze the deps to get a cohesive deps set, otherwise `cabal build <dep>` will install the latest version instead of the one we need
73+
74+
# Our options required for static linking
75+
CABALOPTS="-f-export-dynamic -fembed_data_files --enable-executable-static -j4"
76+
GHCOPTS="-j4 +RTS -A256m -RTS -split-sections -optc-Os -optl=-pthread"
77+
78+
# GOAL: build non-elm/elm-format deps first to save time and cut out baseline issues
79+
# cabal build --dry-run | grep ' - ' | grep -v 'elm-' | grep -v 'avh4' | cut -d' ' -f3 | sed 's/-[^-]*$//' | xargs -I{} cabal build {} --only-dependencies $CABALOPTS --ghc-options="$GHCOPTS"
80+
cabal build --only-dependencies $CABALOPTS --ghc-options="$GHCOPTS"
81+
82+
# GOAL: build the Lamdera binary statically
83+
cabal build $CABALOPTS --ghc-options="$GHCOPTS" || true
84+
85+
# GOAL: catch silly cache failures that work on a second build
86+
GITHUB_ACTIONS=true cabal build $CABALOPTS --ghc-options="$GHCOPTS"
87+
88+
cp "$(cabal list-bin .)" "$bin"
89+
strip "$bin"
90+
91+
# Work around ownership issues that prevent GH actions from managing the files later
92+
[ "$actions" == "true" ] && chown -R "$userId:$groupId" ./* || true
93+
}
94+
declare -f build_binary_docker
95+
96+
# GOAL: get a suitable build environment with GHC & Cabal build for x86_64 in an Alpine container using MUSL instead of GLIBC, so we can build portable static binaries
97+
98+
# For manual testing drop a `bash` line wherever you'd like within build_binary_docker and re-run this script
99+
100+
mkdir -p $dist
23101

102+
[ "$GITHUB_ACTIONS" == "true" ] && runMode="--rm -i" || runMode="-it"
103+
docker $dockerHost run \
104+
--platform linux/amd64 \
105+
-v "$mountRoot:/root/compiler" \
106+
-v "$cacheRoot:/root/cache" \
107+
$runMode lamdera-x86_64-musl-base:latest \
108+
bash -c "$(declare -f build_binary_docker); build_binary_docker '$bin' '$GITHUB_ACTIONS' '$(id -u)' '$(id -g)'"
24109

25-
bin=distribution/dist/$buildTag # Copy built binary to dist
26-
docker run --rm --entrypoint cat $buildTag /lamdera/lamdera > $bin
27-
chmod a+x $bin
28-
file $bin
29-
ls -alh $bin
110+
ls -alh "$bin"
111+
chmod a+x "$bin"
112+
file "$bin"
113+
ls -alh "$bin"
30114
echo "put $bin next/lamdera-next-$os-$arch" | sftp -i ~/.ssh/id_ed25519 -P 22 github@apps.lamdera.com

distribution/common.sh

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
#!/usr/bin/env bash
22

3-
export version="1.2.2"
3+
# Parse version from the canonical source in Version.hs
4+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5+
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
6+
export version=$(grep -E '^raw = \(' "$REPO_ROOT/extra/Lamdera/Version.hs" | sed 's/raw = (\([0-9]*\),\([0-9]*\),\([0-9]*\))/\1.\2.\3/')
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
FROM alpine:3.15 AS build
2+
3+
RUN apk add --no-cache \
4+
bash \
5+
alpine-sdk \
6+
autoconf \
7+
gcc \
8+
gmp \
9+
gmp-dev \
10+
libffi \
11+
libffi-dev \
12+
llvm10 \
13+
make \
14+
musl-dev \
15+
ncurses-dev \
16+
ncurses-static \
17+
tree \
18+
wget \
19+
zlib-dev \
20+
zlib-static \
21+
curl
22+
23+
RUN curl https://downloads.haskell.org/~ghcup/0.1.19.5/x86_64-linux-ghcup-0.1.19.5 -o /usr/local/bin/ghcup && chmod a+x /usr/local/bin/ghcup
24+
25+
# Setup GHC
26+
RUN ghcup install ghc 9.2.8 --set
27+
RUN ghcup install cabal 3.10.1.0 --set
28+
29+
ENV PATH="${PATH}:/root/.ghcup/bin"
30+
31+
# FIX https://bugs.launchpad.net/ubuntu/+source/gcc-4.4/+bug/640734
32+
# Use the next line to debug the right file source if this area starts failing in future
33+
# RUN tree /usr/lib/gcc/x86_64-alpine-linux-musl
34+
# @TODO is there a sure-fire way of getting this path?
35+
WORKDIR /usr/lib/gcc/x86_64-alpine-linux-musl/10.3.1/
36+
RUN cp crtbeginT.o crtbeginT.o.orig
37+
RUN cp crtbeginS.o crtbeginT.o
38+
RUN cp crtend.o crtend.o.orig
39+
RUN cp crtendS.o crtend.o
40+
41+
WORKDIR /root/compiler

distribution/docker/x86_64-musl.dockerfile

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM alpine:3.15 as build
1+
FROM alpine:3.15 AS build
22

33
RUN apk add --no-cache \
44
alpine-sdk \
@@ -63,6 +63,10 @@ COPY ext-sentry ext-sentry
6363
COPY extra extra
6464
COPY test test
6565
COPY .git .git
66+
COPY vendor/elm-repl-worker vendor/elm-repl-worker
67+
68+
ARG GITHUB_ACTIONS
69+
ENV GITHUB_ACTIONS=${GITHUB_ACTIONS}
6670

6771
RUN cabal build $CABALOPTS --ghc-options="$GHCOPTS"
6872

extra/Lamdera.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ module Lamdera
9494
, withCompilerRoot
9595
, withRuntimeRoot
9696
, Ext.Common.setProjectRoot
97+
, Ext.Common.withProjectRoot
9798
, Ext.Common.getProjectRoot
9899
, Ext.Common.getProjectRootFor
99100
, Ext.Common.getProjectRootMaybe

extra/Lamdera/Repl.hs

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -56,58 +56,58 @@ lamderaReplSrc = $(do
5656
let mainPaths = NE.singleton "src/Repl/Worker.elm"
5757

5858
compilerResult <- TH.runIO $ do
59-
putStr "🚀 Compiling `src/Repl/Worker.elm` in `vendor/elm-repl-worker`..."
59+
putStr "-- Compiling `src/Repl/Worker.elm` in `vendor/elm-repl-worker`..."
6060
BW.withScope $ \scope -> do
6161
Dir.withCurrentDirectory ("vendor" </> "elm-repl-worker") $ do
6262
root <- Dir.getCurrentDirectory
63-
Lamdera.setProjectRoot root
64-
Task.run $ do
65-
details <- Task.eio (const "details") $ Details.load Reporting.silent scope root
66-
artifacts <- Task.eio (const "build") $ Build.fromPaths Reporting.silent root details mainPaths
67-
javascript <- Task.mapError (const "generate") $ Generate.dev root details artifacts
68-
return $ LBS.toStrict (B.toLazyByteString javascript)
63+
Lamdera.withProjectRoot root $ do
64+
Task.run $ do
65+
details <- Task.eio (const "details") $ Details.load Reporting.silent scope root
66+
artifacts <- Task.eio (const "build") $ Build.fromPaths Reporting.silent root details mainPaths
67+
javascript <- Task.mapError (const "generate") $ Generate.dev root details artifacts
68+
return $ LBS.toStrict (B.toLazyByteString javascript)
6969

7070
compiledCode <-
7171
case compilerResult of
7272
Right compiledCode_ -> do
73-
TH.runIO $ putStrLn " "
73+
TH.runIO $ putStrLn " OK"
7474
return compiledCode_
7575
Left err ->
7676
error $
77-
"\n❌ Error in Lamdera.Repl.lamderaRepl during the compiler " ++ err ++ " phase.\
77+
"\nError in Lamdera.Repl.lamderaRepl during the compiler " ++ err ++ " phase.\
7878
\\n Try running `lamdera make src/Repl/Worker.elm` directly."
7979

8080
minifiedCode <- TH.runIO $ do
8181
isGithubActions <- Lamdera.lookupEnv "GITHUB_ACTIONS"
8282
case isGithubActions of
8383
Just "true" -> do
84-
putStr "🚀 Loading pre-built `repl-worker.js` from `extra/dist`..."
84+
putStr "-- Loading pre-built `repl-worker.js` from `extra/dist`..."
8585
let distFile = "extra" </> "dist" </> "repl-worker.js"
8686
exists <- Dir.doesFileExist distFile
8787
if exists
8888
then do
89-
putStrLn " "
89+
putStrLn " OK"
9090
BS.readFile distFile
9191
else
9292
error
93-
"\n❌ Error in Lamdera.Repl.lamderaRepl: pre-built repl-worker.js not found.\
93+
"\nError in Lamdera.Repl.lamderaRepl: pre-built repl-worker.js not found.\
9494
\\n Expected file at: extra/dist/repl-worker.js\
9595
\\n Run `stack install` locally to build and commit to the repository."
9696
_ -> do
97-
putStr "🚀 Minifying `repl-worker.js` in `extra`..."
97+
putStr "-- Minifying `repl-worker.js` in `extra`..."
9898
Ext.Common.requireBinary "esbuild"
9999
BS.writeFile ("extra" </> "repl-worker.js") compiledCode
100100
Ext.Common.bash $ "cd extra && esbuild repl-worker.js --minify --target=chrome58,firefox57,safari11,edge16 > " ++ ("dist" </> "repl-worker.js")
101101
minifierResult <- Dir.doesFileExist ("extra" </> "dist" </> "repl-worker.js")
102102
if minifierResult
103103
then do
104-
putStrLn " "
104+
putStrLn " OK"
105105
minifiedCode_ <- BS.readFile ("extra" </> "dist" </> "repl-worker.js")
106106
Dir.removeFile ("extra" </> "repl-worker.js")
107107
return minifiedCode_
108108
else
109109
error
110-
"\n❌ Error in Lamdera.Repl.lamderaRepl during minification.\
110+
"\nError in Lamdera.Repl.lamderaRepl during minification.\
111111
\\n Try running `esbuild repl-worker.js --minify` directly."
112112

113113
Data.FileEmbed.bsToExp minifiedCode)

0 commit comments

Comments
 (0)