From 50aaa96b078e6dbc47c21355d34ef1da83ab20a8 Mon Sep 17 00:00:00 2001 From: Tom Ryder Date: Fri, 4 Aug 2017 17:32:36 +1200 Subject: Initial version with Makefile and README --- Makefile | 9 ++++++++ README.markdown | 27 ++++++++++++++++++++++ watch-git-tags | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+) create mode 100644 Makefile create mode 100644 README.markdown create mode 100755 watch-git-tags diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..90bfa3b --- /dev/null +++ b/Makefile @@ -0,0 +1,9 @@ +.POSIX: +.SUFFIXES: +.PHONY: all install clean +PREFIX = /usr/local +all: +install: + mkdir -p -- $(PREFIX)/bin + cp -- watch-git-tags $(PREFIX)/bin +clean: diff --git a/README.markdown b/README.markdown new file mode 100644 index 0000000..fb49318 --- /dev/null +++ b/README.markdown @@ -0,0 +1,27 @@ +`watch-vcs-tags` +================ + +Scripts that given a list of repository roots as arguments look for new tags +available on remote systems, and report the repository name and a tab-indented +list of new tags, if any: + +Presently only `git` is implemented (well, published). This is all implemented +in POSIX `sh`, but does require a `mktemp(1)` implementation that supports the +`-d` option to create temporary directories. + + $ watch-git-tags ~/.local/src/ed/vim + /home/tom/.local/src/ed/vim + v8.0.0858 + +If you keep a list of your repository paths in a file like ~/.watch-git-tags, +you could put this in a `crontab(5)` task to email you new tags: + + xargs watch-git-tags < /home/tom/.watch-git-tags-repos + +License +------- + +Copyright (c) [Tom Ryder][1]. Distributed under an [MIT License][2]. + +[1]: https://sanctum.geek.nz/ +[2]: https://www.opensource.org/licenses/MIT diff --git a/watch-git-tags b/watch-git-tags new file mode 100755 index 0000000..ccccd00 --- /dev/null +++ b/watch-git-tags @@ -0,0 +1,72 @@ +#!/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 -- cgit v1.2.3