aurutils: v19.3
[aurutils.git] / lib / aur-chroot
blob7598f5b366ff0b412ff0fc3c2a5dfe16666fed0c
1 #!/bin/bash
2 # aur-chroot - build packages with systemd-nspawn
3 [[ -v AUR_DEBUG ]] && set -o xtrace
4 set -o errexit
5 argv0=chroot
6 PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
7 PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
8 machine=$(uname -m)
10 # default arguments
11 directory=/var/lib/aurbuild/$machine
12 makechrootpkg_args=(-cu) # XXX: allow unsetting these options?
13 makechrootpkg_makepkg_args=()
15 # default options
16 update=0 build=0 create=0 status=0 print_path=0
18 args_csv() {
19 # shellcheck disable=SC2155
20 local str=$(printf '%s,' "$@")
21 printf '%s' "${str%,}"
24 # XXX: a missing makepkg.conf usually indicates a missing devtools, whereas
25 # a missing pacman.conf usually indicates the local repository was not configured
26 diag_makepkg_conf() {
27 echo >&2 'Error:'
29 cat <<EOF | pr -to 4 >&2
30 aur-$argv0 could not find a makepkg.conf(5) file for container usage. Before
31 using aur-$argv0, make sure this file is created and valid. See OPTIONS in
32 aur-$argv0(1) for configuration details.
34 The following file paths were checked:
35 EOF
36 printf '%s\n' "${@@Q}" | pr -to 8 >&2
39 diag_pacman_conf() {
40 echo >&2 'Error:'
42 cat <<EOF | pr -to 4 >&2
43 aur-$argv0 could not find a pacman.conf(5) file for container usage. Before
44 using aur-$argv0, make sure this file is created and valid. See OPTIONS in
45 aur-$argv0(1) for configuration details.
47 The following file paths were checked:
48 EOF
49 printf '%s\n' "${@@Q}" | pr -to 8 >&2
52 usage() {
53 printf 'usage: %s [-BU] [--create] [-CDM path] [package...]\n' "$argv0"
54 exit 1
57 opt_short='C:D:M:x:ABNTU'
58 opt_long=('directory:' 'pacman-conf:' 'makepkg-conf:' 'build' 'update'
59 'create' 'bind:' 'bind-rw:' 'user:' 'makepkg-args:'
60 'ignorearch' 'namcap' 'checkpkg' 'temp' 'makechrootpkg-args:'
61 'margs:' 'cargs:' 'nocheck' 'suffix:')
62 opt_hidden=('dump-options' 'status' 'path')
64 if opts=$(getopt -o "$opt_short" -l "$(args_csv "${opt_long[@]}" "${opt_hidden[@]}")" -n "$argv0" -- "$@"); then
65 eval set -- "$opts"
66 else
67 usage
70 unset bindmounts_ro bindmounts_rw makepkg_conf pacman_conf suffix
71 while true; do
72 case "$1" in
73 -x|--suffix)
74 shift; suffix=$1 ;;
75 -B|--build)
76 build=1 ;;
77 -U|--update)
78 update=1 ;;
79 --create)
80 create=1 ;;
81 --status)
82 status=1 ;;
83 --path) # deprecated
84 print_path=1 ;;
85 # makepkg options (`--build`)
86 -A|--ignorearch)
87 makechrootpkg_makepkg_args+=(--ignorearch) ;;
88 --nocheck)
89 makechrootpkg_makepkg_args+=(--nocheck) ;;
90 # XXX: cannot take arguments that contain commas (e.g. for file paths)
91 --makepkg-args|--margs)
92 shift; IFS=, read -a arg -r <<< "$1"
93 makechrootpkg_makepkg_args+=("${arg[@]}") ;;
94 # devtools options (`--build`)
95 -C|--pacman-conf)
96 shift; pacman_conf=$1 ;;
97 -D|--directory)
98 shift; directory=$1 ;;
99 -M|--makepkg-conf)
100 shift; makepkg_conf=$1 ;;
101 --bind)
102 shift; bindmounts_ro+=("$1") ;;
103 --bind-rw)
104 shift; bindmounts_rw+=("$1") ;;
105 -N|--namcap)
106 makechrootpkg_args+=(-n) ;;
107 --checkpkg)
108 makechrootpkg_args+=(-C) ;;
109 -T|--temp)
110 makechrootpkg_args+=(-T) ;;
111 --user)
112 shift; makechrootpkg_args+=(-U "$1") ;;
113 # XXX: cannot take arguments that contain commas (e.g. for file paths)
114 --makechrootpkg-args|--cargs)
115 shift; IFS=, read -a arg -r <<< "$1"
116 makechrootpkg_args+=("${arg[@]}") ;;
117 # other options
118 --dump-options)
119 printf -- '--%s\n' "${opt_long[@]}" ${AUR_DEBUG+"${opt_hidden[@]}"}
120 printf -- '%s' "${opt_short}" | sed 's/.:\?/-&\n/g'
121 exit ;;
122 --) shift; break ;;
123 esac
124 shift
125 done
127 # XXX: default paths can be set through the Makefile (`aur-chroot.in`)
128 etcdir=/etc/aurutils shrdir=/usr/share/devtools
130 # The pacman configuration in the chroot may contain a local repository that
131 # is not configured on the host. Therefore, $db_name is only used for the
132 # default paths below when specified on the command-line or through `AUR_REPO`.
133 if [[ -v suffix ]]; then
134 default_pacman_paths=("$etcdir/pacman-$suffix.conf"
135 "$etcdir/pacman-$machine.conf"
136 "$shrdir/pacman.conf.d/$suffix.conf"
137 "$shrdir/pacman.conf.d/aurutils-$machine.conf")
139 default_makepkg_paths=("$etcdir/makepkg-$suffix.conf"
140 "$etcdir/makepkg-$machine.conf"
141 "$shrdir/makepkg.conf.d/$suffix.conf"
142 "$shrdir/makepkg.conf.d/$machine.conf")
143 else
144 default_pacman_paths=("$etcdir/pacman-$machine.conf"
145 "$shrdir/pacman.conf.d/aurutils-$machine.conf")
147 default_makepkg_paths=("$etcdir/makepkg-$machine.conf"
148 "$shrdir/makepkg.conf.d/$machine.conf")
151 # Change the default /usr/share/devtools/pacman-extra.conf in aur-chroot to
152 # /etc/aurutils/pacman-<repo>.conf or /etc/aurutils/pacman-<uname>.conf in
153 # aur-build, and pass it on to aur-chroot (#824, #846)
154 for def in "${default_pacman_paths[@]}"; do
155 if [[ -f $def ]] && [[ ! -v pacman_conf ]]; then
156 pacman_conf=$def
157 break
159 done
161 # The same as above but for /etc/aurutils/makepkg-<repo>.conf or
162 # /etc/aurutils/makepkg-<uname>.conf. If the file is not found, fallback to
163 # makepkg.conf files in /usr/share/devtools.
164 for def in "${default_makepkg_paths[@]}"; do
165 if [[ -f $def ]] && [[ ! -v makepkg_conf ]]; then
166 makepkg_conf=$def
167 break
169 done
171 # No pacman configuration is available for the container, or it points to a
172 # non-existing file. Print a matching diagnostic and exit.
173 if [[ ! -v pacman_conf ]]; then
174 diag_pacman_conf "${default_pacman_paths[@]}"
175 exit 2
176 elif [[ ! -f $pacman_conf ]]; then
177 diag_pacman_conf "$pacman_conf"
178 exit 2
179 elif [[ ! -v makepkg_conf ]]; then
180 diag_makepkg_conf "${default_makepkg_paths[@]}"
181 exit 2
182 elif [[ ! -f $makepkg_conf ]]; then
183 diag_makepkg_conf "$makepkg_conf"
184 exit 2
187 # Print paths to container and used makepkg/pacman paths. This does
188 # not require a priorly created container.
189 if (( status )); then
190 printf 'chroot:%s\npacman:%s\nmakepkg:%s\n' "$directory" "$pacman_conf" "$makepkg_conf"
191 exit 0
194 # Custom elevation command (#1024)
195 unset auth_args
196 AUR_PACMAN_AUTH=${AUR_PACMAN_AUTH:-sudo}
198 case $AUR_PACMAN_AUTH in
199 sudo) auth_args+=('--preserve-env=GNUPGHOME,SSH_AUTH_SOCK,PKGDEST') ;;
200 esac
202 # bind mount file:// paths to container (#461)
203 # required for update/build steps
204 while read -r key _ value; do
205 case $key=$value in
206 Server=file://*)
207 bindmounts_rw+=("${value#file://}") ;;
208 esac
209 done < <(pacman-conf --config "$pacman_conf")
210 wait "$!"
212 # create new container, required for update/build steps
213 if (( create )); then
214 # default to base-devel or multilib-devel, unless packages are
215 # specified on the command-line.
216 # available packages depend on the configured pacman configuration
217 if (( $# )); then
218 base_packages=("$@")
220 # XXX: use pacini to not process Include directives in pacman.conf
221 # (not supported by devtools)
222 elif [[ $(pacini --section=multilib "$pacman_conf") ]] && [[ $machine == "x86_64" ]]; then
223 base_packages=('base-devel' 'multilib-devel')
224 else
225 base_packages=('base-devel')
228 # parent path is not created by mkarchroot (#371)
229 if [[ ! -d $directory ]]; then
230 # shellcheck disable=SC2086
231 $AUR_PACMAN_AUTH install -d "$directory" -m 755 -v
234 if [[ ! -d $directory/root ]]; then
235 # shellcheck disable=SC2086
236 $AUR_PACMAN_AUTH mkarchroot -C "$pacman_conf" -M "$makepkg_conf" "$directory"/root "${base_packages[@]}"
238 fi >&2
240 # arch-nspawn makes no distinction between a missing working directory
241 # and one which does not exist
242 if [[ ! -d $directory/root ]]; then
243 printf >&2 '%s: %q is not a directory\n' "$argv0" "$directory"/root
244 printf >&2 '%s: did you run aur chroot --create?\n' "$argv0"
245 exit 20
248 if (( update )); then
249 # locking is done by systemd-nspawn
250 # shellcheck disable=SC2086
251 $AUR_PACMAN_AUTH arch-nspawn -C "$pacman_conf" -M "$makepkg_conf" "$directory"/root \
252 "${bindmounts_ro[@]/#/--bind-ro=}" \
253 "${bindmounts_rw[@]/#/--bind=}" pacman -Syu --noconfirm "$@"
254 fi >&2
256 # print path for processing by other tools (e.g. makepkg --packagelist)
257 if (( print_path )); then
258 realpath -- "$directory"/root
259 exit $?
262 if (( build )); then
263 # use makechrootpkg -c as default build command (sync /root container)
264 # arguments after -- are used as makechrootpkg arguments
265 # shellcheck disable=SC2086
266 $AUR_PACMAN_AUTH "${auth_args[@]}" makechrootpkg -r "$directory" \
267 "${bindmounts_ro[@]/#/-D}" "${bindmounts_rw[@]/#/-d}" \
268 "${makechrootpkg_args[@]}" -- "${makechrootpkg_makepkg_args[@]}"
269 fi >&2
271 # vim: set et sw=4 sts=4 ft=sh: