Skip to content

Commit 44f6d4f

Browse files
committed
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.
1 parent 84912d4 commit 44f6d4f

File tree

3 files changed

+146
-12
lines changed

3 files changed

+146
-12
lines changed

contrib/guix/guix-build

Lines changed: 60 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -178,12 +178,6 @@ host_to_commonname() {
178178
esac
179179
}
180180

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-
187181
# Determine the reference time used for determinism (overridable by environment)
188182
SOURCE_DATE_EPOCH="${SOURCE_DATE_EPOCH:-$(git log --format=%at -1)}"
189183

@@ -201,10 +195,70 @@ time-machine() {
201195
-- "$@"
202196
}
203197

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

256+
# Download the depends sources now as we won't have internet access in the build
257+
# container
258+
for host in $HOSTS; do
259+
make -C "${PWD}/depends" -j"$JOBS" download-"$(host_to_commonname "$host")" ${V:+V=1} ${SOURCES_PATH:+SOURCES_PATH="$SOURCES_PATH"}
260+
done
261+
208262
# Usage: outdir_for_host HOST
209263
#
210264
# HOST: The current platform triple we're building for
@@ -235,12 +289,6 @@ and untracked files and directories will be wiped, allowing you to start anew.
235289
EOF
236290
}
237291

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-
244292
# Deterministically build Bitcoin Core
245293
# shellcheck disable=SC2153
246294
for host in $HOSTS; do

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: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,6 @@ 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}}"

0 commit comments

Comments
 (0)