Repository navigation
217 lines (197 loc) · 8.87 KB
/
Copy path32bit.yml
File metadata and controls
217 lines (197 loc) · 8.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
# 32-bit test: build and test borg on armv7 (32-bit) under qemu user-mode
# emulation, and check that a repository written on a 32-bit machine can be
# read on a 64-bit one and the other way round.
#
# Why: all our other CI machines are 64-bit, so nothing ever exercises borg on a
# platform where a pointer, size_t, Py_ssize_t and off_t are 32 bits wide - a
# size computation that overflows there, a struct/msgpack format that assumes a
# 64-bit word or an mmap that a 32-bit address space can not satisfy would only
# be found by our users on such machines.
#
# Why armv7: 32-bit x86 desktops are basically gone, but 32-bit ARM is not - it
# is what borg users on older Raspberry Pis (Pi 1/2/3, Zero) and on quite some
# NAS / router / embedded boxes are running. It also has two properties x86 does
# not have: it does not tolerate unaligned memory accesses everywhere, and plain
# "char" is unsigned on ARM (it is signed on x86), which is a classic source of
# portability bugs in C code. GitHub's arm64 runners can not execute 32-bit ARM
# code natively, so this has to be emulated regardless.
#
# Why trixie: borg needs OpenSSL >= 3.2, so debian bookworm and its OpenSSL 3.0
# are out - trixie has OpenSSL 3.5 (and python 3.13) for armhf.
#
# Everything inside the container is emulated instruction by instruction, so
# this is slow. Therefore it does not run for every pull request, but only when
# native code or format relevant code was touched (plus weekly and on demand).
name: 32-bit
on:
pull_request:
branches: [ master ]
paths:
- '**.pyx'
- '**.pxd'
- 'src/borg/**/*.c'
- 'src/borg/**/*.h'
- 'src/borg/chunkers/**'
- 'src/borg/crypto/**'
- 'src/borg/repository.py'
- 'src/borg/repoobj.py'
- 'src/borg/archive.py'
- 'src/borg/cache.py'
- 'scripts/endian_interop_test.py'
- '.github/workflows/32bit.yml'
schedule:
- cron: '43 6 * * 3' # Wednesdays at 06:43 UTC
workflow_dispatch: # Allow manual trigger
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
permissions:
contents: read
env:
PY_COLORS: "1"
jobs:
armv7:
name: armv7 (32-bit, emulated)
runs-on: ubuntu-26.04
timeout-minutes: 120
env:
# Debian trixie has python 3.13. Fewer of our dependencies ship armv7l
# wheels than s390x ones (blake3 does, the rest is pure python or is
# compiled from source, emulated), so the first, uncached run is slow.
IMAGE: docker.io/arm32v7/debian:trixie-slim
CONTAINER: borg-armv7
# both sides of the interoperability test share this directory:
INTEROP: ${{ github.workspace }}/.interop
# a hung emulated test must fail instead of eating the job timeout:
PYTEST_TIMEOUT: "600"
# The word size sensitive parts: the native code (chunkers, crypto,
# compression, hashindex, item) and the code that reads/writes the
# repository format and computes sizes and offsets. Extend this if
# it turns out to be too narrow.
PYTEST_TARGETS: >-
borg.testsuite.chunkers
borg.testsuite.crypto
borg.testsuite.compress_test
borg.testsuite.hashindex_test
borg.testsuite.item_test
borg.testsuite.repoobj_test
borg.testsuite.repository_test
borg.testsuite.archive_test
borg.testsuite.cache_test
borg.testsuite.digests_test
borg.testsuite.helpers.msgpack_test
borg.testsuite.helpers.time_test
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
# Just fetching one commit is not enough for setuptools-scm, so we fetch all.
fetch-depth: 0
fetch-tags: true
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
# same python version as in the container, so both sides are comparable
python-version: '3.13'
# The wheels pip has to build from source inside the emulated container
# (msgpack, PyYAML, backports-zstd, borghash, borgstore) are the expensive
# part of the container setup, so keep them from run to run.
- name: Cache pip-built wheels (armv7)
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: .pip-cache-armv7
key: armv7-pip-${{ hashFiles('pyproject.toml') }}
restore-keys: |
armv7-pip-
- name: Install Linux packages
run: |
sudo apt-get update
sudo apt-get install -y pkg-config build-essential
sudo apt-get install -y libssl-dev libacl1-dev liblz4-dev
- name: Build borg (native, 64-bit)
run: |
set -euxo pipefail
# Note: a non-editable install on purpose - the armv7 build below uses
# the same source tree and an editable install would put the extension
# modules of one architecture in there for the other one to pick up.
python -m venv "$RUNNER_TEMP/venv-native"
"$RUNNER_TEMP/venv-native/bin/pip" install --upgrade pip wheel
# Note: no pytest and no other development dependencies in this venv on
# purpose - this is what a normal borg installation looks like.
"$RUNNER_TEMP/venv-native/bin/pip" install .
"$RUNNER_TEMP/venv-native/bin/borg" --version
"$RUNNER_TEMP/venv-native/bin/python" -c 'import sys; assert sys.maxsize == 2**63 - 1, sys.maxsize'
# the container has no git, so tell setuptools-scm the version we got here:
echo "BORG_VERSION=$("$RUNNER_TEMP/venv-native/bin/borg" --version | cut -d' ' -f2)" >> $GITHUB_ENV
- name: Set up QEMU
uses: docker/setup-qemu-action@99012661954931238ded8c8b007157a8430204e1 # v4.4.0
with:
platforms: arm
- name: Start the armv7 container
run: |
set -euxo pipefail
mkdir -p .pip-cache-armv7
docker run -d --name "$CONTAINER" --platform linux/arm/v7 \
-v "${{ github.workspace }}:/borg" -w /borg \
-e PIP_CACHE_DIR=/borg/.pip-cache-armv7 \
-e SETUPTOOLS_SCM_PRETEND_VERSION_FOR_BORGBACKUP="$BORG_VERSION" \
-e HOST_UID="$(id -u)" -e HOST_GID="$(id -g)" \
"$IMAGE" sleep infinity
# if this says anything but armv7l, the emulation did not kick in:
test "$(docker exec "$CONTAINER" uname -m)" = "armv7l"
- name: Build borg (armv7, 32-bit)
run: |
docker exec -i "$CONTAINER" bash -s <<'EOF'
set -euxo pipefail
export DEBIAN_FRONTEND=noninteractive
apt-get update
apt-get install -y --no-install-recommends \
python3 python3-dev python3-venv \
build-essential pkg-config libssl-dev libacl1-dev liblz4-dev
python3 -c 'import sys; assert sys.maxsize == 2**31 - 1, sys.maxsize; print("maxsize:", sys.maxsize)'
python3 -m venv /venv
/venv/bin/pip install --upgrade pip wheel
/venv/bin/pip install pytest pytest-xdist pytest-benchmark pytest-timeout
/venv/bin/pip install /borg
/venv/bin/borg --version
chown -R "$HOST_UID:$HOST_GID" /borg/.pip-cache-armv7
EOF
- name: Run the word size sensitive tests on armv7
run: |
docker exec -i \
-e PYTEST_TARGETS="$PYTEST_TARGETS" \
-e PYTEST_TIMEOUT="$PYTEST_TIMEOUT" \
-e PY_COLORS="$PY_COLORS" \
"$CONTAINER" bash -s <<'EOF'
set -euxo pipefail
# run against the installed borg, not against the source tree:
cd /tmp
/venv/bin/python -m pytest -v -n4 -rs --benchmark-skip --pyargs $PYTEST_TARGETS
EOF
- name: Write test data and a repository on armv7
run: |
set -euxo pipefail
"$RUNNER_TEMP/venv-native/bin/python" scripts/endian_interop_test.py testdata "$INTEROP"
docker exec -i -e INTEROP=/borg/.interop "$CONTAINER" bash -s <<'EOF'
set -euxo pipefail
BORG=/venv/bin/borg /venv/bin/python /borg/scripts/endian_interop_test.py write "$INTEROP" b32
chown -R "$HOST_UID:$HOST_GID" "$INTEROP"
EOF
- name: Read the armv7 repository on x86_64 (and write to it)
run: |
set -euxo pipefail
export BORG="$RUNNER_TEMP/venv-native/bin/borg"
PY="$RUNNER_TEMP/venv-native/bin/python"
$PY scripts/endian_interop_test.py verify "$INTEROP" b32 --as b64
$PY scripts/endian_interop_test.py write "$INTEROP" b64
$PY scripts/endian_interop_test.py compare "$INTEROP" b32 b64
- name: Read the x86_64 archives on armv7
run: |
docker exec -i -e INTEROP=/borg/.interop "$CONTAINER" bash -s <<'EOF'
set -euxo pipefail
BORG=/venv/bin/borg /venv/bin/python /borg/scripts/endian_interop_test.py verify "$INTEROP" b64 --as b32
chown -R "$HOST_UID:$HOST_GID" "$INTEROP"
EOF
- name: Stop the armv7 container
if: ${{ always() }}
run: docker rm -f "$CONTAINER" || true