Merge pull request #1016 from VorpalBlade/feature/3rd-party-completion
[aurutils.git] / lib / aur-fetch--mirror
blobef659204e2eb044ec334e758af942f87c554f11e
1 #!/bin/bash
2 set -o errexit
3 [[ -v AUR_DEBUG ]] && set -o xtrace
4 #argv0=fetch--mirror
5 XDG_CACHE_HOME=${XDG_CACHE_HOME:-$HOME/.cache}
6 AUR_MIRROR=${AUR_MIRROR:-https://github.com/archlinux/aur}
7 AUR_MIRROR_TTL=${AUR_MIRROR_TTL:-300}
8 AUR_ROOT=${AUR_ROOT:-$XDG_CACHE_HOME/aur}
9 startdir=$PWD
10 local_clones=0
12 if [[ $1 = '--lclone' ]]; then
13 local_clones=1
14 shift
17 # --------------------------------------------------
18 # Step 1. Create a sparse checkout of the AUR mirror
19 git_active_remotes() {
20 git config --get-all remote.origin.fetch | awk -F'[/:]' '{print $3}'
23 # XXX: this includes refs/heads (which we do not use) but unlike
24 # git-config this accepts multiple arguments in one call
25 git_set_branches() {
26 git remote set-branches origin --add main # ensure at least 1 remote
27 sort -u | xargs -d '\n' git remote set-branches origin
30 git_ls_remote_ttl() {
31 local cachetime now ttl=$AUR_MIRROR_TTL
32 printf -v now '%(%s)T' -1
34 if ! cachetime=$(stat -c %Y "$1" 2>/dev/null) || (( now > (cachetime + ttl) )); then
35 git ls-remote origin 'refs/heads/*' | awk -F/ '{print $3}' >"$1"
39 exec {fd}< "$AUR_ROOT"
40 { flock --wait 5 "$fd" || exit 1
42 # Shallow clone
43 [[ ! -d $AUR_ROOT ]] && git clone --depth=1 --bare "$AUR_MIRROR" "$AUR_ROOT"
44 cd "$AUR_ROOT"
46 # Keep a refcache to filter out packages which are not in AUR. This is
47 # includes unlisted packages (unlike `aur pkglist --pkgbase`)
48 git_ls_remote_ttl 'remote-pkgbase'
50 # Retrieve list of active remotes
51 mapfile -t active_remotes < <(git_active_remotes | grep -v 'main')
53 # Only consider AUR targets
54 mapfile -t target_remotes < <(printf '%s\n' "$@" | grep -Fxf 'remote-pkgbase')
56 # Set remote branches as union of active remotes and arguments. If '*' is set
57 # instead, `git fetch origin` in $AUR_ROOT will pull in the entire history.
58 printf '%s\n' "${target_remotes[@]}" "${active_remotes[@]}" | git_set_branches
60 # Retrieve objects
61 git fetch origin "${target_remotes[@]}"
63 # Resetting branches is only needed when .git/config contains both refs/heads
64 # and refs/remotes/origin, i.e. when using git-clone. `--lclone` uses git-init
65 # and refspec manipulation instead.
66 # for b in "${target_remotes[@]}"; do
67 # git branch --force "$b" origin/"$b"
68 # done
69 } >&2
71 # ------------------------------------------------------------
72 # Step 2. Propagate each branch in the mirror to a local clone
73 (( ! local_clones )) && exit
74 results=()
76 git_srcdest_origin() {
77 local refspec=refs/remotes/origin/$1
79 git config remote.origin.fetch "+$refspec:$refspec"
80 git fetch --quiet
81 git checkout -B master "$refspec"
84 for b in "${target_remotes[@]}"; do
85 cd "$startdir"
87 # XXX: "Cloning into an existing directory is only allowed if the
88 # directory is empty"
89 if [[ ! -d $b/.git ]] && mkdir "$b"; then
90 cd "$b"
91 git init
92 git remote add origin "$AUR_ROOT"
94 # Compared to git clone --local, using $refspec as both source and
95 # destination allows updates from `git-fetch` in $AUR_ROOT to be
96 # directly visible in local clones. $AUR_ROOT does not require
97 # local branches or refs/heads for this to work.
98 git_srcdest_origin "$b"
100 # Export results to aur-fetch
101 head=$(git rev-parse --verify --quiet HEAD)
102 results+=("$b:$head")
103 fi >&2
104 done
106 # The lock is only released here, because we do not want an instance to modify
107 # AUR_ROOT while local git-clones are still underway. Additionally, local clones
108 # use cp(1) and are thus a cheap operation. See --local in git-clone(1).
109 exec {fd}<&-
111 if (( ${#results[@]} )); then
112 printf '%s\n' "${results[@]}"