2 # aur-build - build packages to a local repository
3 [[ -v AUR_DEBUG
]] && set -o xtrace
8 PS4
='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
10 # Avoid CDPATH screwing with cd (#1047)
14 chroot
=0 no_sync
=0 overwrite
=0 sign_pkg
=0 run_pkgver
=0 truncate
=1
16 # default arguments (empty)
17 chroot_args
=() chroot_makepkg_args
=() pacconf_args
=() repo_args
=() repo_add_args
=()
18 pkglist_args
=() makepkg_args
=() makepkg_common_args
=() read_args
=()
21 gpg_args
=(--detach-sign --no-armor --batch)
24 # shellcheck disable=SC2155
25 local str
=$
(printf '%s,' "$@")
26 printf '%s' "${str%,}"
29 # Print diagnostic on non-moved packages (#794)
30 diag_moved_packages
() {
33 cat <<EOF | pr -to 4 >&2
34 aur-$argv0 encountered an error before moving packages to the local repository.
35 This may happen when signing built packages with gpg (aur $argv0 --sign),
36 or with certain makepkg errors.
38 The following files were preserved:
40 printf '%s\n' "${@@Q}" |
pr -to 8 >&2
43 get_local_upgrades
() {
46 # pacman prints diagnostics (::) to standard output, but does not accept
47 # repositories starting in `:: `. Redirect output accordingly.
48 LANG
=C pacman
-Sup --print-format '%r/%n' |
awk -F/ -v repo
="$repo" '
50 $1 ~ /^:: / {print $0 >"/dev/stderr"}
52 return "${PIPESTATUS[0]}"
56 if [[ ! -v AUR_DEBUG
]]; then
59 # Only remove package directory if all files were moved (#593)
60 if ! rm -df -- "$var_tmp"; then
61 diag_moved_packages
"$var_tmp"/*
64 printf >&2 'AUR_DEBUG: %s: temporary files at %s\n' "$argv0" "$tmp"
65 printf >&2 'AUR_DEBUG: %s: temporary files at %s\n' "$argv0" "$var_tmp"
70 printf >&2 'usage: %s [-acfNS] [-d repo] [--root path] [--margs makepkg_arg...]\n' "$argv0"
74 # mollyguard for makepkg
75 if (( UID
== 0 )) && [[ ! -v AUR_ASROOT
]]; then
76 printf >&2 'warning: aur-%s is not meant to be run as root.\n' "$argv0"
77 printf >&2 'warning: To proceed anyway, set the %s variable.\n' 'AUR_ASROOT'
82 opt_short
='a:d:D:U:AcCfnrsvzLNRST'
83 opt_long
=('arg-file:' 'chroot' 'database:' 'force' 'root:' 'sign' 'gpg-sign'
84 'verify' 'directory:' 'no-sync' 'pacman-conf:' 'remove' 'pkgver'
85 'rmdeps' 'no-confirm' 'no-check' 'ignore-arch' 'log' 'new'
86 'makepkg-conf:' 'bind:' 'bind-rw:' 'prevent-downgrade' 'temp'
87 'syncdeps' 'clean' 'namcap' 'checkpkg' 'makepkg-args:' 'user:'
88 'margs:' 'buildscript:' 'null' 'dbext:')
89 opt_hidden
=('dump-options' 'ignorearch' 'noconfirm' 'nocheck' 'nosync' 'repo:'
90 'results:' 'results-append:')
92 if opts
=$
(getopt
-o "$opt_short" -l "$(args_csv "${opt_long[@]}" "${opt_hidden[@]}")" -n "$argv0" -- "$@"); then
98 unset db_ext db_name db_path db_root makepkg_conf pacman_conf results_file pkgrel_incr queue
108 -d|
--database|
--repo)
110 repo_args
+=(--repo "$1") ;;
114 shift; makepkg_common_args
+=(-p "$1")
115 pkglist_args
+=(-p "$1") ;;
119 shift; makepkg_conf
=$1 ;;
121 shift; pacman_conf
=$1 ;;
123 run_pkgver
=1; makepkg_args
+=(--noextract)
124 chroot_args
+=(--margs '--holdver') ;;
127 repo_args
+=(--root "$1") ;;
128 -S|
--sign|
--gpg-sign)
129 sign_pkg
=1; repo_add_args
+=(-s) ;;
132 shift; chroot_args
+=(--directory "$1") ;;
134 shift; chroot_args
+=(--bind "$1") ;;
136 shift; chroot_args
+=(--bind-rw "$1") ;;
137 # XXX: different meaning between aur-build -U (--user) and aur-chroot -U (--update)
139 shift; chroot_args
+=(--user "$1") ;;
141 chroot_args
+=(--namcap) ;;
143 chroot_args
+=(--checkpkg) ;;
145 chroot_args
+=(-temp) ;;
146 # makepkg options (common)
147 -A|
--ignorearch|
--ignore-arch)
148 chroot_makepkg_args
+=(--ignorearch)
149 makepkg_common_args
+=(--ignorearch) ;;
150 -n|
--noconfirm|
--no-confirm)
151 makepkg_common_args
+=(--noconfirm) ;;
153 makepkg_common_args
+=(--rmdeps) ;;
155 makepkg_common_args
+=(--syncdeps) ;;
156 # makepkg options (build)
158 makepkg_args
+=(--clean) ;;
160 makepkg_args
+=(--log) ;;
161 --nocheck|
--no-check)
162 chroot_makepkg_args
+=(--nocheck)
163 makepkg_args
+=(--nocheck) ;;
164 # XXX: cannot take arguments that contain commas (e.g. for file paths)
165 --makepkg-args|
--margs)
166 shift; chroot_makepkg_args
+=(--margs "$1")
167 IFS
=, read -a arg
-r <<< "$1"
168 makepkg_args
+=("${arg[@]}") ;;
171 repo_add_args
+=(-v) ;;
173 repo_add_args
+=(-R) ;;
175 repo_add_args
+=(-n) ;;
177 repo_add_args
+=(-p) ;;
180 shift; results_file
=$1 ;;
182 shift; results_file
=$1; truncate
=0 ;;
184 read_args
+=(-d $
'\0') ;;
186 printf -- '--%s\n' "${opt_long[@]}" ${AUR_DEBUG+"${opt_hidden[@]}"}
187 printf -- '%s' "${opt_short}" | sed 's/.:\?/-&\n/g'
194 # Assign environment variables
195 db_ext=${db_ext:-$AUR_DBEXT} db_name=${db_name:-$AUR_REPO} db_root=${db_root:-$AUR_DBROOT}
197 # shellcheck disable=SC2174
198 mkdir -pm 0700 -- "${TMPDIR:-/tmp}/aurutils-
$UID"
199 tmp=$(mktemp -d --tmpdir "aurutils-
$UID/$argv0.XXXXXXXX
")
201 # shellcheck disable=SC2174
202 mkdir -pm 0700 -- "${TMPDIR:-/var/tmp}/aurutils-
$UID"
203 var_tmp=$(mktemp -d --tmpdir="${TMPDIR:-/var/tmp/}" "aurutils-
$UID/$argv0.XXXXXXXX
")
205 trap 'trap_exit' EXIT
208 if (( chroot )); then
209 if [[ -v pacman_conf ]]; then
210 chroot_args+=(--pacman-conf "$pacman_conf")
211 elif [[ $db_name ]]; then
212 chroot_args+=(--suffix "$db_name")
214 if [[ -v makepkg_conf ]]; then
215 chroot_args+=(--makepkg-conf "$makepkg_conf")
218 # Retrieve the makepkg and pacman configuration used in the container.
220 IFS=: read -r _ pacman_conf
221 IFS=: read -r _ makepkg_conf
222 } < <(aur chroot "${chroot_args[@]}" --status)
225 # Ensure PKGEXT defined in the container makepkg.conf is used for
226 # makepkg calls on the host (`makepkg --packagelist`).
230 # Propagate `makepkg` configuration to other tools.
231 if [[ -v makepkg_conf ]]; then
232 makepkg_common_args+=(--config "$makepkg_conf")
233 pkglist_args+=(--config "$makepkg_conf")
236 # Automatically choose the local repository based on `pacman`
237 # configuration. With container builds, this repository is not
238 # necessarily configured on the host.
239 if [[ -v pacman_conf ]]; then
240 pacconf_args+=(--config "$pacman_conf")
243 if [[ $db_name ]] && [[ $db_root ]]; then
244 db_path=$db_root/$db_name.${db_ext:-db}
245 db_path=$(realpath -- "$db_path")
247 { IFS=: read -r _ db_name
248 IFS=: read -r _ db_root
249 IFS=: read -r _ db_path # canonicalized
250 } < <(aur repo --status "${repo_args[@]}" "${pacconf_args[@]}")
253 db_root=$(realpath -- "$db_root")
255 # Check that a valid database extension was retrieved (#700, #1038)
256 if [[ -z $AUR_DBEXT ]] && [[ $db_path =~ \.db$ ]]; then
257 printf >&2 '%s: %s does not have a valid database archive extension\n' "$argv0" "$db_path"
258 # TODO: this usually happens on file systems not supporting symbolic links
259 # (SMB/CIFS). Add a diagnostic to point towards AUR_DBEXT in this case
263 # File permission checks
264 # XXX: read permissions not necessarily required for chroot builds
265 if [[ ! -f $db_path ]]; then
266 printf >&2 '%s: %s: not a regular file\n' "$argv0" "$db_path"
268 elif [[ ! -w $db_path ]]; then
269 printf >&2 '%s: %s: permission denied\n' "$argv0" "$db_path"
271 elif [[ -v pacman_conf ]] && [[ ! -r $pacman_conf ]]; then
272 printf >&2 '%s: %s: permission denied\n' "$argv0" "$pacman_conf"
274 elif [[ -v makepkg_conf ]] && [[ ! -r $makepkg_conf ]]; then
275 printf >&2 '%s: %s: permission denied\n' "$argv0" "$makepkg_conf"
279 # Write successfully built packages to file (#437, #980)
280 if [[ -v results_file ]]; then
281 results_file=$(realpath -- "$results_file")
282 (( truncate )) && true | tee "$results_file"
285 if [[ -v queue ]]; then
288 exec {fd}< <(echo "$startdir")
291 # Early consistency check for signed database
292 if (( ! sign_pkg )); then
293 db_sigs=("$db_root/$db_name".sig "$db_root/$db_name".files.sig)
295 if [[ -f ${db_sigs[0]} ]]; then
296 printf >&2 '%s: database signature found, but signing is disabled\n' "$argv0"
298 printf '%q\n' >&2 "${db_sigs[@]}"
302 elif [[ -v GPGKEY ]]; then
303 #shellcheck disable=SC2086
304 ${AUR_GPG:-gpg} --list-keys "$GPGKEY"
305 gpg_args+=(-u "$GPGKEY")
308 if (( chroot )); then
309 # Update pacman and makepkg configuration for the chroot build
310 # queue. A full system upgrade is run on the /root container to
311 # avoid lenghty upgrades for makechrootpkg -u.
312 aur chroot "${chroot_args[@]}" --create --update
315 while IFS= read "${read_args[@]}" -ru "$fd" path; do
317 [[ $path ]] && cd -- "$path"
319 # Allow running repo-add(8) on existing packages (#839)
323 # Run pkgver function before --packagelist (#500)
324 if (( run_pkgver )); then
325 #shellcheck disable=SC2086
326 ${AUR_MAKEPKG:-makepkg} -od "${makepkg_common_args[@]}" >&2
329 # Retrieve list of potential package paths. This is used to (optionally)
330 # check if package paths are already available in the local repository
331 # before builds. If so, the build is skipped and the path is passed to
332 # repo-add (create_package=0). If no paths are available, the package is
333 # assumed to not exist and the build proceeds as usual (create_package=1).
334 if (( ! overwrite )); then
336 #shellcheck disable=SC2086
337 while read -r pkgpath; do
338 [[ -f $pkgpath ]] && exists+=("$pkgpath")
339 done < <(PKGDEST="$db_root" ${AUR_BUILD_PKGLIST:-aur build--pkglist} "${pkglist_args[@]}")
342 printf >&2 '%s: warning: failed to retrieve package list\n' "$argv0"
345 if (( ${#exists[@]} )); then
346 printf >&2 '%s: warning: skipping existing package (use -f to overwrite)\n' "$argv0"
349 printf '%q\n' >&2 "${exists[@]}"
350 pkglist=("${exists[@]}")
353 if (( ${#exists[@]} )) && [[ -v results_file ]]; then
354 printf "exist
:file://%s
\n" "${exists[@]}" | tee -a "$results_file" >/dev/null
358 if (( create_package )); then
359 if (( chroot )); then
360 PKGDEST="$var_tmp" aur chroot "${chroot_args[@]}" --build "${chroot_makepkg_args[@]}"
362 #shellcheck disable=SC2086
363 PKGDEST="$var_tmp" LOGDEST="${LOGDEST:-$PWD}" \
364 ${AUR_MAKEPKG:-makepkg} "${makepkg_common_args[@]}" "${makepkg_args[@]}"
368 pkglist
=(!(*.sig
)) # discard makepkg --sign from package list (#410)
371 # pkglist has paths to $db_root/<pkg>
374 # Sign any packages without signatures, even if the packages are existing.
377 for p
in "${pkglist[@]}"; do
378 # Package basename (equals $p if create_package=1)
381 # Signature from makepkg --sign
382 if [[ -f $p_base.sig
]]; then
383 siglist
+=("$p_base".sig
)
385 # Skipped package build with signature
386 elif [[ -f $db_root/$p_base.sig
]] && [[ ! -f $p_base ]]; then
387 printf >&2 '%s: existing signature file %q\n' "$argv0" "$db_root/$p_base.sig"
389 # No candidate signature, generate one
390 elif (( sign_pkg
)); then
391 #shellcheck disable=SC2086
392 ${AUR_GPG:-gpg} "${gpg_args[@]}" --output "$p_base".sig
"$p"
394 printf >&2 '%s: created signature file %q\n' "$argv0" "$p_base".sig
395 siglist
+=("$p_base".sig
)
399 if (( create_package
)); then
400 mv -f "${siglist[@]}" "${pkglist[@]}" "$db_root"
402 if [[ -v results_file
]]; then
403 printf "build:file://$db_root/%s\n" "${pkglist[@]}" |
tee -a "$results_file" >/dev
/null
406 elif (( ${#siglist[@]} )); then
407 mv -f "${siglist[@]}" "$db_root"
411 #shellcheck disable=SC2086
412 env
-C "$db_root" LANG
=C
${AUR_REPO_ADD:-repo-add} "${repo_add_args[@]}" "$db_path" "${pkglist[@]}"
414 if (( chroot )) || (( no_sync )); then
417 #shellcheck disable=SC2086
418 ${AUR_PACMAN_AUTH:-sudo} pacsync "$db_name"
419 #shellcheck disable=SC2086
420 ${AUR_PACMAN_AUTH:-sudo} pacsync "$db_name" --dbext=.files
422 # Retrieve upgrade targets in local repository. May error in case of
423 # conflicts or dependency errors.
424 mapfile -t targets < <(get_local_upgrades "$db_name")
427 if (( ${#targets[@]} )); then
428 printf >&2 "%s
: upgrading packages
in repository
'%s'\n" "$argv0" "$db_name"
429 #shellcheck disable=SC2086
430 printf '%s\n' "${targets[@]}" | ${AUR_PACMAN_AUTH:-sudo} pacman -S --noconfirm -
437 # vim: set et sw=4 sts=4 ft=sh: