Created
February 25, 2020 23:37
-
-
Save AladW/c282bca477038177f1eb9d1ff479b2ce to your computer and use it in GitHub Desktop.
WIP
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# aur-sync - download and build AUR packages automatically | |
[[ -v AUR_DEBUG ]] && set -o xtrace | |
set -o errexit | |
argv0=sync | |
XDG_CACHE_HOME=${XDG_CACHE_HOME:-$HOME/.cache} | |
XDG_CONFIG_HOME=${XDG_CONFIG_HOME:-$HOME/.config} | |
XDG_DATA_HOME=${XDG_DATA_HOME:-$HOME/.local/share} | |
AURDEST=${AURDEST:-$XDG_CACHE_HOME/aurutils/$argv0} | |
PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }' | |
# default arguments | |
build_args=(--clean --syncdeps) | |
build_extra_args=() | |
repo_args=() | |
# default options (enabled) | |
build=1 chkver_depth=2 download=1 view=1 provides=0 graph=1 log_fmt=diff | |
# default options (disabled) | |
rotate=0 update=0 | |
lib32() { | |
awk -v arch="$(uname -m)" '{ | |
if(arch == "i686") { | |
gsub(/^lib32-/,"") | |
gsub(/^gcc-multilib$/,"") | |
} | |
}' | |
} | |
# files: $1 pkgname\tpkgbase $2 pkgname (order by $2) | |
select_pkgbase() { | |
awk 'NR == FNR { | |
map[$1] = $2 | |
next | |
} | |
$1 in map { | |
base = map[$1] | |
# only print pkgbase on first occurrence | |
if (base in seen) { | |
next | |
} else { | |
print base | |
seen[base] | |
} | |
}' "$@" | |
} | |
# fields: $1 pkgname, $2 depends[<>=] | |
tr_ver() { | |
awk -F'[<>=]' '{print $1}' | |
} | |
complement() { | |
# empty set should not return 1 | |
grep -Fxvf "$@" || return $(( $? - 1 )) | |
} | |
order() { | |
cut -f1,2 depends | tr_ver | tsort | |
} | |
trap_exit() { | |
if [[ ! -v AUR_DEBUG ]]; then | |
rm -rf -- "$tmp" "$tmp_view" | |
else | |
printf >&2 'AUR_DEBUG: %s: temporary files at %s\n' "$argv0" "$tmp" | |
printf >&2 'AUR_DEBUG: %s: temporary files at %s\n' "$argv0" "$tmp_view" | |
fi | |
} | |
usage() { | |
plain >&2 'usage: %s [-d repo] [-ALcfnPprRSTuv] pkgname...' "$argv0" | |
exit 1 | |
} | |
source /usr/share/makepkg/util/util.sh | |
source /usr/share/makepkg/util/message.sh | |
source /usr/share/makepkg/util/parseopts.sh | |
if [[ ! -v NO_COLOR ]] && [[ ! -v AUR_DEBUG ]]; then | |
[[ -t 2 ]] && colorize | |
fi | |
# mollyguard for makepkg | |
if (( UID == 0 )) && [[ ! -v AUR_ASROOT ]]; then | |
warning 'aur-%s is not meant to be run as root.' "$argv0" | |
warning 'To proceed anyway, set the %s variable.' 'AUR_ASROOT' | |
exit 1 | |
fi | |
opt_short='B:d:D:AcfLnpPrRSTuv' | |
opt_long=('bind:' 'bind-rw:' 'database:' 'repo:' 'directory:' 'ignore:' | |
'root:' 'makepkg-conf:' 'pacman-conf:' 'chroot' 'continue' | |
'force' 'ignore-arch' 'log' 'no-confirm' 'no-ver' 'no-graph' | |
'no-ver-argv' 'no-view' 'print' 'provides' 'rm-deps' | |
'sign' 'temp' 'upgrades' 'pkgver' 'rebuild' 'rebuild-tree' | |
'build-command:' 'ignore-file:' 'remove' 'provides-from:' | |
'new' 'prevent-downgrade' 'verify' 'format:') | |
opt_hidden=('dump-options' 'allan' 'ignorearch' 'ignorefile:' | |
'noconfirm' 'nover' 'nograph' 'nover-argv' 'noview' | |
'rebuildtree' 'rmdeps' 'gpg-sign') | |
if ! parseopts "$opt_short" "${opt_long[@]}" "${opt_hidden[@]}" -- "$@"; then | |
usage | |
fi | |
set -- "${OPTRET[@]}" | |
unset pkg pkg_i repo repo_p ignore_file | |
while true; do | |
case "$1" in | |
# sync options | |
--allan) | |
rotate=1 ;; | |
--continue) | |
download=0 ;; | |
--format) | |
shift; log_fmt=$1 ;; | |
--ignore) | |
shift; IFS=, read -a pkg -r <<< "$1" | |
pkg_i+=("${pkg[@]}") | |
unset pkg ;; | |
--ignorefile|--ignore-file) | |
shift; ignore_file=$1 ;; | |
--nograph|--no-graph) | |
graph=0 ;; | |
--nover|--no-ver) | |
chkver_depth=0 ;; | |
--nover-argv|--no-ver-argv) | |
chkver_depth=1 ;; | |
--noview|--no-view) | |
view=0 ;; | |
-P|--provides) | |
provides=1 ;; | |
--provides-from) | |
shift; IFS=, read -a repo -r <<< "$1" | |
repo_p+=("${repo[@]}") | |
unset repo ;; | |
-p|--print) | |
build=0 ;; | |
--rebuild) | |
build_args+=(-f); chkver_depth=1 ;; | |
--rebuildtree|--rebuild-tree) | |
build_args+=(-f); chkver_depth=0 ;; | |
-u|--upgrades) | |
update=1 ;; | |
# database options | |
-d|--database|--repo) | |
shift; repo_args+=(-d "$1") ;; | |
--root) | |
shift; repo_args+=(-r "$1") ;; | |
# build options | |
-B|--build-command) | |
shift; build_args+=(--build-command "$1") ;; | |
-c|--chroot) | |
build_args+=(--chroot) ;; | |
-f|--force) | |
build_args+=(--force) ;; | |
--makepkg-conf) | |
shift; build_args+=(--makepkg-conf "$1") ;; | |
--pacman-conf) | |
shift; build_args+=(--pacman-conf "$1") | |
repo_args+=(--pacman-conf "$1") ;; | |
--pkgver) | |
build_args+=(--pkgver) ;; | |
-S|--sign|--gpg-sign) | |
build_args+=(--sign) ;; | |
# build options (devtools) | |
-D|--directory) | |
shift; build_args+=(--directory "$1") ;; | |
--bind) | |
shift; build_args+=(--bind "$1") ;; | |
--bind-rw) | |
shift; build_args+=(--bind-rw "$1") ;; | |
-T|--temp) | |
build_args+=(-T) ;; | |
# build options (makepkg) | |
-A|--ignorearch|--ignore-arch) | |
build_args+=(--ignorearch) ;; | |
-L|--log) | |
build_args+=(--log) ;; | |
-n|--noconfirm|--no-confirm) | |
build_args+=(--noconfirm) ;; | |
-r|--rmdeps|--rm-deps) | |
build_args+=(--rmdeps) ;; | |
# build options (repo-add) | |
-R|--remove) | |
build_args+=(--remove) ;; | |
-v|--verify) | |
build_args+=(--verify) ;; | |
--prevent-downgrade) | |
build_args+=(--prevent-downgrade) ;; | |
--new) | |
build_args+=(--new) ;; | |
# other options | |
--dump-options) | |
printf -- '--%s\n' "${opt_long[@]}" ${AUR_DEBUG+"${opt_hidden[@]}"} | |
printf -- '%s' "${opt_short}" | sed 's/.:\?/-&\n/g' | |
exit ;; | |
--) shift; break ;; | |
esac | |
shift | |
done | |
tmp=$(mktemp -d --tmpdir "aurutils-$argv0.XXXXXXXX") || exit | |
tmp_view=$(mktemp -d --tmpdir "aurutils-$argv0-view.XXXXXXXX") || exit | |
trap 'trap_exit' EXIT | |
# Directory for git checksums (revisions viewed by the user) | |
view_db=$XDG_DATA_HOME/aurutils/view | |
mkdir -p "$view_db" | |
# Append contents of ignore file | |
if [[ -f ${ignore_file=$XDG_CONFIG_HOME/aurutils/sync/ignore} ]]; then | |
while IFS='#' read -r i _; do | |
[[ $i ]] && pkg_i+=("$i") | |
done < "$ignore_file" | |
fi | |
if (( rotate )); then | |
if { hash rot13 && target=$(aur pkglist | shuf -n 1); } 2>/dev/null; then | |
exec bash -c "{ aur \"$argv0\" -c \"$target\" && repo-elephant | rot13; } 2>&1 | rot13" | |
else | |
echo '?'; exit 16 # EBUSY | |
fi | |
fi | |
if ! (( $# + update )); then | |
error '%s: no targets specified' "$argv0" | |
exit 1 | |
fi | |
mkdir -p "$AURDEST" | |
cd_safe "$tmp" | |
# Retrieve path to local repo (#448) | |
aur repo "${repo_args[@]}" --list --status-file=db >db_info | |
{ IFS= read -r db_name | |
IFS= read -r db_root | |
} <db | |
if [[ -w $db_root/$db_name.db ]]; then | |
msg >&2 'Using [%s] repository' "$db_name" | |
else | |
error '%s: %s: permission denied' "$argv0" "$db_root/$db_name.db" | |
exit 13 | |
fi | |
{ if (( $# )); then | |
printf '%s\n' "$@" | |
fi | |
if (( update )); then | |
aur vercmp --quiet <db_info | |
fi | |
} >argv | |
if [[ -s argv ]]; then | |
# shellcheck disable=SC2094 | |
# $1 pkgname $2 depends $3 pkgbase $4 pkgver | |
xargs -a argv -d'\n' aur depends --table >depends | |
else | |
plain >&2 "there is nothing to do" | |
exit | |
fi | |
# $1 pkgname $2 pkgbase $3 pkgver | |
cut -f2 --complement depends | sort -u >pkginfo | |
{ if (( ${#pkg_i[@]} )); then | |
warning "$argv0: ignoring %s package" "${pkg_i[@]}" | |
printf '%s\n' "${pkg_i[@]}" | |
fi | |
# Packages with equal or newer versions are taken as complement | |
# for the queue. If chkver_argv is enabled, packages on the | |
# command-line are excluded from this complement. | |
if (( chkver_depth )); then | |
# note: AUR cannot be queried by pkgbase (FS#57230) | |
cut -f1,3 pkginfo | aur vercmp -p db_info -c >current | |
# shellcheck disable=SC2002 | |
case $chkver_depth in | |
1) cat current | complement argv ;; | |
2) cat current ;; | |
esac | |
fi | |
# Note: this uses pacman's copy of the repo (as used by makepkg -s) | |
if (( ${#repo_p[@]} )); then | |
cut -f1 pkginfo | complement argv | aur-repo-filter "${repo_p[@]/#/--database=}" | |
elif (( provides )); then | |
cut -f1 pkginfo | complement argv | aur repo-filter | |
fi | |
} >filter | |
# pkgname queue (AUR + repos) | |
if order depends >queue_0; then | |
tac queue_0 | lib32 | complement filter >queue_1 | |
else | |
# input contains a loop | |
error '%s: invalid argument' "$argv0" | |
exit 22 | |
fi | |
# pkgbase queue (AUR) | |
cut -f1,2 pkginfo | select_pkgbase - queue_1 >queue | |
if [[ -s queue ]]; then | |
cd_safe "$AURDEST" | |
else | |
plain >&2 "there is nothing to do" | |
exit | |
fi | |
if (( download )); then | |
msg >&2 "Retrieving package files" | |
xargs -a "$tmp"/queue -d'\n' aur fetch -S --results "$tmp"/fetch_results | |
while IFS=: read -r mode rev_old rev path; do | |
path=${path#file://} name=${path##*/} | |
case $mode in | |
clone) | |
;; | |
fetch) | |
if [[ ! -f $view_db/$name ]]; then | |
printf '%s\n' "$rev_old" > "$view_db/$name" | |
fi ;; | |
merge) | |
;; | |
reset) | |
;; | |
esac | |
done < "$tmp"/fetch_results | |
fi | |
if (( graph )); then | |
# Concatenate all SRCINFO files to avoid split aur-graph invocations. | |
while read -r pkg; do | |
[[ $pkg ]] && printf '%s/.SRCINFO\n' "$pkg" | |
done < "$tmp"/queue | xargs -d'\n' cat > "$tmp"/queue_info -- | |
if ! aur graph "$tmp"/queue_info >/dev/null; then | |
error "%s: failed to verify dependency graph" "$argv0" | |
exit 1 | |
fi | |
fi | |
if (( view )); then | |
# Avoid directory prefix in printed paths (#452) | |
viewer() ( cd "$1"; vifm -c 'set vifminfo=' -c 'view!' -c '0' - ) | |
# Link build files in the queue (absolute links) | |
while read -r pkg; do | |
[[ $pkg ]] && printf '%s/%s\0' "$PWD" "$pkg" | |
done < "$tmp"/queue | xargs -0 ln -st "$tmp_view" -- | |
git_log() { | |
local dir=$1 mode=$2 range=$3 | |
git -C "$dir" --no-pager "$mode" --patch --stat "$range" | |
} | |
git_rev() { | |
local dir=$1 obj=$2 | |
git -C "$dir" rev-parse --verify --quiet "$obj" | |
} | |
declare -A heads | |
while read -r pkg; do | |
head=$(git_rev "$pkg" HEAD) | |
heads[$pkg]=$head | |
if read -r view < "$view_db/$pkg" && rev_view=$(git_rev "$pkg" "$view"); then | |
if [[ $rev_view != "$head" ]]; then | |
git_log "$pkg" "$log_fmt" "$rev_view..$head" > "$tmp_view/$pkg.$log_fmt" | |
fi | |
elif [[ $view ]]; then | |
error '%s: %s: invalid revision %s' "$argv0" "$pkg" "$view" | |
exit 22 | |
else | |
: aur_view unavailable | |
fi | |
done < "$tmp"/queue | |
if [[ -v AUR_PAGER ]]; then | |
# shellcheck disable=SC2086 | |
command -- $AUR_PAGER "$tmp_view" | |
else | |
{ # Print patch files | |
find "$tmp_view" -maxdepth 1 -type f | |
# Print build directories in dependency order | |
while read -r name; do | |
[[ $name ]] && find -L "$tmp_view/$name" -maxdepth 1 | |
done < "$tmp"/queue | |
} | viewer "$tmp_view" | |
fi | |
# Update gitsums (viewer exited successfully) | |
while read -r pkg; do | |
# XXX check if heads[$pkg] is defined | |
printf '%s\n' "${heads[$pkg]}" > "$view_db/$pkg" | |
done < "$tmp"/queue | |
fi | |
if (( build )); then | |
aur build --arg-file "$tmp"/queue --database "$db_name" --root "$db_root" \ | |
"${build_args[@]}" "${build_extra_args[@]}" | |
else | |
while read -r name; do | |
[[ $name ]] && printf '%s/%s\n' "$PWD" "$name" | |
done < "$tmp"/queue | |
fi | |
# vim: set et sw=4 sts=4 ft=sh: |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment