OILS / deps / wedge.sh View on Github | oils.pub

525 lines, 279 significant
1#!/usr/bin/env bash
2#
3# Build a wedge.
4#
5# Usage:
6# deps/wedge.sh <function name>
7#
8# Containerized build:
9#
10# $0 build deps/source.medo/re2c/
11#
12# Host build, without containers:
13#
14# $0 unboxed deps/source.medo/re2c/
15#
16# Individual steps:
17#
18# $0 unboxed-make deps/source.medo/re2c/
19# $0 unboxed-install deps/source.medo/re2c/
20# $0 unboxed-smoke-test deps/source.medo/re2c/
21#
22# Host dir structure:
23#
24# ~/git/oilshell/oil
25# deps/
26# source.medo/ # Source Files
27# MEDO # points to silo
28# re2c.wedge.sh # later it will be re2c.wedge.hay
29# re2c-3.0.blob # .tar.gz file that you can 'medo sync'
30# re2c-3.1.blob
31# opaque.medo/ # Binary files, e.g. Clang
32# derived.medo/ # Saved output of 'wedge build'
33#
34# _build/ # Temp dirs and output
35# obj/ # for C++ / Ninja
36# deps-source/ # sync'd from deps/source.medo - should it be
37# # _build/wedge/source?
38# wedge/ # for containerized builds
39# tmp/ # build directory
40# boxed/ # output of containerized build
41# # TODO: rename from /binary/
42# logs/
43# smoke-test/ # current dir for smoke test
44
45# Every package ("wedge") has these dirs associated with it:
46#
47# 1. Dir with additional tests / files, near tarball and *.wedge.sh ($wedge_dir)
48# 2. Where it's extracted ($src_dir)
49# 3. The temp dir where you run ./configure --prefix; make; make install ($build_dir)
50# 4. The dir to install to ($install_dir)
51# 5. The temp dir where the smoke test is run
52
53# For Debian/Ubuntu
54
55# Note: xz-utils needed to extract, but medo should make that transparent?
56#
57# Container dir structure
58#
59# /home/uke/
60# tmp-mount/
61# _build/ # Build into this temp dir
62# deps-source/
63# re2c/
64# re2c-3.0.tar.xz
65# re2c-3.0/ # Extract it here
66# wedge/
67# re2c
68# /wedge/ # Output is mounted to oil/_mount/wedge-out
69# oilshell.org/
70# pkg/
71# re2c/
72# 3.0/
73# debug-info/ # Probably needs to be at an absolute path because of
74# # --debug-link
75# re2c/
76# 3.0/
77#
78# Then Dockerfile.wild does:
79#
80# COPY _build/wedge/binary/oils-for-unix.org/pkg/re2c/3.0 \
81# /wedge/oils-for-unix.org/pkg/re2c/3.0
82
83set -o nounset
84set -o pipefail
85set -o errexit
86
87REPO_ROOT=$(cd "$(dirname $0)/.."; pwd)
88readonly REPO_ROOT
89
90OILS_ABSOLUTE_ROOT='/wedge/oils-for-unix.org'
91
92# The user may build a wedge outside a container here
93OILS_RELATIVE_ROOT="$HOME/wedge/oils-for-unix.org"
94
95log() {
96 echo "$@" >&2
97}
98
99die() {
100 log "$0: fatal: $@"
101 exit 1
102}
103
104#
105# Dirs
106#
107
108source-dir() {
109 if test -n "${WEDGE_TARBALL_NAME:-}"; then
110 # for Python-3.10.4 to override 'python3' package name
111 echo "$REPO_ROOT/_build/deps-source/$WEDGE_NAME/$WEDGE_TARBALL_NAME-$WEDGE_VERSION"
112
113 else
114 echo "$REPO_ROOT/_build/deps-source/$WEDGE_NAME/$WEDGE_NAME-$WEDGE_VERSION"
115 fi
116}
117
118build-dir() {
119 # call it tmp-build?
120 echo "$REPO_ROOT/_build/wedge/tmp/$WEDGE_NAME-$WEDGE_VERSION"
121}
122
123install-dir() {
124 local prefix
125 if test -n "${WEDGE_IS_ABSOLUTE:-}"; then
126 prefix=$OILS_ABSOLUTE_ROOT
127 else
128 prefix=$OILS_RELATIVE_ROOT
129 fi
130
131 # TODO: We want to support multiple versions of the same wedge
132 # So maybe we can provide
133 #
134 # WEDGE_VERSION_LIST='4.4 5.2'
135 #
136 # And then provide a flag to select them?
137
138 echo "$prefix/pkg/$WEDGE_NAME/$WEDGE_VERSION"
139}
140
141smoke-test-dir() {
142 echo "$REPO_ROOT/_build/wedge/smoke-test/$WEDGE_NAME-$WEDGE_VERSION"
143}
144
145load-wedge() {
146 ### source .wedge.sh file and ensure it conforms to protocol
147
148 local wedge_dir=$1
149 local version_requested=${2:-}
150
151 echo "Loading $wedge_dir"
152 echo
153
154 source $wedge_dir/WEDGE
155
156 echo " OK name: ${WEDGE_NAME?"$wedge_dir: WEDGE_NAME required"}"
157
158 # This WEDGE supports a single version.
159 if test -n "${WEDGE_VERSION:-}"; then
160 echo " -- single version: $WEDGE_VERSION"
161 fi
162
163 # Can validate version against this
164 if test -n "${WEDGE_VERSION_LIST:-}"; then
165 echo " -- version list: $WEDGE_VERSION_LIST"
166
167 if test -z "$version_requested"; then
168 die "FAIL Expected explicit version, one of: $WEDGE_VERSION_LIST"
169 fi
170
171 case "$WEDGE_VERSION_LIST" in
172 *"$version_requested"*)
173 echo " OK Setting WEDGE_VERSION to $version_requested"
174 WEDGE_VERSION=$version_requested
175 ;;
176 *)
177 die "FAIL Requested version $version_requested should be one of: $WEDGE_VERSION_LIST"
178 ;;
179 esac
180 fi
181
182 if test -n "${WEDGE_TARBALL_NAME:-}"; then
183 echo " -- tarball name: $WEDGE_TARBALL_NAME"
184 fi
185 if test -n "${WEDGE_IS_ABSOLUTE:-}"; then
186 echo ' -- WEDGE_IS_ABSOLUTE'
187 fi
188
189 # Python and R installation use the network
190 if test -n "${WEDGE_LEAKY_BUILD:-}"; then
191 echo ' -- WEDGE_LEAKY_BUILD'
192 fi
193
194 if declare -f wedge-make; then
195 echo " OK wedge-make"
196 elif declare -f wedge-make-from-source-dir; then
197 echo " OK wedge-make-from-source-dir"
198 else
199 die "$wedge_dir: wedge-make(-from-source-dir) not declared"
200 fi
201
202 if declare -f wedge-install; then
203 echo " OK wedge-install"
204 elif declare -f wedge-make-from-source-dir; then
205 echo " OK wedge-install-from-source-dir"
206 else
207 die "$wedge_dir: wedge-install(-from-source-dir) not declared"
208 fi
209
210 # Just one function for now
211 for func in wedge-smoke-test; do
212 if declare -f $func > /dev/null; then
213 echo " OK $func"
214 else
215 die "$wedge_dir: $func not declared"
216 fi
217 done
218 echo
219
220 echo "Loaded $wedge_dir"
221 echo
222}
223
224_run-sourced-func() {
225 "$@"
226}
227
228#
229# Actions
230#
231
232validate() {
233 local wedge=$1
234 local version_requested=${2:-}
235
236 load-wedge $wedge "$version_requested"
237}
238
239abs-wedge-dir() {
240 local wedge_dir=$1
241 case $wedge_dir in
242 /*) # it's already absolute
243 echo $wedge_dir
244 ;;
245 *)
246 echo $PWD/$wedge_dir
247 ;;
248 esac
249}
250
251unboxed-make() {
252 ### Build on the host
253
254 local wedge_dir=$1 # e.g. re2c.wedge.sh
255 local version_requested=${2:-} # e.g. 5.2
256
257 load-wedge $wedge_dir "$version_requested"
258
259 local source_dir
260 source_dir=$(source-dir)
261 echo " SRC $source_dir"
262
263 local build_dir
264 build_dir=$(build-dir)
265
266 # NOT created because it might require root permissions!
267 local install_dir
268 install_dir=$(install-dir)
269
270 local abs_wedge_dir
271 abs_wedge_dir=$(abs-wedge-dir $wedge_dir)
272
273 rm -r -f -v $build_dir
274 mkdir -p $build_dir
275
276 if declare -f wedge-make-from-source-dir; then
277 # e.g. for yash, which can't build outside the source tree
278 pushd $source_dir
279 wedge-make-from-source-dir $source_dir $install_dir $abs_wedge_dir
280 popd
281 else
282 pushd $build_dir
283 wedge-make $source_dir $build_dir $install_dir $abs_wedge_dir
284 popd
285 fi
286}
287
288
289# https://www.gnu.org/prep/standards/html_node/Standard-Targets.html
290
291# Do not strip executables when installing them. This helps eventual
292# debugging that may be needed later, and nowadays disk space is cheap and
293# dynamic loaders typically ensure debug sections are not loaded during
294# normal execution. Users that need stripped binaries may invoke the
295# install-strip target to do that.
296
297_unboxed-install() {
298 local wedge=$1 # e.g. re2c.wedge.sh
299 local version_requested=${2:-} # e.g. 5.2
300
301 load-wedge $wedge "$version_requested"
302
303 local source_dir
304 source_dir=$(source-dir)
305
306 local build_dir
307 build_dir=$(build-dir)
308
309 local install_dir
310 install_dir=$(install-dir)
311 mkdir -p $install_dir
312
313 if declare -f wedge-make-from-source-dir; then
314 pushd $source_dir
315 wedge-install-from-source-dir $source_dir $install_dir
316 popd
317 else
318 # Note: install-dir needed for time-helper, but not others
319 #
320 # I think it would nicer to pushd $build_dir in most cases
321
322 wedge-install $build_dir $install_dir
323 fi
324}
325
326unboxed-install() {
327 local wedge=$1 # e.g. re2.wedge.sh
328
329 if test -n "${WEDGE_IS_ABSOLUTE:-}"; then
330 sudo $0 _unboxed-install "$@"
331 else
332 _unboxed-install "$@"
333 fi
334}
335
336unboxed-smoke-test() {
337 local wedge_dir=$1 # e.g. re2c/ with WEDGE
338 local version_requested=${2:-} # e.g. 5.2
339
340 load-wedge $wedge_dir "$version_requested"
341
342 local smoke_test_dir
343 smoke_test_dir=$(smoke-test-dir)
344 local install_dir
345 install_dir=$(install-dir)
346
347 echo ' SMOKE TEST'
348
349 local abs_wedge_dir
350 abs_wedge_dir=$(abs-wedge-dir $wedge_dir)
351
352 # TODO: To ensure a clean dir, it might be better to test that it does NOT
353 # exist first, and just make it. If it exists, then remove everything.
354
355 rm -r -f -v $smoke_test_dir
356 mkdir -p $smoke_test_dir
357
358 pushd $smoke_test_dir
359 set -x
360 wedge-smoke-test $install_dir $abs_wedge_dir
361 set +x
362 popd
363
364 echo ' OK'
365}
366
367unboxed-stats() {
368 local wedge=$1
369
370 load-wedge $wedge "$version_requested"
371
372 du --si -s $(source-dir)
373 echo
374
375 du --si -s $(build-dir)
376 echo
377
378 du --si -s $(install-dir)
379 echo
380}
381
382unboxed() {
383 local wedge_dir=$1
384
385 # Can override default version. Could be a flag since it's optional? But
386 # right now we always pass it.
387 local version_requested=${2:-}
388
389 # TODO:
390 # - Would be nice to export the logs somewhere
391
392 unboxed-make $wedge_dir "$version_requested"
393
394 unboxed-install $wedge_dir "$version_requested"
395
396 unboxed-smoke-test $wedge_dir "$version_requested"
397}
398
399readonly DEFAULT_DISTRO=debian-10 # Debian Buster
400
401DOCKER=${DOCKER:-docker}
402
403boxed() {
404 ### Build inside a container, and put output in a specific place.
405
406 # TODO: Specify the container OS, CPU like x86-64, etc.
407
408 local wedge=$1
409 local version_requested=${2:-}
410 local distro=${3:-$DEFAULT_DISTRO}
411
412 local bootstrap_image=oilshell/wedge-bootstrap-$distro
413
414 load-wedge $wedge "$version_requested"
415
416 # Permissions will be different, so we separate the two
417
418 local wedge_host_dir
419 local wedge_guest_dir
420 if test -n "${WEDGE_IS_ABSOLUTE:-}"; then
421 wedge_host_dir=_build/wedge/binary # TODO: rename to /absolute/
422 wedge_guest_dir=/wedge
423 else
424 wedge_host_dir=_build/wedge/relative
425 wedge_guest_dir=/home/uke0/wedge
426 fi
427
428 mkdir -v -p $wedge_host_dir
429
430 # TODO:
431 #
432 # Mount
433 # INPUTS: the PKG.wedge.sh, and the tarball
434 # CODE: this script: deps/wedge.sh
435 # OUTPUT: /wedge/oils-for-unix.org
436 # TODO: Also put logs and symbols somewhere
437
438 # Run unboxed-{build,install,smoke-test} INSIDE the container
439 local -a args=(
440 sh -c 'cd ~/oil; deps/wedge.sh unboxed "$1" "$2"'
441 dummy "$wedge" "$version_requested"
442 )
443
444 local -a docker_flags=()
445 if test -n "${WEDGE_LEAKY_BUILD:-}"; then
446 :
447 else
448 # Disable network for hermetic builds. TODO: Add automated test
449 docker_flags=( --network none )
450 fi
451
452 # TODO:
453 # - Don't mount the whole REPO_ROOT
454 # - We want the bare minimum of files, for cache invalidation
455 # - Maybe make it read only
456 # - Bind mount WEDGE_DEPS='', space separated list of paths
457 # - py3-libs depends on python3 and mypy wedges!
458
459 # -E to preserve CONTAINERS_REGISTRIES_CONF
460 sudo -E $DOCKER run "${docker_flags[@]}" \
461 --mount "type=bind,source=$REPO_ROOT,target=/home/uke0/oil" \
462 --mount "type=bind,source=$PWD/$wedge_host_dir,target=$wedge_guest_dir" \
463 $bootstrap_image \
464 "${args[@]}"
465}
466
467smoke-test() {
468 local wedge_dir=$1
469 local wedge_out_dir=${2:-_build/wedge/binary} # TODO: rename to /boxed
470 local version_requested=${3:-}
471 local distro=${4:-$DEFAULT_DISTRO}
472 local debug_shell=${5:-}
473
474 load-wedge $wedge_dir "$version_requested"
475
476 local bootstrap_image=oilshell/wedge-bootstrap-$distro
477
478 local -a args=(
479 sh -c 'cd ~/oil; deps/wedge.sh unboxed-smoke-test $1' dummy "$wedge_dir"
480 )
481 local -a docker_flags=()
482 if test -n "$debug_shell"; then
483 docker_flags=( -i -t )
484 args=( "$debug_shell" )
485 fi
486
487 local wedge_mount_dir
488 if test -n "${WEDGE_IS_ABSOLUTE:-}"; then
489 wedge_mount_dir=/wedge
490 else
491 wedge_mount_dir=/home/uke0/wedge
492 fi
493
494 sudo $DOCKER run "${docker_flags[@]}" \
495 --network none \
496 --mount "type=bind,source=$REPO_ROOT,target=/home/uke0/oil" \
497 --mount "type=bind,source=$PWD/$wedge_out_dir,target=$wedge_mount_dir" \
498 $bootstrap_image \
499 "${args[@]}"
500}
501
502if [[ $# -eq 0 || $1 =~ ^(--help|-h)$ ]]; then
503 # A trick for help. TODO: Move this to a common file, and combine with help
504 # in test/spec.sh.
505
506 awk '
507 $0 ~ /^#/ { print $0 }
508 $0 !~ /^#/ { print ""; exit }
509 ' $0
510 exit
511fi
512
513case $1 in
514 validate|\
515 unboxed|\
516 unboxed-make|unboxed-install|_unboxed-install|\
517 unboxed-smoke-test|unboxed-stats|\
518 boxed|smoke-test)
519 "$@"
520 ;;
521
522 *)
523 die "Invalid action '$1'"
524 ;;
525esac