Skip to content

Commit 0c9597c

Browse files
committed
Merge #21304: guix: Add guix-clean script + establish gc-root for container profiles
867a5e1 guix: Register garbage collector root for containers (Carl Dong) 8f8b96f guix: Update hint messages to mention guix-clean (Carl Dong) 44f6d4f guix: Record precious directories and add guix-clean (Carl Dong) 84912d4 build: Remove spaces from variable-printing rules (Carl Dong) Pull request description: ``` guix: Record precious directories and add guix-clean Many users have reported problems that stem from having an unclean working tree. To that end, I've written a guix-clean script which should help reset the working tree while respecting user-specified precious directories. Precious directories, such as: - SOURCES_PATH - BASE_CACHE - SDK_PATH - OUTDIR Should be preserved when cleaning the working tree, and are thus recorded in ./contrib/guix/var/precious_dirs. The ./contrib/guix/guix-clean script is able to parse that file and make sure to avoid them when cleaning out the working tree. ``` ACKs for top commit: laanwj: ACK 867a5e1 Tree-SHA512: c498fad781ff5e6406639df2b91b687fc528273fdf266bcdba8f6eec3b3b37ecce544b6da0252f0b9c6717f9d88e844e4c7b72d1877bdbabfc6871ddd0172af5
2 parents 6664211 + 867a5e1 commit 0c9597c

File tree

6 files changed

+175
-20
lines changed

6 files changed

+175
-20
lines changed

Makefile.am

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
# Pattern rule to print variables, e.g. make print-top_srcdir
66
print-%:
7-
@echo '$*' = '$($*)'
7+
@echo '$*'='$($*)'
88

99
ACLOCAL_AMFLAGS = -I build-aux/m4
1010
SUBDIRS = src

contrib/guix/guix-build

Lines changed: 83 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,14 @@ ERR: Build directories for this commit already exist for the following platform
103103
104104
Aborting...
105105
106+
Hint: To blow everything away, you may want to use:
107+
108+
$ ./contrib/guix/guix-clean
109+
110+
Specifically, this will remove all files without an entry in the index,
111+
excluding the SDK directory, the depends download cache, the depends built
112+
packages cache, the garbage collector roots for Guix environments, and the
113+
output directory.
106114
EOF
107115
for host in $hosts_distsrc_exists; do
108116
echo " ${host} '$(distsrc_for_host "$host")'"
@@ -119,7 +127,7 @@ fi
119127
for host in $HOSTS; do
120128
case "$host" in
121129
*darwin*)
122-
OSX_SDK="$(make -C "${PWD}/depends" --no-print-directory HOST="$host" print-OSX_SDK | sed 's@^[^=]\+=[[:space:]]\+@@g')"
130+
OSX_SDK="$(make -C "${PWD}/depends" --no-print-directory HOST="$host" print-OSX_SDK | sed 's@^[^=]\+=@@g')"
123131
if [ -e "$OSX_SDK" ]; then
124132
echo "Found macOS SDK at '${OSX_SDK}', using..."
125133
else
@@ -178,12 +186,6 @@ host_to_commonname() {
178186
esac
179187
}
180188

181-
# Download the depends sources now as we won't have internet access in the build
182-
# container
183-
for host in $HOSTS; do
184-
make -C "${PWD}/depends" -j"$JOBS" download-"$(host_to_commonname "$host")" ${V:+V=1} ${SOURCES_PATH:+SOURCES_PATH="$SOURCES_PATH"}
185-
done
186-
187189
# Determine the reference time used for determinism (overridable by environment)
188190
SOURCE_DATE_EPOCH="${SOURCE_DATE_EPOCH:-$(git log --format=%at -1)}"
189191

@@ -201,10 +203,70 @@ time-machine() {
201203
-- "$@"
202204
}
203205

