[
  {
    "path": ".gitignore",
    "content": "asp\nasp.1\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (c) 2014 Dave Reisner\n\nPermission is hereby granted, free of charge, to any person\nobtaining a copy of this software and associated documentation\nfiles (the \"Software\"), to deal in the Software without\nrestriction, including without limitation the rights to use,\ncopy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the\nSoftware is furnished to do so, subject to the following\nconditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\nOF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\nHOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\nWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\nOTHER DEALINGS IN THE SOFTWARE.\n\n"
  },
  {
    "path": "Makefile",
    "content": "PACKAGE_NAME = asp\n\nVERSION := $(shell git describe --dirty 2>/dev/null)\n\nPREFIX = /usr/local\n\nBINPROGS = \\\n\tasp\n\nMANPAGES = \\\n\tman/asp.1\n\nBASH_COMPLETION = \\\n\tshell/bash-completion\n\nZSH_COMPLETION = \\\n\tshell/zsh-completion\n\nINCLUDES = \\\n\tarchweb.inc.sh \\\n\tpackage.inc.sh \\\n\tremote.inc.sh \\\n\tutil.inc.sh\n\nall: $(BINPROGS) $(MANPAGES)\n\nV_GEN = $(_v_GEN_$(V))\n_v_GEN_ = $(_v_GEN_0)\n_v_GEN_0 = @echo \"  GEN     \" $@;\n\nedit = $(V_GEN) m4 -P $@.in | sed 's/@ASP_VERSION@/$(VERSION)/' >$@ && chmod go-w,+x $@\n\n%: %.in $(INCLUDES)\n\t$(edit)\n\ndoc: $(MANPAGES)\nman/%: man/%.txt Makefile\n\t$(V_GEN) a2x \\\n\t\t-d manpage \\\n\t\t-f manpage \\\n\t\t-a manversion=\"$(PACKAGE_NAME) $(VERSION)\" \\\n\t\t-a manmanual=\"$(PACKAGE_NAME) manual\" $<\n\ncheck: $(BINPROGS)\n\t@for f in $(BINPROGS); do bash -O extglob -n $$f; done\n\nlint: $(BINPROGS)\n\t@for f in $(BINPROGS); do shellcheck $$f; done\n\nclean:\n\t$(RM) $(BINPROGS) $(MANPAGES)\n\ninstall: all\n\tinstall -dm755 $(DESTDIR)$(PREFIX)/bin $(DESTDIR)$(PREFIX)/share/man/man1\n\tinstall -m755 $(BINPROGS) $(DESTDIR)$(PREFIX)/bin\n\tinstall -m644 $(MANPAGES) $(DESTDIR)$(PREFIX)/share/man/man1\n\tinstall -Dm644 $(BASH_COMPLETION) $(DESTDIR)$(PREFIX)/share/bash-completion/completions/asp\n\tinstall -Dm644 $(ZSH_COMPLETION) $(DESTDIR)$(PREFIX)/share/zsh/site-functions/_asp\n\n.PHONY: all clean install\n"
  },
  {
    "path": "README.md",
    "content": "> [!CAUTION]\n> **THIS REPO IS ARCHIVED**\n> \n> In the context of the [git migration](https://archlinux.org/news/git-migration-announcement/) using `asp` has been deprecated in favor of `pkgctl` or plain `git`.\n> \n> For details see the respective wiki entry: https://wiki.archlinux.org/title/Arch_build_system#Retrieve_PKGBUILD_source\n\n---\n\n# asp\n\n`asp` is a tool to manage the build source files used to create Arch Linux\npackages. It replaces the `abs` tool, offering more up to date sources (via the\nsvntogit repositories) and uses a sparse checkout model to conserve diskspace.\nThis probably won't be interesting to users who want a full checkout (for\nwhatever reason that may be).\n\n# Setup\n\nNone! Though, it should be noted that the `ASPROOT` environment variable\nwill control where `asp` keeps its local git repo. By default, this is\n`${XDG_CACHE_HOME:-$HOME/.cache}/asp`.\n\n# Examples\n\nGet the source files for some packages:\n\n~~~\nasp export pacman testing/systemd extra/pkgfile\n~~~\n\nGet a fully functional git checkout of a single package:\n\n~~~\nasp checkout pkgfile\n~~~\n\nList the repositories a package has been pushed to:\n\n~~~\nasp list-repos pacman\n~~~\n\n"
  },
  {
    "path": "archweb.inc.sh",
    "content": "archweb_get_pkgbase() {\n  local pkgbase\n\n  pkgbase=$(curl -LGs 'https://archlinux.org/packages/search/json/' --data-urlencode \"q=$1\" |\n      jq -r --arg pkgname \"$1\" 'limit(1; .results[] | select(.pkgname == $pkgname).pkgbase)')\n  [[ $pkgbase ]] || return\n\n  printf '%s\\n' \"$pkgbase\"\n}\n"
  },
  {
    "path": "asp.in",
    "content": "#!/bin/bash\n\nASP_VERSION=@ASP_VERSION@\nARCH_GIT_REPOS=(packages community)\n\nOPT_ARCH=$(uname -m)\n: \"${ASPROOT:=${XDG_CACHE_HOME:-$HOME/.cache}/asp}\"\n: \"${ASPCACHE:=$ASPROOT/cache}\"\n\nm4_include(util.inc.sh)\nm4_include(remote.inc.sh)\nm4_include(package.inc.sh)\nm4_include(archweb.inc.sh)\n\nusage() {\n  cat<<EOF\nasp $ASP_VERSION [OPTIONS...] {COMMAND} ...\n\nManage build sources for Arch packages.\n\nOptions:\n  -a           ARCH        Specify an architecture other than the host's\n  -h                       Show this help\n  -V                       Show package version\n\nPackage Commands:\n  checkout           NAME...     Create a mutable git repository for packages\n  difflog            NAME        Show revision history with diffs\n  export             NAME...     Export packages\n  list-all                       List all known packages\n  list-arches        NAME...     List architectures for packages\n  list-local                     List tracked packages\n  list-repos         NAME...     List repos for packages\n  log                NAME        Show revision history\n  ls-files           NAME        List files for package\n  shortlog           NAME        Show revision history in short form\n  show               NAME [FILE] Show the PKGBUILD or other FILE\n  untrack            NAME...     Remove a package from the local repository\n  update             [NAME...]   Update packages (update all tracked if none specified)\n\nMeta Commands:\n  disk-usage                     Show amount of disk used by locally tracked packages\n  gc                             Cleanup and optimize the local repository\n  help                           Show this help\n  set-git-protocol   PROTO       Change git protocol (one of: git, http, https)\n\nEOF\n}\n\n__require_argc() {\n  local min max argc=$2\n\n  case $1 in\n    *-)\n      min=${1%-}\n      ;;\n    *-*)\n      IFS=- read -r min max <<<\"$1\"\n      ;;\n    *)\n      min=$1 max=$1\n      ;;\n  esac\n\n  if (( min == max && argc != min )); then\n    log_fatal '%s expects %d args, got %d' \"${FUNCNAME[1]#action__}\" \"$min\" \"$argc\"\n  elif (( max && argc > max )); then\n    log_fatal '%s expects at most %d args, got %d' \"${FUNCNAME[1]#action__}\" \"$max\" \"$argc\"\n  elif (( argc < min )); then\n    log_fatal '%s expects at least %d args, got %d' \"${FUNCNAME[1]#action__}\" \"$min\" \"$argc\"\n  fi\n}\n\nversion() {\n  printf 'asp %s\\n' \"$ASP_VERSION\"\n}\n\nupdate_all() {\n  local r\n\n  for r in \"${ARCH_GIT_REPOS[@]}\"; do\n    log_info \"updating remote '%s'\" \"$r\"\n    remote_update \"$r\"\n  done\n}\n\nupdate_local_branches() {\n  local r=0\n\n  while read -r branchname; do\n    git branch -qf \"$branchname\" \"refs/remotes/$branchname\" || r=1\n  done < <(git branch --no-color)\n\n  return \"$r\"\n}\n\nupdate_remote_branches() {\n  local refspecs=() remote pkgname\n  declare -A refspec_map\n\n  if (( $# == 0 )); then\n    update_all\n    return\n  fi\n\n  # map packages to remotes\n  for pkgname; do\n    package_init -n \"$pkgname\" remote || return 1\n    refspec_map[\"$remote\"]+=\" packages/$pkgname\"\n  done\n\n  # update each remote all at once\n  for remote in \"${!refspec_map[@]}\"; do\n    read -ra refspecs <<<\"${refspec_map[\"$remote\"]}\"\n    remote_update_refs \"$remote\" \"${refspecs[@]}\"\n  done\n}\n\nupdate_packages() {\n  update_remote_branches \"$@\" && update_local_branches\n}\n\ninitialize() {\n  local remote url\n\n  umask 0022\n\n  export GIT_DIR=$ASPROOT/.git\n\n  if [[ ! -f $ASPROOT/.asp ]]; then\n    git init -q \"$ASPROOT\" || return 1\n    for remote in \"${ARCH_GIT_REPOS[@]}\"; do\n      git remote add \"$remote\" \"https://github.com/archlinux/svntogit-$remote.git\" || return 1\n    done\n\n    touch \"$ASPROOT/.asp\" || return 1\n  else\n    # migrate from git.archlinux.org to github.com\n    for remote in \"${ARCH_GIT_REPOS[@]}\"; do\n      url=$(git remote get-url \"$remote\")\n      # https://github.blog/2021-09-01-improving-git-protocol-security-github/\n      if [[ $url = *'git.archlinux.org'* ]] || [[ $url = *'git://github.com'* ]]; then\n        git remote set-url \"$remote\" \"https://github.com/archlinux/svntogit-$remote.git\"\n      fi\n    done\n  fi\n\n  if [[ ! -d $ASPCACHE ]]; then\n    mkdir -p \"$ASPCACHE\" || return 1\n  fi\n\n  return 0\n}\n\ndump_packages() {\n  local remote refspecs dumpfn\n\n  case $1 in\n    all)\n      dumpfn=remote_get_all_refs\n      ;;\n    local)\n      dumpfn=remote_get_tracked_refs\n      ;;\n    *)\n      log_fatal 'BUG: invalid dump type: \"%s\"' \"$1\"\n      ;;\n  esac\n\n  for remote in \"${ARCH_GIT_REPOS[@]}\"; do\n    \"$dumpfn\" \"$remote\" refspecs\n    if [[ $refspecs ]]; then\n      printf '%s\\n' \"${refspecs[@]##*/}\"\n    fi\n  done | sort\n}\n\nlist_local() {\n  dump_packages 'local'\n}\n\nlist_all() {\n  dump_packages 'all'\n}\n\nshortlog() {\n  package_log \"$@\" \"${FUNCNAME[0]}\"\n}\n\nlog() {\n  package_log \"$@\" \"${FUNCNAME[0]}\"\n}\n\ndifflog() {\n  package_log \"$@\" \"${FUNCNAME[0]}\"\n}\n\ngc() {\n  git gc --prune=all\n}\n\nuntrack() {\n  local pkgname=$1 remote\n\n  package_init -n \"$pkgname\" remote || return 1\n\n  remote_untrack \"$remote\" \"$pkgname\"\n  package_untrack \"$pkgname\" \"$remote\"\n}\n\ndisk_usage() {\n  local usage\n  read -r usage _ < <(du -sh \"$ASPROOT\")\n\n  log_info 'Using %s on disk.' \"$usage\"\n}\n\naction__checkout() {\n  __require_argc 1- $#\n  map package_checkout \"$@\"\n}\n\naction__difflog() {\n  __require_argc 1 $#\n  difflog \"$1\"\n}\n\naction__disk-usage() {\n  __require_argc 0 $#\n  disk_usage\n}\n\naction__export() {\n  __require_argc 1- $#\n  map package_export \"$@\"\n}\n\naction__gc() {\n  __require_argc 0 $#\n  gc\n}\n\naction__help() {\n  __require_argc 0 $#\n  usage\n}\n\naction__list-all() {\n  __require_argc 0 $#\n  list_all\n}\n\naction__list-arches() {\n  __require_argc 1- $#\n  map package_get_arches \"$@\"\n}\n\naction__list-local() {\n  __require_argc 0 $#\n  list_local\n}\n\naction__list-repos() {\n  __require_argc 1- $#\n  map package_get_repos \"$@\"\n}\n\naction__log() {\n  __require_argc 1 $#\n  log \"$1\"\n}\n\naction__shortlog() {\n  __require_argc 1 $#\n  shortlog \"$1\"\n}\n\naction__show() {\n  __require_argc 1-2 $#\n  package_show_file \"$@\"\n}\n\naction__untrack() {\n  __require_argc 1- $#\n  map untrack \"$@\"\n}\n\naction__update() {\n  update_packages \"$@\"\n}\n\naction__ls-files() {\n  __require_argc 1 $#\n\n  package_list_files \"$1\"\n}\n\naction__set-git-protocol() {\n  __require_argc 1 $#\n\n  case $1 in\n    git|http|https)\n      ;;\n    *)\n      log_fatal 'invalid protocol: %s' \"$1\"\n      ;;\n  esac\n\n  for remote in \"${ARCH_GIT_REPOS[@]}\"; do\n    git remote set-url \"$remote\" \"$1://github.com/archlinux/svntogit-$remote.git\"\n  done\n}\n\ndispatch_action() {\n  local candidates\n\n  [[ $1 ]] || log_fatal 'no action specified (use -h for help)'\n\n  # exact match\n  if declare -F \"action__$1\" &>/dev/null; then\n    \"action__$1\" \"${@:2}\"\n    return\n  fi\n\n  # prefix match\n  mapfile -t candidates < <(compgen -A function \"action__$1\")\n  case ${#candidates[*]} in\n    0)\n      log_fatal 'unknown action: %s' \"$1\"\n      ;;\n    1)\n      \"${candidates[0]}\" \"${@:2}\"\n      return\n      ;;\n    *)\n      {\n        printf \"error: verb '%s' is ambiguous; possibilities:\" \"$1\"\n        printf \" '%s'\" \"${candidates[@]#action__}\"\n        echo\n      } >&2\n      return 1\n      ;;\n  esac\n}\n\ninitialize || log_fatal 'failed to initialize asp repository in %s' \"$ASPROOT\"\n\ncase $1 in\n  --version)\n    version\n    exit 0\n    ;;\n  --help)\n    usage\n    exit 0\n    ;;\nesac\n\nwhile getopts ':a:hV' flag; do\n  case $flag in\n    a)\n      OPT_ARCH=$OPTARG\n      ;;\n    h)\n      usage\n      exit 0\n      ;;\n    V)\n      version\n      exit 0\n      ;;\n    \\?)\n      log_fatal \"invalid option -- '%s'\" \"$OPTARG\"\n      ;;\n    :)\n      log_fatal \"option '-%s' requires an argument\" \"$OPTARG\"\n      ;;\n  esac\ndone\nshift $(( OPTIND - 1 ))\n\ndispatch_action \"$@\"\n"
  },
  {
    "path": "man/asp.1.txt",
    "content": "/////\nvim:set ts=4 sw=4 syntax=asciidoc noet:\n/////\nasp(1)\n======\n\nName\n----\nasp - Manage Arch Linux build sources\n\nSynopsis\n--------\nasp [options] command [targets...]\n\nDescription\n-----------\nManage the version-controlled sources for the build scripts used to create Arch\nLinux packages. This program provides a thin wrapper over the svntogit\nrepositories hosted at https://github.com/archlinux. It aims to provide a\nreplacement for abs which favors a sparse checkout.\n\nCommands\n--------\nThe following commands are understood:\n\n*checkout* 'TARGET'...::\n\tCreate a new git repository containing the full source and history\n\tfor each of the given targets. The new repository will pull from the\n\trepository in '$ASPROOT' and must be updated separately after using\n\t'asp update'. If a checkout occurs on the same filesystem as '$ASPROOT',\n\tmost of the metadata can be hard linked, making this a relatively cheap\n\tcopy.\n\n*difflog* 'TARGET'::\n\tShow the full revision history of the target, with file diffs.\n\n*disk-usage*::\n\tReport the approximate disk usage for locally tracked packages.\n\n*export* 'TARGET'...::\n\tDump the build source files for each target into a directory of the\n\ttarget's name in '$PWD'. Targets can be specified simply as 'package' to\n\tcheck out the source files at HEAD, or in 'repository/package' format\n\tto checkout the source files which were used to push the 'package' which\n\texists in 'repository'.\n\n*gc*::\n\tPerform housekeeping procedures on the local repo, optimizing and\n\tcompacting the repo to free disk space.\n\n*help*::\n\tDisplay the command line usage and exit.\n\n*list-all*::\n\tList all known packages in the repositories.\n\n*list-arches* 'TARGET'...::\n\tList the architectures the given targets are available for.\n\n*list-local*::\n\tList all packages which are tracked locally.\n\n*list-repos* 'TARGET'...::\n\tList the repositories the given targets exist in.\n\n*log* 'TARGET'::\n\tShow the revision history of the target.\n\n*ls-files* 'TARGET'::\n\tList source files for the given target.\n\n*set-git-protocol* 'PROTOCOL'::\n\tSet the protocol used to communicate with the remote git repositories. Must\n\tbe one of 'git', 'http', or 'https'.\n\n*shortlog* 'TARGET'::\n\tShow a condensed revision history of the target.\n\n*show* 'TARGET' ['FILE']::\n\tShow the file content of the target, which may be in the format 'package'\n\tor 'repository/package'. If an additional 'file' argument is provided, attempt\n\tto display that file rather than the PKGBUILD. If the repository is not\n\tspecified, the file will be shown at the most recent revision (which may be\n\tnewer than what is in the repositories).\n\n*untrack* 'TARGET'...::\n\tRemove a remote tracking branch from the local repository. Disk usage for\n\tthe removed package(s) may not be freed until garbage collection has taken\n\tplace.\n\n*update* ['TARGET'...]::\n\tFor each target, if the package is not known to the local repository,\n\tattempt to track it. If the package is tracked, update the package\n\tto the newest version. If no targets are provided, all locally known\n\tpackages will be updated.\n\nOptions\n-------\n*-a* 'architecture'::\n\tWhen relevant, specify an architecture other than that of the current host.\n\n*-h*::\n\tPrint a short help text and exit.\n\n*-V*::\n\tPrint a short version string and exit.\n\nEnvironment\n-----------\n*ASPROOT*::\n\tDetermines where the metadata is stored for locally tracked packages. Defaults\n\tto '`${XDG_CACHE_HOME:-$HOME/.cache}/asp`'.\n\n*ASPCACHE*::\n\tDetermines where cached data is stored. Defaults to '$ASPROOT/cache'. Data in\n\tthis directory can always be safely deleted.\n\nAuthors\n-------\nDave Reisner <d@falconindy.com>\n"
  },
  {
    "path": "package.inc.sh",
    "content": "package_resolve() {\n  local pkgbase\n\n  [[ $pkgname ]] || log_fatal 'BUG: package_resolve called without pkgname var set'\n\n  if package_find_remote \"$1\" \"$2\"; then\n    return 0\n  fi\n\n  if pkgbase=$(archweb_get_pkgbase \"$1\") && package_find_remote \"$pkgbase\" \"$2\"; then\n    log_info '%s is part of package %s' \"$1\" \"$pkgbase\"\n    pkgname=$pkgbase\n    return 0\n  fi\n\n  log_error 'unknown package: %s' \"$pkgname\"\n  return 1\n}\n\npackage_init() {\n  local do_update=1\n\n  if [[ $1 = -n ]]; then\n    do_update=0\n    shift\n  fi\n\n  pkgname=$1\n\n  package_resolve \"$pkgname\" \"$2\" || return\n\n  (( do_update )) || return 0\n\n  remote_is_tracking \"${!2}\" \"$pkgname\" ||\n      remote_update_refs \"${!2}\" \"packages/$pkgname\"\n}\n\npackage_find_remote() {\n  pkgname=$1\n\n  # fastpath, checks local caches only\n  for r in \"${ARCH_GIT_REPOS[@]}\"; do\n    if remote_is_tracking \"$r\" \"$pkgname\"; then\n      printf -v \"$2\" %s \"$r\"\n      return 0\n    fi\n  done\n\n  # slowpath, needs to talk to the remote\n  for r in \"${ARCH_GIT_REPOS[@]}\"; do\n    if remote_has_package \"$r\" \"$pkgname\"; then\n      printf -v \"$2\" %s \"$r\"\n      return 0\n    fi\n  done\n\n  return 1\n}\n\npackage_log() {\n  local method=$2 logargs remote\n  pkgname=$1\n\n  package_init \"$pkgname\" remote || return\n\n  case $method in\n    shortlog)\n      logargs=('--pretty=oneline')\n      ;;\n    difflog)\n      logargs=('-p')\n      ;;\n    log)\n      logargs=()\n      ;;\n    *)\n      log_fatal 'BUG: unknown log method: %s' \"$method\"\n      ;;\n  esac\n\n  git log \"${logargs[@]}\" \"$remote/packages/$pkgname\" -- trunk/\n}\n\npackage_show_file() {\n  local file=${2:-PKGBUILD} remote repo subtree\n  pkgname=$1\n\n  if [[ $pkgname = */* ]]; then\n    IFS=/ read -r repo pkgname <<<\"$pkgname\"\n  fi\n\n  package_init \"$pkgname\" remote || return\n\n  if [[ $file != */* ]]; then\n    if [[ $repo ]]; then\n      subtree=repos/$repo-$OPT_ARCH/\n    else\n      subtree=trunk/\n    fi\n  fi\n\n  git show \"remotes/$remote/packages/$pkgname:$subtree$file\"\n}\n\npackage_list_files() {\n  local remote subtree=trunk\n  pkgname=$1\n\n  if [[ $pkgname = */* ]]; then\n    IFS=/ read -r repo pkgname <<<\"$pkgname\"\n  fi\n\n  package_init \"$pkgname\" remote || return\n\n  if [[ $repo ]]; then\n    subtree=repos/$repo-$OPT_ARCH\n  fi\n\n\n  git ls-tree -r --name-only \"remotes/$remote/packages/$pkgname\" \"$subtree\" |\n      awk -v \"prefix=$subtree/\" 'sub(prefix, \"\")'\n}\n\npackage_export() {\n  local remote repo arch=$OPT_ARCH arches subtree=trunk\n  pkgname=$1\n\n  if [[ $pkgname = */* ]]; then\n    IFS=/ read -r repo pkgname <<<\"$pkgname\"\n  fi\n\n  package_init \"$pkgname\" remote || return\n\n  if [[ $repo ]]; then\n    mapfile -t arches < <(package_get_arches \"$pkgname\")\n    if (( ${#arches[*]} == 1 )) && [[ ${arches[0]} = any ]]; then\n      arch=any\n    fi\n    subtree=repos/$repo-$arch\n  fi\n\n  if ! git show \"remotes/$remote/packages/$pkgname:$subtree/\" &>/dev/null; then\n    if [[ $repo ]]; then\n      log_error \"package '%s' not found in repo '%s-%s'\" \"$pkgname\" \"$repo\" \"$OPT_ARCH\"\n      return 1\n    else\n      log_error \"package '%s' has no trunk directory!\" \"$pkgname\"\n      return 1\n    fi\n  fi\n\n  mkdir \"$pkgname\" || return\n\n  log_info 'exporting %s:%s' \"$pkgname\" \"$subtree\"\n  git archive --format=tar \"remotes/$remote/packages/$pkgname\" \"$subtree/\" |\n      tar --transform \"s,^$subtree,$pkgname,\" -xf - \"$subtree/\"\n}\n\npackage_checkout() {\n  local remote\n  pkgname=$1\n\n  package_init \"$pkgname\" remote || return\n\n  git show-ref -q \"refs/heads/$remote/packages/$pkgname\" ||\n      git branch -qf --no-track {,}\"$remote/packages/$pkgname\"\n\n  quiet_git clone \\\n    --shared \\\n    --single-branch \\\n    --branch \"$remote/packages/$pkgname\" \\\n    --config \"pull.rebase=true\" \\\n    \"$ASPROOT\" \"$pkgname\" || return\n}\n\npackage_get_repos_with_arch() {\n  local remote=$2 path arch repo\n  pkgname=$1\n\n  while read -r path; do\n    path=${path##*/}\n    repo=${path%-*}\n    arch=${path##*-}\n    printf '%s %s\\n' \"$repo\" \"$arch\"\n  done < <(git ls-tree --name-only \"remotes/$remote/packages/$pkgname\" repos/)\n}\n\npackage_get_arches() {\n  local remote arch\n  declare -A arches\n  pkgname=$1\n\n  package_init \"$pkgname\" remote || return\n\n  while read -r _ arch; do\n    arches[\"$arch\"]=1\n  done < <(package_get_repos_with_arch \"$pkgname\" \"$remote\")\n\n  printf '%s\\n' \"${!arches[@]}\"\n}\n\npackage_get_repos() {\n  local remote repo\n  declare -A repos\n  pkgname=$1\n\n  package_init \"$pkgname\" remote || return\n\n  while read -r repo _; do\n    repos[\"$repo\"]=1\n  done < <(package_get_repos_with_arch \"$pkgname\" \"$remote\")\n\n  printf '%s\\n' \"${!repos[@]}\"\n}\n\npackage_untrack() {\n  local remote=$2\n  pkgname=$1\n\n  if git show-ref -q \"refs/heads/$remote/packages/$pkgname\"; then\n    git branch -D \"$remote/packages/$pkgname\"\n  fi\n}\n"
  },
  {
    "path": "remote.inc.sh",
    "content": "__remote_refcache_update() {\n  local remote=$1 cachefile=$ASPCACHE/remote-$remote refs\n\n  refs=$(git ls-remote \"$remote\" 'refs/heads/packages/*') ||\n      log_fatal \"failed to update remote $remote\"\n\n  printf '%s' \"$refs\" |\n      awk '{ sub(/refs\\/heads\\/packages\\//, \"\", $2); print $2 }' >\"$cachefile\"\n}\n\n__remote_refcache_is_stale() {\n  local now cachetime cachefile=$1 ttl=3600\n\n  printf -v now '%(%s)T' -1\n\n  # The cache is stale if we've exceeded the TTL.\n  if ! cachetime=$(stat -c %Y \"$cachefile\" 2>/dev/null) ||\n      (( now > (cachetime + ttl) )); then\n    return 0\n  fi\n\n  # We also consider the cache to be stale when this script is newer than the\n  # cache. This allows upgrades to asp to implicitly wipe the cache and not\n  # make any guarantees about the file format.\n  if (( $(stat -c %Y \"${BASH_SOURCE[0]}\" 2>/dev/null) > cachetime )); then\n    return 0\n  fi\n\n  return 1\n}\n\n__remote_refcache_get() {\n  local remote=$1 cachefile=$ASPCACHE/remote-$remote\n\n  if __remote_refcache_is_stale \"$cachefile\"; then\n    __remote_refcache_update \"$remote\"\n  fi\n\n  mapfile -t \"$2\" <\"$cachefile\"\n}\n\nremote_get_all_refs() {\n  local remote=$1\n\n  __remote_refcache_get \"$remote\" \"$2\"\n}\n\nremote_has_package() {\n  local remote=$1 pkgname=$2 refs\n\n  remote_get_all_refs \"$remote\" refs\n\n  in_array \"$pkgname\" \"${refs[@]}\"\n}\n\nremote_is_tracking() {\n  local repo=$1 pkgname=$2\n\n  git show-ref -q \"$repo/packages/$pkgname\"\n}\n\nremote_get_tracked_refs() {\n  local remote=$1\n\n  mapfile -t \"$2\" < \\\n    <(git for-each-ref --format='%(refname:strip=3)' \"refs/remotes/$remote\")\n}\n\nremote_update_refs() {\n  local remote=$1 refspecs=(\"${@:2}\")\n\n  quiet_git fetch \"$remote\" \"${refspecs[@]}\"\n}\n\nremote_update() {\n  local remote=$1 refspecs\n\n  remote_get_tracked_refs \"$remote\" refspecs\n\n  # refuse to update everything\n  [[ -z $refspecs ]] && return 0\n\n  remote_update_refs \"$remote\" \"${refspecs[@]}\"\n}\n\nremote_untrack() {\n  local remote=$1 pkgname=$2\n\n  if git show-ref -q \"refs/remotes/$remote/packages/$pkgname\"; then\n    git branch -dr \"$remote/packages/$pkgname\"\n  fi\n}\n"
  },
  {
    "path": "shell/bash-completion",
    "content": "#!/bin/bash\n\nin_array() {\n  for _ in \"${@:2}\"; do\n    [[ $_ = \"$1\" ]] && return 0\n  done\n  return 1\n}\n\n_asp() {\n  local verb='' i cur prev comps\n\n  _get_comp_words_by_ref cur prev\n\n  # top level commands\n  local -A verbs=(\n    [ALL_PACKAGES]='checkout difflog export list-arches list-repos log shortlog show ls-files'\n    [LOCAL_PACKAGES]='untrack update'\n    [NONE]='disk-usage gc help list-all list-local'\n    [PROTO]='set-git-protocol'\n  )\n\n  # flags\n  local -A opts=(\n    [UNKNOWN]='-a'\n    [NONE]='-h -V'\n  )\n\n  if in_array \"$prev\" ${opts[UNKNOWN]}; then\n    return 0\n  fi\n\n  if [[ $cur = -* ]]; then\n    COMPREPLY=( $(compgen -W '${opts[*]}' -- \"$cur\") )\n    return 0\n  fi\n\n  # verb completion\n  for (( i = 0; i < ${#COMP_WORDS[@]}; ++i )); do\n    word=${COMP_WORDS[i]}\n    if in_array \"$word\" ${verbs[ALL_PACKAGES]}; then\n      verb=$word\n      comps=$(ASP_GIT_QUIET=1 \\asp list-all | sed 's,.*/,,')\n      break\n    elif in_array \"$word\" ${verbs[LOCAL_PACKAGES]}; then\n      verb=$word\n      comps=$(ASP_GIT_QUIET=1 \\asp list-local | sed 's,.*/,,')\n      break\n    elif in_array \"$word\" ${verbs[PROTO]}; then\n      verb=$word\n      comps='git http https'\n      break\n    elif in_array \"$word\" ${verbs[NONE]}; then\n      verb=$word\n      break\n    fi\n  done\n\n  # sub-verb completion\n  case $verb in\n    show)\n      if (( i < ${#COMP_WORDS[@]} - 2 )); then\n        comps=$(ASP_GIT_QUIET=1 \\asp ls-files \"${COMP_WORDS[i+1]}\" 2>/dev/null)\n      fi\n      ;;\n    '')\n      comps=${verbs[*]}\n      ;;\n  esac\n\n  if [[ $comps ]]; then\n    COMPREPLY=( $(compgen -W '$comps' -- \"$cur\") )\n  fi\n}\n\ncomplete -F _asp asp\n"
  },
  {
    "path": "shell/zsh-completion",
    "content": "#compdef asp\n\n_asp_command() {\n  local -a _asp_cmds\n  _asp_cmds=(\n      'checkout'\n      'difflog'\n      'export'\n      'gc'\n      'disk-usage'\n      'help'\n      'list-all'\n      'list-arches'\n      'list-local'\n      'list-repos'\n      'ls-files'\n      'log'\n      'shortlog'\n      'show'\n      'set-git-protocol'\n      'update'\n      'untrack'\n      )\n\n  if (( CURRENT == 1 )); then\n    _describe -t commands 'asp command' _asp_cmds || compadd \"$@\"\n  else\n    local curcontext=\"$curcontext\"\n    cmd=\"${${_asp_cmds[(r)$words[1]:*]%%:*}}\"\n    if (( $#cmd )); then\n      if (( $+functions[_asp_$cmd] )); then\n        _asp_$cmd\n      else\n        _message \"no more options\"\n      fi\n    else\n      _message \"unknown asp command: $words[1]\"\n    fi\n  fi\n}\n\n_arguments \\\n  '-a[architecture]' \\\n  '-h[print help and exit]' \\\n  '-V[print version and exit]' \\\n  '*::asp command:_asp_command'\n\n# vim: set et sw=2 ts=2 ft=zsh :\n"
  },
  {
    "path": "util.inc.sh",
    "content": "log_meta() {\n  # shellcheck disable=SC2059\n  printf \"$1 $2\\\\n\" \"${@:3}\"\n}\n\nlog_error() {\n  log_meta 'error:' \"$@\" >&2\n}\n\nlog_fatal() {\n  log_error \"$@\"\n  exit 1\n}\n\nlog_warning() {\n  log_meta 'warning:' \"$@\" >&2\n}\n\nlog_info() {\n  log_meta '==>' \"$@\"\n}\n\nmap() {\n  local map_r=0\n  for _ in \"${@:2}\"; do\n    \"$1\" \"$_\" || map_r=1\n  done\n  return $map_r\n}\n\nin_array() {\n  local item needle=$1\n\n  for item in \"${@:2}\"; do\n    [[ $item = \"$needle\" ]] && return 0\n  done\n\n  return 1\n}\n\nquiet_git() {\n  [[ $ASP_GIT_QUIET ]] && set -- \"$1\" -q \"${@:2}\"\n\n  command git \"$@\"\n}\n"
  }
]