aboutsummaryrefslogblamecommitdiff
path: root/watch-git-tags
blob: ccccd00b7f3d5393068f45cd1e4b97ef6c859d1b (plain) (tree)







































































                                                                              
#!/bin/sh
self=watch-git-tags

# List sorted local tags
lt() {
    git tag -l |
        LC_COLLATE=C sort
}

# List sorted remote tags
rt() {
    git ls-remote -qt |
        awk '!/\^\{\}$/{print substr($2,11)}' |
        LC_COLLATE=C sort
}

# Create a temporary directory with name in $td, and handle POSIX-ish traps to
# remove it when the script exits; requires mktemp(1) (not POSIX)
td=$(mktemp -d) || exit
cleanup() {
    [ -n "$td" ] || return
    rm -fr -- "$td"
}
for sig in EXIT HUP INT TERM ; do
    # shellcheck disable=SC2064
    trap "cleanup $sig" "$sig"
done

# Use current directory if no other arguments
[ "$#" -gt 0 ] || set -- .

# Iterate through each repo in a subshell in parallel
for repo ; do (

    # Make a temporary directory with a hash in its name for uniqueness
    df=$(printf %s "$repo" | sed s:/:_:g)
    cs=$(printf %s "$repo" | cksum)
    sd=$td/$df.${cs%% *}
    mkdir -- "$sd" || exit

    # Step in and write repo path to file
    cd -- "$sd" || exit
    printf '%s\n' "$repo" > path || exit

    # Write local and remote tags to files
    (
        cd -- "$repo" || exit
        lt "$repo" > "$sd"/a || exit
        rt "$repo" > "$sd"/b
    ) ||
    exit

    # Write new tags to file
    LC_COLLATE=C comm -13 -- [ab] > new

) & done

# Wait for each of those to finish
wait

# Iterate through the temp dirs in order
for dir in "$td"/* ; do (
    cd -- "$dir" || exit 0

    # Look for non-zero "new" files (at least one new tag)
    [ -s new ] || exit 0

    # Print repository path and new tags
    sed '1!s/^/\t/' -- path new
    exit 1

) ; done