206+
207+
# Precious directories are those which should not be cleaned between successive
208+
# guix builds
209+
depends_precious_dir_names='SOURCES_PATH BASE_CACHE SDK_PATH'
210+
precious_dir_names="${depends_precious_dir_names} OUTDIR_BASE PROFILES_BASE"
211+
212+
# Usage: contains IFS-SEPARATED-LIST ITEM
213+
contains() {
214+
for i in ${1}; do
215+
if [ "$i" = "${2}" ]; then
216+
return 0 # Found!
217+
fi
218+
done
219+
return 1
220+
}
221+
222+
# If the user explicitly specified a precious directory, create it so we
223+
# can map it into the container
224+
for precious_dir_name in $precious_dir_names; do
225+
precious_dir_path="${!precious_dir_name}"
226+
if [ -n "$precious_dir_path" ]; then
227+
if [ ! -e "$precious_dir_path" ]; then
228+
mkdir -p "$precious_dir_path"
229+
elif [ -L "$precious_dir_path" ]; then
230+
echo "ERR: ${precious_dir_name} cannot be a symbolic link"
231+
exit 1
232+
elif [ ! -d "$precious_dir_path" ]; then
233+
echo "ERR: ${precious_dir_name} must be a directory"
234+
exit 1
235+
fi
236+
fi
237+
done
238+
239+
mkdir -p "$VAR_BASE"
240+
241+
# Record the _effective_ values of precious directories such that guix-clean can
242+
# avoid clobbering them if appropriate.
243+
#
244+
# shellcheck disable=SC2046,SC2086
245+
{
246+
# Get depends precious dir definitions from depends
247+
make -C "${PWD}/depends" \
248+
--no-print-directory \
249+
-- $(printf "print-%s\n" $depends_precious_dir_names)
250+
251+
# Get remaining precious dir definitions from the environment
252+
for precious_dir_name in $precious_dir_names; do
253+
precious_dir_path="${!precious_dir_name}"
254+
if ! contains "$depends_precious_dir_names" "$precious_dir_name"; then
255+
echo "${precious_dir_name}=${precious_dir_path}"
256+
fi
257+
done
258+
} > "${VAR_BASE}/precious_dirs"
259+
204260
# Make sure an output directory exists for our builds
205261
OUTDIR_BASE="${OUTDIR_BASE:-${VERSION_BASE}/output}"
206262
mkdir -p "$OUTDIR_BASE"
207263

264+
# Download the depends sources now as we won't have internet access in the build
265+
# container
266+
for host in $HOSTS; do
267+
make -C "${PWD}/depends" -j"$JOBS" download-"$(host_to_commonname "$host")" ${V:+V=1} ${SOURCES_PATH:+SOURCES_PATH="$SOURCES_PATH"}
268+
done
269+
208270
# Usage: outdir_for_host HOST
209271
#
210272
# HOST: The current platform triple we're building for
@@ -213,6 +275,14 @@ outdir_for_host() {
213275
echo "${OUTDIR_BASE}/${1}"
214276
}
215277

278+
# Usage: profiledir_for_host HOST COMMAND
279+
#
280+
# HOST: The current platform triple we're building for
281+
#
282+
profiledir_for_host() {
283+
echo "${PROFILES_BASE}/${2}-${1}"
284+
}
285+
216286

