summaryrefslogtreecommitdiff
path: root/asp32.in
diff options
context:
space:
mode:
Diffstat (limited to 'asp32.in')
-rw-r--r--asp32.in375
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 "$@"