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