217287
#########
218288
# BUILD #
@@ -223,24 +293,19 @@ outdir_for_host() {
223293
int_trap() {
224294
cat << EOF
225295
** INT received while building ${1}, you may want to clean up the relevant
226-
output, deploy, and distsrc-* directories before rebuilding
296+
work directories (e.g. distsrc-*) before rebuilding
227297
228298
Hint: To blow everything away, you may want to use:
229299
230-
$ git clean -xdff --exclude='/depends/SDKs/*'
300+
$ ./contrib/guix/guix-clean
231301
232302
Specifically, this will remove all files without an entry in the index,
233-
excluding the SDK directory. Practically speaking, this means that all ignored
234-
and untracked files and directories will be wiped, allowing you to start anew.
303+
excluding the SDK directory, the depends download cache, the depends built
304+
packages cache, the garbage collector roots for Guix environments, and the
305+
output directory.
235306
EOF
236307
}
237308

238-
# Create SOURCES_PATH, BASE_CACHE, and SDK_PATH if they are non-empty so that we
239-
# can map them into the container
240-
[ -z "$SOURCES_PATH" ] || mkdir -p "$SOURCES_PATH"
241-
[ -z "$BASE_CACHE" ] || mkdir -p "$BASE_CACHE"
242-
[ -z "$SDK_PATH" ] || mkdir -p "$SDK_PATH"
243-
244309
# Deterministically build Bitcoin Core
245310
# shellcheck disable=SC2153
246311
for host in $HOSTS; do
@@ -347,6 +412,7 @@ EOF
347412
--keep-failed \
348413
--fallback \
349414
--link-profile \
415+
--root="$(profiledir_for_host "${HOST}" build)" \
350416
${SUBSTITUTE_URLS:+--substitute-urls="$SUBSTITUTE_URLS"} \
351417
${ADDITIONAL_GUIX_COMMON_FLAGS} ${ADDITIONAL_GUIX_ENVIRONMENT_FLAGS} \
352418
-- env HOST="$host" \

contrib/guix/guix-clean

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
#!/usr/bin/env bash
2+
export LC_ALL=C
3+
set -e -o pipefail
4+
5+
# Source the common prelude, which:
6+
# 1. Checks if we're at the top directory of the Bitcoin Core repository
7+
# 2. Defines a few common functions and variables
8+
#
9+
# shellcheck source=libexec/prelude.bash
10+
source "$(dirname "${BASH_SOURCE[0]}")/libexec/prelude.bash"
11+
12+
13+
###################
14+
## Sanity Checks ##
15+
###################
16+
17+
################
18+
# Required non-builtin commands should be invokable
19+
################
20+
21+
check_tools cat mkdir make git guix
22+
23+
24+
#############
25+
## Clean ##
26+
#############
27+
28+
# Usage: under_dir MAYBE_PARENT MAYBE_CHILD
29+
#
30+
# If MAYBE_CHILD is a subdirectory of MAYBE_PARENT, print the relative path
31+
# from MAYBE_PARENT to MAYBE_CHILD. Otherwise, return 1 as the error code.
32+
#
33+
# NOTE: This does not perform any symlink-resolving or path canonicalization.
34+
#
35+
under_dir() {
36+
local path_residue
37+
path_residue="${2##${1}}"
38+
if [ -z "$path_residue" ] || [ "$path_residue" = "$2" ]; then
39+
return 1
40+
else
41+
echo "$path_residue"
42+
fi
43+
}
44+
45+
# Usage: dir_under_git_root MAYBE_CHILD
46+
#
47+
# If MAYBE_CHILD is under the current git repository and exists, print the
48+
# relative path from the git repository's top-level directory to MAYBE_CHILD,
49+
# otherwise, exit with an error code.
50+
#
51+
dir_under_git_root() {
52+
local rv
53+
rv="$(under_dir "$(git_root)" "$1")"
54+
[ -n "$rv" ] && echo "$rv"
55+
}
56+
57+
shopt -s nullglob
58+
found_precious_dirs_files=( "${version_base_prefix}"*/"${var_base_basename}/precious_dirs" ) # This expands to an array of directories...
59+
shopt -u nullglob
60+
61+
exclude_flags=()
62+
63+
for precious_dirs_file in "${found_precious_dirs_files[@]}"; do
64+
# Make sure the precious directories (e.g. SOURCES_PATH, BASE_CACHE, SDK_PATH)
65+
# are excluded from git-clean
66+
echo "Found precious_dirs file: '${precious_dirs_file}'"
67+
68+
# Exclude the precious_dirs file itself
69+
if dirs_file_exclude_fragment=$(dir_under_git_root "$(dirname "$precious_dirs_file")"); then
70+
exclude_flags+=( --exclude="${dirs_file_exclude_fragment}/precious_dirs" )
71+
fi
72+
73+
# Read each 'name=dir' pair from the precious_dirs file
74+
while IFS='=' read -r name dir; do
75+
# Add an exclusion flag if the precious directory is under the git root.
76+
if under=$(dir_under_git_root "$dir"); then
77+
echo "Avoiding ${name}: ${under}"
78+
exclude_flags+=( --exclude="$under" )
79+
fi
80+
done < "$precious_dirs_file"
81+
done
82+
83+
git clean -xdff "${exclude_flags[@]}"

contrib/guix/libexec/prelude.bash

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,9 @@ VERSION_BASE="${version_base_prefix}${VERSION}" # TOP
5858
DISTSRC_BASE="${DISTSRC_BASE:-${VERSION_BASE}}"
5959

6060
OUTDIR_BASE="${OUTDIR_BASE:-${VERSION_BASE}/output}"
61+
62+
var_base_basename="var"
63+
VAR_BASE="${VAR_BASE:-${VERSION_BASE}/${var_base_basename}}"
64+
65+
profiles_base_basename="profiles"
66+
PROFILES_BASE="${PROFILES_BASE:-${VAR_BASE}/${profiles_base_basename}}"

depends/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
# Pattern rule to print variables, e.g. make print-top_srcdir
44
print-%:
5-
@echo '$*' = '$($*)'
5+
@echo '$*'='$($*)'
66

77
# When invoking a sub-make, keep only the command line variable definitions
88
# matching the pattern in the filter function.

src/Makefile.am

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
# Pattern rule to print variables, e.g. make print-top_srcdir
66
print-%:
7-
@echo '$*' = '$($*)'
7+
@echo '$*'='$($*)'
88

99
DIST_SUBDIRS = secp256k1 univalue
1010

0 commit comments

Comments
 (0)