diff options
Diffstat (limited to 'asp32.in')
-rw-r--r-- | asp32.in | 375 |
1 files changed, 375 insertions, 0 deletions
diff --git a/asp32.in b/asp32.in new file mode 100644 index 0000000..b5471d8 --- /dev/null +++ b/asp32.in @@ -0,0 +1,375 @@ +#!/bin/bash + +ASP_VERSION=@ASP_VERSION@ +ARCH_GIT_REPOS=(packages64 community64 packages32) + +OPT_ARCH=$(uname -m) +OPT_FORCE=0 +: "${ASPROOT:=${XDG_CACHE_HOME:-$HOME/.cache}/asp32}" +: "${ASPCACHE:=$ASPROOT/cache}" + +m4_include(util.inc.sh) +m4_include(remote.inc.sh) +m4_include(package.inc.sh) +m4_include(archweb.inc.sh) + +usage() { + cat<<EOF +asp32 $ASP_VERSION [OPTIONS...] {COMMAND} ... + +Manage build sources for Arch packages. + +Options: + -a ARCH Specify an architecture other than the host's + -f Allow files to be overwritten + -h Show this help + -V Show package version + +Package Commands: + checkout NAME... Create a mutable git repository for packages + difflog NAME Show revision history with diffs + export NAME... Export packages + list-all List all known packages + list-arches NAME... List architectures for packages + list-local List tracked packages + list-repos NAME... List repos for packages + log NAME Show revision history + ls-files NAME List files for package + shortlog NAME Show revision history in short form + show NAME [FILE] Show the PKGBUILD or other FILE + untrack NAME... Remove a package from the local repository + update [NAME...] Update packages (update all tracked if none specified) + +Meta Commands: + disk-usage Show amount of disk used by locally tracked packages + gc Cleanup and optimize the local repository + help Show this help + set-git-protocol PROTO Change git protocol (one of: git, http, https) + +EOF +} + +__require_argc() { + local min max argc=$2 + + case $1 in + *-) + min=${1%-} + ;; + *-*) + IFS=- read -r min max <<<"$1" + ;; + *) + min=$1 max=$1 + ;; + esac + + if (( min == max && argc != min )); then + log_fatal '%s expects %d args, got %d' "${FUNCNAME[1]#action__}" "$min" "$argc" + elif (( max && argc > max )); then + log_fatal '%s expects at most %d args, got %d' "${FUNCNAME[1]#action__}" "$max" "$argc" + elif (( argc < min )); then + log_fatal '%s expects at least %d args, got %d' "${FUNCNAME[1]#action__}" "$min" "$argc" + fi +} + +version() { + printf 'asp %s\n' "$ASP_VERSION" +} + +update_all() { + local r + + for r in "${ARCH_GIT_REPOS[@]}"; do + log_info "updating remote '%s'" "$r" + remote_update "$r" + done +} + +update_local_branches() { + local r=0 + + while read -r branchname; do + git branch -qf "$branchname" "refs/remotes/$branchname" || r=1 + done < <(git branch --no-color) + + return "$r" +} + +update_remote_branches() { + local refspecs=() remote pkgname + declare -A refspec_map + + if (( $# == 0 )); then + update_all + return + fi + + # map packages to remotes + for pkgname; do + package_init -n "$pkgname" remote || return 1 + refspec_map["$remote"]+=" packages/$pkgname" + done + + # update each remote all at once + for remote in "${!refspec_map[@]}"; do + read -ra refspecs <<<"${refspec_map["$remote"]}" + remote_update_refs "$remote" "${refspecs[@]}" + done +} + +update_packages() { + update_remote_branches "$@" && update_local_branches +} + +initialize() { + local remote + + umask 0022 + + export GIT_DIR=$ASPROOT/.git + + if [[ ! -f $ASPROOT/.asp ]]; then + git init -q "$ASPROOT" || return 1 + for remote in "${ARCH_GIT_REPOS[@]}"; do + if [[ "${remote}" = *64 ]]; then + git remote add "$remote" "https://git.archlinux.org/svntogit/${remote%64}.git" || return 1 + elif [[ "${remote}" = *32 ]]; then + git remote add "$remote" "https://git.archlinux32.org/archlinux32/${remote%32}.git" || return 1 + fi + done + + touch "$ASPROOT/.asp" || return 1 + fi + + if [[ ! -d $ASPCACHE ]]; then + mkdir -p "$ASPCACHE" || return 1 + fi + + return 0 +} + +dump_packages() { + local remote refspecs dumpfn + + case $1 in + all) + dumpfn=remote_get_all_refs + ;; + local) + dumpfn=remote_get_tracked_refs + ;; + *) + die 'internal error: invalid dump type: "%s"' "$1" + ;; + esac + + for remote in "${ARCH_GIT_REPOS[@]}"; do + "$dumpfn" "$remote" refspecs + if [[ $refspecs ]]; then + printf '%s\n' "${refspecs[@]##*/}" + fi + done | sort +} + +list_local() { + dump_packages 'local' +} + +list_all() { + dump_packages 'all' +} + +shortlog() { + package_log "$@" "${FUNCNAME[0]}" +} + +log() { + package_log "$@" "${FUNCNAME[0]}" +} + +difflog() { + package_log "$@" "${FUNCNAME[0]}" +} + +gc() { + git gc --prune=all +} + +untrack() { + local pkgname=$1 remote + + package_init -n "$pkgname" remote || return 1 + + remote_untrack "$remote" "$pkgname" + package_untrack "$pkgname" "$remote" +} + +disk_usage() { + local usage + read -r usage _ < <(du -sh "$ASPROOT") + + log_info 'Using %s on disk.' "$usage" +} + +action__checkout() { + __require_argc 1- $# + map package_checkout "$@" +} + +action__difflog() { + __require_argc 1 $# + difflog "$1" +} + +action__disk-usage() { + __require_argc 0 $# + disk_usage +} + +action__export() { + __require_argc 1- $# + map package_export "$@" +} + +action__gc() { + __require_argc 0 $# + gc +} + +action__help() { + __require_argc 0 $# + usage +} + +action__list-all() { + __require_argc 0 $# + list_all +} + +action__list-arches() { + __require_argc 1- $# + map package_get_arches "$@" +} + +action__list-local() { + __require_argc 0 $# + list_local +} + +action__list-repos() { + __require_argc 1- $# + map package_get_repos "$@" +} + +action__log() { + __require_argc 1 $# + log "$1" +} + +action__shortlog() { + __require_argc 1 $# + shortlog "$1" +} + +action__show() { + __require_argc 1-2 $# + package_show_file "$@" +} + +action__untrack() { + __require_argc 1- $# + map untrack "$@" +} + +action__update() { + update_packages "$@" +} + +action__ls-files() { + __require_argc 1 $# + + package_list_files "$1" +} + +action__set-git-protocol() { + __require_argc 1 $# + + case $1 in + git|http|https) + ;; + *) + log_fatal 'invalid protocol: %s' "$1" + ;; + esac + + for remote in "${ARCH_GIT_REPOS[@]}"; do + if [[ "${remote}" = *64 ]]; then + git remote set-url "$remote" "$1://git.archlinux.org/svntogit/${remote%64}.git" + elif [[ "${remote}" = *32 ]]; then + git remote set-url "$remote" "$1://git.archlinux32.org/archlinux32/${remote%32}.git" + fi + done +} + +dispatch_action() { + local candidates + + [[ $1 ]] || log_fatal 'no action specified (use -h for help)' + + # exact match + if declare -F "action__$1" &>/dev/null; then + "action__$1" "${@:2}" + return + fi + + # prefix match + mapfile -t candidates < <(compgen -A function "action__$1") + case ${#candidates[*]} in + 0) + log_fatal 'unknown action: %s' "$1" + ;; + 1) + "${candidates[0]}" "${@:2}" + return + ;; + *) + { + printf "error: verb '%s' is ambiguous; possibilities:" "$1" + printf " '%s'" "${candidates[@]#action__}" + echo + } >&2 + return 1 + ;; + esac +} + +initialize || log_fatal 'failed to initialize asp repository in %s' "$ASPROOT" + +while getopts ':a:fhV' flag; do + case $flag in + a) + OPT_ARCH=$OPTARG + ;; + f) + OPT_FORCE=1 + ;; + h) + usage + exit 0 + ;; + V) + version + exit 0 + ;; + \?) + log_fatal "invalid option -- '%s'" "$OPTARG" + ;; + :) + log_fatal "option '-%s' requires an argument" "$OPTARG" + ;; + esac +done +shift $(( OPTIND - 1 )) + +dispatch_action "$@" |