detached c7b705a

Merge pull request #113 from bnema/feat/linux-arm64-prebuilt-binary

build: publish Linux ARM64 pre-built binary
commit
c7b705ac3fd2d361a83c9c6b8359fa86ea8ff936
author
bnema · · 2026-07-18 15:52 UTC
committer
GitHub · · 2026-07-18 15:52 UTC
merge of
b1b4f59 + 1d11e86 · diff against the first parent
signature
GPG UnverifiedB5690EEEBB952194 The key is unknown
8 files · +171 -11
M .github/workflows/ci.yml +10 -0
@@ -36,6 +36,16 @@ jobs:
3636 run: make lint
3737 - name: Test
3838 run: make test
39+ - name: Test installer
40+ if: matrix.os == 'ubuntu-latest'
41+ run: make test-installer
42+ - name: Cross-compile linux/arm64
43+ if: matrix.os == 'ubuntu-latest'
44+ env:
45+ CGO_ENABLED: 0
46+ GOARCH: arm64
47+ GOOS: linux
48+ run: go build ./...
3949 - name: Cross-compile darwin/arm64
4050 if: matrix.os == 'ubuntu-latest'
4151 env:
@@ -36,6 +36,16 @@ jobs:
36 run: make lint36 run: make lint
37 - name: Test37 - name: Test
38 run: make test38 run: make test
39+ - name: Test installer
40+ if: matrix.os == 'ubuntu-latest'
41+ run: make test-installer
42+ - name: Cross-compile linux/arm64
43+ if: matrix.os == 'ubuntu-latest'
44+ env:
45+ CGO_ENABLED: 0
46+ GOARCH: arm64
47+ GOOS: linux
48+ run: go build ./...
39 - name: Cross-compile darwin/arm6449 - name: Cross-compile darwin/arm64
40 if: matrix.os == 'ubuntu-latest'50 if: matrix.os == 'ubuntu-latest'
41 env:51 env:
M .goreleaser.yaml +2 -4
@@ -19,8 +19,6 @@ builds:
1919 - amd64
2020 - arm64
2121 ignore:
22- - goos: linux
23- goarch: arm64
2422 - goos: darwin
2523 goarch: amd64
2624 ldflags:
@@ -32,7 +30,7 @@ builds:
3230 archives:
3331 - id: default
3432 # Contract consumed by install.sh and the AUR package block:
35- # vev_linux_x86_64.tar.gz / vev_darwin_arm64.tar.gz
33+ # vev_linux_x86_64.tar.gz / vev_linux_arm64.tar.gz / vev_darwin_arm64.tar.gz
3634 name_template: >-
3735 {{ .ProjectName }}_{{ .Os }}_{{ if eq .Arch "amd64" }}x86_64{{ else }}{{ .Arch }}{{ end }}
3836 formats: ['tar.gz']
@@ -89,7 +87,7 @@ release:
8987
9088 ## Install
9189
92- ### Script (Linux x86_64, macOS arm64)
90+ ### Script (Linux x86_64/arm64, macOS arm64)
9391 ```sh
9492 curl -fsSL https://raw.githubusercontent.com/bnema/vev/{{ .Tag }}/install.sh | VEV_VERSION={{ .Tag }} sh
9593 ```
@@ -19,8 +19,6 @@ builds:
19 - amd6419 - amd64
20 - arm6420 - arm64
21 ignore:21 ignore:
22- - goos: linux
23- goarch: arm64
24 - goos: darwin22 - goos: darwin
25 goarch: amd6423 goarch: amd64
26 ldflags:24 ldflags:
@@ -32,7 +30,7 @@ builds:
32 archives:30 archives:
33 - id: default31 - id: default
34 # Contract consumed by install.sh and the AUR package block:32 # Contract consumed by install.sh and the AUR package block:
35- # vev_linux_x86_64.tar.gz / vev_darwin_arm64.tar.gz33+ # vev_linux_x86_64.tar.gz / vev_linux_arm64.tar.gz / vev_darwin_arm64.tar.gz
36 name_template: >-34 name_template: >-
37 {{ .ProjectName }}_{{ .Os }}_{{ if eq .Arch "amd64" }}x86_64{{ else }}{{ .Arch }}{{ end }}35 {{ .ProjectName }}_{{ .Os }}_{{ if eq .Arch "amd64" }}x86_64{{ else }}{{ .Arch }}{{ end }}
38 formats: ['tar.gz']36 formats: ['tar.gz']
@@ -89,7 +87,7 @@ release:
89 87
90 ## Install88 ## Install
91 89
92- ### Script (Linux x86_64, macOS arm64)90+ ### Script (Linux x86_64/arm64, macOS arm64)
93 ```sh91 ```sh
94 curl -fsSL https://raw.githubusercontent.com/bnema/vev/{{ .Tag }}/install.sh | VEV_VERSION={{ .Tag }} sh92 curl -fsSL https://raw.githubusercontent.com/bnema/vev/{{ .Tag }}/install.sh | VEV_VERSION={{ .Tag }} sh
95 ```93 ```
M Makefile +4 -1
@@ -1,4 +1,4 @@
1-.PHONY: install test lint mocks
1+.PHONY: install test test-installer lint mocks
22
33 install:
44 go install .
@@ -10,6 +10,9 @@ install:
1010 test:
1111 go test ./... -race
1212
13+test-installer:
14+ sh scripts/install_platform_test.sh
15+
1316 lint:
1417 @test -z "$$(goimports -l .)"
1518 go vet ./...
@@ -1,4 +1,4 @@
1-.PHONY: install test lint mocks1+.PHONY: install test test-installer lint mocks
2 2
3 install:3 install:
4 go install .4 go install .
@@ -10,6 +10,9 @@ install:
10 test:10 test:
11 go test ./... -race11 go test ./... -race
12 12
13+test-installer:
14+ sh scripts/install_platform_test.sh
15+
13 lint:16 lint:
14 @test -z "$$(goimports -l .)"17 @test -z "$$(goimports -l .)"
15 go vet ./...18 go vet ./...
M README.md +10 -2
@@ -7,7 +7,7 @@ A terminal multiplexer for Linux and macOS on Apple silicon (arm64). One Go bina
77 > [!WARNING]
88 > Alpha software. Expect breaking changes.
99
10-CI covers Ubuntu and macOS arm64. The release installer supports Linux x86_64 and macOS arm64.
10+Pre-built releases are available for Linux x86_64, Linux arm64, and macOS on Apple silicon (arm64). CI tests on Ubuntu x86_64 and macOS arm64; it also verifies cross-compilation for Linux arm64 and macOS arm64. Linux arm64 is not tested on native ARM hardware.
1111
1212 What it is built around:
1313
@@ -18,11 +18,19 @@ What it is built around:
1818
1919 ## Install
2020
21+Install a pre-built release on Linux x86_64/arm64 or macOS Apple silicon (arm64):
22+
23+```sh
24+curl -fsSL https://raw.githubusercontent.com/bnema/vev/main/install.sh | sh
25+```
26+
27+Alternatively, build and install the binary with Go:
28+
2129 ```sh
2230 go install github.com/bnema/vev@latest
2331 ```
2432
25-The default UI runs entirely from the `vev` binary. Optional external bar anchors can be configured in `~/.config/vev/config`.
33+The default UI runs entirely from the `vev` binary. The pre-built installer also installs optional external bar anchors, which only take effect when configured in `~/.config/vev/config`.
2634
2735 ## Usage
2836
@@ -7,7 +7,7 @@ A terminal multiplexer for Linux and macOS on Apple silicon (arm64). One Go bina
7 > [!WARNING]7 > [!WARNING]
8 > Alpha software. Expect breaking changes.8 > Alpha software. Expect breaking changes.
9 9
10-CI covers Ubuntu and macOS arm64. The release installer supports Linux x86_64 and macOS arm64.10+Pre-built releases are available for Linux x86_64, Linux arm64, and macOS on Apple silicon (arm64). CI tests on Ubuntu x86_64 and macOS arm64; it also verifies cross-compilation for Linux arm64 and macOS arm64. Linux arm64 is not tested on native ARM hardware.
11 11
12 What it is built around:12 What it is built around:
13 13
@@ -18,11 +18,19 @@ What it is built around:
18 18
19 ## Install19 ## Install
20 20
21+Install a pre-built release on Linux x86_64/arm64 or macOS Apple silicon (arm64):
22+
23+```sh
24+curl -fsSL https://raw.githubusercontent.com/bnema/vev/main/install.sh | sh
25+```
26+
27+Alternatively, build and install the binary with Go:
28+
21 ```sh29 ```sh
22 go install github.com/bnema/vev@latest30 go install github.com/bnema/vev@latest
23 ```31 ```
24 32
25-The default UI runs entirely from the `vev` binary. Optional external bar anchors can be configured in `~/.config/vev/config`.33+The default UI runs entirely from the `vev` binary. The pre-built installer also installs optional external bar anchors, which only take effect when configured in `~/.config/vev/config`.
26 34
27 ## Usage35 ## Usage
28 36
M cmd/vev-perf-harness/launcher.go +17 -0
@@ -628,6 +628,23 @@ func (e *ptyLocalEcho) applicationOutput(chunk []byte) []byte {
628628 func (p *cliProcess) Close() error {
629629 var result error
630630 p.closed.Do(func() {
631+ // No measurement waits for terminal chunks during teardown. Continue
632+ // consuming them so a full channel cannot block the client before it
633+ // receives the shell exit request and closes its transport receive span.
634+ if p.chunks != nil && p.done != nil {
635+ go func() {
636+ for {
637+ select {
638+ case _, ok := <-p.chunks:
639+ if !ok {
640+ return
641+ }
642+ case <-p.done:
643+ return
644+ }
645+ }
646+ }()
647+ }
631648 // A public terminal client owns a shell session. Ask that shell to exit
632649 // before closing the PTY so its transport can finish its receive span;
633650 // this avoids turning ordinary harness teardown into an aborted trace.
@@ -628,6 +628,23 @@ func (e *ptyLocalEcho) applicationOutput(chunk []byte) []byte {
628 func (p *cliProcess) Close() error {628 func (p *cliProcess) Close() error {
629 var result error629 var result error
630 p.closed.Do(func() {630 p.closed.Do(func() {
631+ // No measurement waits for terminal chunks during teardown. Continue
632+ // consuming them so a full channel cannot block the client before it
633+ // receives the shell exit request and closes its transport receive span.
634+ if p.chunks != nil && p.done != nil {
635+ go func() {
636+ for {
637+ select {
638+ case _, ok := <-p.chunks:
639+ if !ok {
640+ return
641+ }
642+ case <-p.done:
643+ return
644+ }
645+ }
646+ }()
647+ }
631 // A public terminal client owns a shell session. Ask that shell to exit648 // A public terminal client owns a shell session. Ask that shell to exit
632 // before closing the PTY so its transport can finish its receive span;649 // before closing the PTY so its transport can finish its receive span;
633 // this avoids turning ordinary harness teardown into an aborted trace.650 // this avoids turning ordinary harness teardown into an aborted trace.
M cmd/vev-perf-harness/launcher_test.go +50 -0
@@ -18,6 +18,56 @@ import (
1818 "github.com/bnema/vev/pkg/safedir"
1919 )
2020
21+type discardTerminalOutput struct{}
22+
23+func (discardTerminalOutput) Write(p []byte) (int, error) { return len(p), nil }
24+func (discardTerminalOutput) Sync() error { return nil }
25+func (discardTerminalOutput) Close() error { return nil }
26+
27+func TestCLIProcessCloseDrainsQueuedTerminalOutputBeforeClientExit(t *testing.T) {
28+ harnessPTY, clientPTY := net.Pipe()
29+ t.Cleanup(func() { _ = clientPTY.Close() })
30+ waitErr := make(chan error)
31+ secondRead := make(chan struct{})
32+ p := &cliProcess{
33+ pty: harnessPTY,
34+ output: discardTerminalOutput{},
35+ chunks: make(chan []byte, 1),
36+ done: make(chan struct{}),
37+ waitErr: waitErr,
38+ waitTimeout: func() <-chan time.Time { return time.After(time.Second) },
39+ }
40+ go p.copyTerminal()
41+ go func() {
42+ _, _ = clientPTY.Write([]byte("first"))
43+ _, _ = clientPTY.Write([]byte("second"))
44+ close(secondRead)
45+ buf := make([]byte, len("exit\n"))
46+ if _, err := clientPTY.Read(buf); err != nil {
47+ return
48+ }
49+ if _, err := clientPTY.Write([]byte("third")); err != nil {
50+ return
51+ }
52+ waitErr <- nil
53+ }()
54+ select {
55+ case <-secondRead:
56+ case <-time.After(time.Second):
57+ t.Fatal("terminal reader did not queue output")
58+ }
59+ closed := make(chan error, 1)
60+ go func() { closed <- p.Close() }()
61+ select {
62+ case err := <-closed:
63+ if err != nil {
64+ t.Fatal(err)
65+ }
66+ case <-time.After(time.Second):
67+ t.Fatal("Close did not drain queued terminal output before waiting for client exit")
68+ }
69+}
70+
2171 func TestCLIProcessCloseKeepsTerminalDrainActiveUntilClientExit(t *testing.T) {
2272 pty, err := os.CreateTemp(t.TempDir(), "pty")
2373 if err != nil {
@@ -18,6 +18,56 @@ import (
18 "github.com/bnema/vev/pkg/safedir"18 "github.com/bnema/vev/pkg/safedir"
19 )19 )
20 20
21+type discardTerminalOutput struct{}
22+
23+func (discardTerminalOutput) Write(p []byte) (int, error) { return len(p), nil }
24+func (discardTerminalOutput) Sync() error { return nil }
25+func (discardTerminalOutput) Close() error { return nil }
26+
27+func TestCLIProcessCloseDrainsQueuedTerminalOutputBeforeClientExit(t *testing.T) {
28+ harnessPTY, clientPTY := net.Pipe()
29+ t.Cleanup(func() { _ = clientPTY.Close() })
30+ waitErr := make(chan error)
31+ secondRead := make(chan struct{})
32+ p := &cliProcess{
33+ pty: harnessPTY,
34+ output: discardTerminalOutput{},
35+ chunks: make(chan []byte, 1),
36+ done: make(chan struct{}),
37+ waitErr: waitErr,
38+ waitTimeout: func() <-chan time.Time { return time.After(time.Second) },
39+ }
40+ go p.copyTerminal()
41+ go func() {
42+ _, _ = clientPTY.Write([]byte("first"))
43+ _, _ = clientPTY.Write([]byte("second"))
44+ close(secondRead)
45+ buf := make([]byte, len("exit\n"))
46+ if _, err := clientPTY.Read(buf); err != nil {
47+ return
48+ }
49+ if _, err := clientPTY.Write([]byte("third")); err != nil {
50+ return
51+ }
52+ waitErr <- nil
53+ }()
54+ select {
55+ case <-secondRead:
56+ case <-time.After(time.Second):
57+ t.Fatal("terminal reader did not queue output")
58+ }
59+ closed := make(chan error, 1)
60+ go func() { closed <- p.Close() }()
61+ select {
62+ case err := <-closed:
63+ if err != nil {
64+ t.Fatal(err)
65+ }
66+ case <-time.After(time.Second):
67+ t.Fatal("Close did not drain queued terminal output before waiting for client exit")
68+ }
69+}
70+
21 func TestCLIProcessCloseKeepsTerminalDrainActiveUntilClientExit(t *testing.T) {71 func TestCLIProcessCloseKeepsTerminalDrainActiveUntilClientExit(t *testing.T) {
22 pty, err := os.CreateTemp(t.TempDir(), "pty")72 pty, err := os.CreateTemp(t.TempDir(), "pty")
23 if err != nil {73 if err != nil {
M install.sh +5 -4
@@ -1,5 +1,5 @@
11 #!/bin/sh
2-# vev installer — Linux x86_64 and macOS arm64.
2+# vev installer — Linux x86_64/arm64 and macOS arm64.
33 # Usage: curl -fsSL https://raw.githubusercontent.com/bnema/vev/main/install.sh | sh
44 # Env: VEV_VERSION=vX.Y.Z to pin a version (default: latest release).
55 set -eu
@@ -14,9 +14,10 @@ err() { printf '\033[1;31merror:\033[0m %s\n' "$*" >&2; exit 1; }
1414 OS="$(uname -s | tr '[:upper:]' '[:lower:]')"
1515 ARCH="$(uname -m)"
1616 case "$OS/$ARCH" in
17- linux/x86_64|linux/amd64) TARBALL="vev_linux_x86_64.tar.gz" ;;
18- darwin/arm64) TARBALL="vev_darwin_arm64.tar.gz" ;;
19- *) err "unsupported platform: $OS/$ARCH (supported: linux/x86_64, darwin/arm64)" ;;
17+ linux/x86_64|linux/amd64) TARBALL="vev_linux_x86_64.tar.gz" ;;
18+ linux/aarch64|linux/arm64) TARBALL="vev_linux_arm64.tar.gz" ;;
19+ darwin/arm64) TARBALL="vev_darwin_arm64.tar.gz" ;;
20+ *) err "unsupported platform: $OS/$ARCH (supported: linux/x86_64, linux/arm64, darwin/arm64)" ;;
2021 esac
2122
2223 # --- Pick install dir ------------------------------------------------------
@@ -1,5 +1,5 @@
1 #!/bin/sh1 #!/bin/sh
2-# vev installer — Linux x86_64 and macOS arm64.2+# vev installer — Linux x86_64/arm64 and macOS arm64.
3 # Usage: curl -fsSL https://raw.githubusercontent.com/bnema/vev/main/install.sh | sh3 # Usage: curl -fsSL https://raw.githubusercontent.com/bnema/vev/main/install.sh | sh
4 # Env: VEV_VERSION=vX.Y.Z to pin a version (default: latest release).4 # Env: VEV_VERSION=vX.Y.Z to pin a version (default: latest release).
5 set -eu5 set -eu
@@ -14,9 +14,10 @@ err() { printf '\033[1;31merror:\033[0m %s\n' "$*" >&2; exit 1; }
14 OS="$(uname -s | tr '[:upper:]' '[:lower:]')"14 OS="$(uname -s | tr '[:upper:]' '[:lower:]')"
15 ARCH="$(uname -m)"15 ARCH="$(uname -m)"
16 case "$OS/$ARCH" in16 case "$OS/$ARCH" in
17- linux/x86_64|linux/amd64) TARBALL="vev_linux_x86_64.tar.gz" ;;17+ linux/x86_64|linux/amd64) TARBALL="vev_linux_x86_64.tar.gz" ;;
18- darwin/arm64) TARBALL="vev_darwin_arm64.tar.gz" ;;18+ linux/aarch64|linux/arm64) TARBALL="vev_linux_arm64.tar.gz" ;;
19- *) err "unsupported platform: $OS/$ARCH (supported: linux/x86_64, darwin/arm64)" ;;19+ darwin/arm64) TARBALL="vev_darwin_arm64.tar.gz" ;;
20+ *) err "unsupported platform: $OS/$ARCH (supported: linux/x86_64, linux/arm64, darwin/arm64)" ;;
20 esac21 esac
21 22
22 # --- Pick install dir ------------------------------------------------------23 # --- Pick install dir ------------------------------------------------------
A scripts/install_platform_test.sh +73 -0
@@ -0,0 +1,73 @@
1+#!/bin/sh
2+set -eu
3+
4+ROOT_DIR=$(CDPATH='' cd "$(dirname "$0")/.." && pwd)
5+TEST_DIR=$(mktemp -d)
6+trap 'rm -rf "$TEST_DIR"' EXIT HUP INT TERM
7+
8+FAKE_BIN="$TEST_DIR/bin"
9+mkdir -p "$FAKE_BIN"
10+
11+cat >"$FAKE_BIN/uname" <<'EOF'
12+#!/bin/sh
13+case "${1:-}" in
14+ -s) printf '%s\n' "$FAKE_OS" ;;
15+ -m) printf '%s\n' "$FAKE_ARCH" ;;
16+ *) exit 2 ;;
17+esac
18+EOF
19+
20+cat >"$FAKE_BIN/curl" <<'EOF'
21+#!/bin/sh
22+printf '%s\n' "$*" >>"$CURL_LOG"
23+exit 97
24+EOF
25+
26+chmod +x "$FAKE_BIN/uname" "$FAKE_BIN/curl"
27+
28+fail() {
29+ printf 'FAIL: %s\n' "$*" >&2
30+ exit 1
31+}
32+
33+assert_mapping() {
34+ os=$1
35+ arch=$2
36+ tarball=$3
37+ curl_log="$TEST_DIR/curl-$os-$arch.log"
38+ output="$TEST_DIR/output-$os-$arch.log"
39+
40+ if FAKE_OS=$os FAKE_ARCH=$arch CURL_LOG=$curl_log HOME="$TEST_DIR/home" \
41+ PATH="$FAKE_BIN:$PATH" VEV_VERSION=v0.0.0 \
42+ sh "$ROOT_DIR/install.sh" >"$output" 2>&1; then
43+ fail "$os/$arch unexpectedly completed installation"
44+ fi
45+
46+ expected_url="https://github.com/bnema/vev/releases/download/v0.0.0/$tarball"
47+ [ -f "$curl_log" ] || fail "$os/$arch did not attempt a download"
48+ grep -F "$expected_url" "$curl_log" >/dev/null \
49+ || fail "$os/$arch did not select $tarball"
50+ [ "$(wc -l <"$curl_log" | tr -d ' ')" = 1 ] \
51+ || fail "$os/$arch attempted more than the archive download"
52+}
53+
54+assert_mapping Linux x86_64 vev_linux_x86_64.tar.gz
55+assert_mapping Linux amd64 vev_linux_x86_64.tar.gz
56+assert_mapping Linux aarch64 vev_linux_arm64.tar.gz
57+assert_mapping Linux arm64 vev_linux_arm64.tar.gz
58+assert_mapping Darwin arm64 vev_darwin_arm64.tar.gz
59+
60+curl_log="$TEST_DIR/curl-Linux-armv7l.log"
61+output="$TEST_DIR/output-Linux-armv7l.log"
62+if FAKE_OS=Linux FAKE_ARCH=armv7l CURL_LOG=$curl_log HOME="$TEST_DIR/home" \
63+ PATH="$FAKE_BIN:$PATH" VEV_VERSION=v0.0.0 \
64+ sh "$ROOT_DIR/install.sh" >"$output" 2>&1; then
65+ fail "Linux/armv7l unexpectedly succeeded"
66+fi
67+grep -F "unsupported platform: linux/armv7l" "$output" >/dev/null \
68+ || fail "Linux/armv7l did not report an unsupported platform"
69+grep -F "supported: linux/x86_64, linux/arm64, darwin/arm64" "$output" >/dev/null \
70+ || fail "Linux/armv7l did not list the canonical supported platforms"
71+[ ! -e "$curl_log" ] || fail "Linux/armv7l invoked curl before rejection"
72+
73+printf 'installer platform tests passed\n'
@@ -0,0 +1,73 @@
1+#!/bin/sh
2+set -eu
3+
4+ROOT_DIR=$(CDPATH='' cd "$(dirname "$0")/.." && pwd)
5+TEST_DIR=$(mktemp -d)
6+trap 'rm -rf "$TEST_DIR"' EXIT HUP INT TERM
7+
8+FAKE_BIN="$TEST_DIR/bin"
9+mkdir -p "$FAKE_BIN"
10+
11+cat >"$FAKE_BIN/uname" <<'EOF'
12+#!/bin/sh
13+case "${1:-}" in
14+ -s) printf '%s\n' "$FAKE_OS" ;;
15+ -m) printf '%s\n' "$FAKE_ARCH" ;;
16+ *) exit 2 ;;
17+esac
18+EOF
19+
20+cat >"$FAKE_BIN/curl" <<'EOF'
21+#!/bin/sh
22+printf '%s\n' "$*" >>"$CURL_LOG"
23+exit 97
24+EOF
25+
26+chmod +x "$FAKE_BIN/uname" "$FAKE_BIN/curl"
27+
28+fail() {
29+ printf 'FAIL: %s\n' "$*" >&2
30+ exit 1
31+}
32+
33+assert_mapping() {
34+ os=$1
35+ arch=$2
36+ tarball=$3
37+ curl_log="$TEST_DIR/curl-$os-$arch.log"
38+ output="$TEST_DIR/output-$os-$arch.log"
39+
40+ if FAKE_OS=$os FAKE_ARCH=$arch CURL_LOG=$curl_log HOME="$TEST_DIR/home" \
41+ PATH="$FAKE_BIN:$PATH" VEV_VERSION=v0.0.0 \
42+ sh "$ROOT_DIR/install.sh" >"$output" 2>&1; then
43+ fail "$os/$arch unexpectedly completed installation"
44+ fi
45+
46+ expected_url="https://github.com/bnema/vev/releases/download/v0.0.0/$tarball"
47+ [ -f "$curl_log" ] || fail "$os/$arch did not attempt a download"
48+ grep -F "$expected_url" "$curl_log" >/dev/null \
49+ || fail "$os/$arch did not select $tarball"
50+ [ "$(wc -l <"$curl_log" | tr -d ' ')" = 1 ] \
51+ || fail "$os/$arch attempted more than the archive download"
52+}
53+
54+assert_mapping Linux x86_64 vev_linux_x86_64.tar.gz
55+assert_mapping Linux amd64 vev_linux_x86_64.tar.gz
56+assert_mapping Linux aarch64 vev_linux_arm64.tar.gz
57+assert_mapping Linux arm64 vev_linux_arm64.tar.gz
58+assert_mapping Darwin arm64 vev_darwin_arm64.tar.gz
59+
60+curl_log="$TEST_DIR/curl-Linux-armv7l.log"
61+output="$TEST_DIR/output-Linux-armv7l.log"
62+if FAKE_OS=Linux FAKE_ARCH=armv7l CURL_LOG=$curl_log HOME="$TEST_DIR/home" \
63+ PATH="$FAKE_BIN:$PATH" VEV_VERSION=v0.0.0 \
64+ sh "$ROOT_DIR/install.sh" >"$output" 2>&1; then
65+ fail "Linux/armv7l unexpectedly succeeded"
66+fi
67+grep -F "unsupported platform: linux/armv7l" "$output" >/dev/null \
68+ || fail "Linux/armv7l did not report an unsupported platform"
69+grep -F "supported: linux/x86_64, linux/arm64, darwin/arm64" "$output" >/dev/null \
70+ || fail "Linux/armv7l did not list the canonical supported platforms"
71+[ ! -e "$curl_log" ] || fail "Linux/armv7l invoked curl before rejection"
72+
73+printf 'installer platform tests passed\n'

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 2

Tags 13

↑↓ moveenter openesc close