diff options
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | mirror.1 | 15 | ||||
-rw-r--r-- | mirror.5 | 59 | ||||
-rw-r--r-- | mirror.sh | 40 |
5 files changed, 102 insertions, 17 deletions
@@ -1,2 +1,2 @@ mirror -*.list +*.mirror @@ -3,6 +3,7 @@ BINDIR?=$(PREFIX)/bin DATADIR?=$(PREFIX)/share MANDIR?=$(DATADIR)/man MAN1DIR?=$(MANDIR)/man1 +MAN5DIR?=$(MANDIR)/man5 LIBDIR?=$(PREFIX)/lib SYSDDIR?=$(LIBDIR)/systemd/system USERSDIR?=$(LIBDIR)/sysusers.d @@ -19,12 +20,14 @@ clean: install: all install -m755 -Dt $(DESTDIR)$(BINDIR) mirror install -m644 -Dt $(DESTDIR)$(MAN1DIR) mirror.1 + install -m644 -Dt $(DESTDIR)$(MAN5DIR) mirror.5 install -m644 -Dt $(DESTDIR)$(SYSDDIR) mirror.{timer,service} install -m644 -Dt $(DESTDIR)$(USERSDIR) mirror.conf uninstall: rm -f $(DESTDIR)$(BINDIR)/mirror rm -f $(DESTDIR)$(MAN1DIR)/mirror.1 + rm -f $(DESTDIR)$(MAN5DIR)/mirror.5 rm -f $(DESTDIR)$(SYSDDIR)/mirror.{timer,service} rm -f $(DESTDIR)$(USERSDIR)/mirror.conf @@ -1,19 +1,19 @@ -.TH mirror 1 "2023-12-28" +.TH mirror 1 "2023-12-01" .SH NAME mirror \- copies remote git repositories in bulk .SH SYNOPSIS .SY mirror -.RI [ list ] +.RI [ repositories ] .SY mirror\ -v .YS .SH DESCRIPTION This script will read -.I list -file for paths to git repositories, clone them in bare mirror mode or update existing mirrors as necessary. If not -provided -.I list +.I repositories +file for paths or addresses to git repositories, clone them in a bare mirror mode or update existing mirrors as +necessary. If not provided +.I repositories will default to -.B repositories.list +.B repositories.mirror in the current working directory. .P With @@ -25,4 +25,5 @@ Exit status is zero if all repositories in the list have been mirrored successfu option was used. If one or more mirrors fail or an unknown command-line option is provided, a non-zero status is returned. .SH SEE ALSO +.BR mirror (5), .BR git (1) diff --git a/mirror.5 b/mirror.5 new file mode 100644 index 0000000..0e8fef3 --- /dev/null +++ b/mirror.5 @@ -0,0 +1,59 @@ +.TH mirror 5 "2023-12-01" +.SH NAME +mirror \- file format for listing sources for git repository mirrors +.SH SYNTAX +Each file contains number of lines: +.P +.RS +.RI [ type ] +.I source +.RE +.P +Any leading whitespace is ignored. Lines that begin with +.B # +are ignored. Lines are split into +.I type +and +.I source +using regular shell word splitting mechanism. If first word is not recognized as a +.IR type , +then it is assumed to be part of the +.I source +and gets prepended to the rest of the line with a single space character as a separator. Because of this behaviour it is +recommended to use an explicit +.I type +if +.I source +contains whitespace. +.SH SUPPORTED TYPES +.I Type +is recognized if it matches any of the following types. If it does not, +.B repo +is assumed. +.SS repo +Repository is mirrored directly from a +.IR source . +The +.I source +must be compatible with +.BR git-clone (1) +command. +.SS gitolite +First, +.I source +is queried assuming gitolite info command is available via SSH. Each repository that user has read permissions to is +then mirrored. Addresses of the repositories are generated by appending +.BI / path +to +.IR source. +The +.I source +must be compatible with both +.BR ssh (1) +and +.BR git-clone (1) +commands. +.SH SEE ALSO +.BR mirror (1), +.BR git-clone (1), +.BR ssh (1) @@ -6,11 +6,39 @@ _version() { _usage() { - echo "Usage: $0 [-v] [list]" + echo "Usage: $0 [-v] [repositories]" exit 1 } >&2 +_interpret() { + while read type_ source_; do + case "${type_}" in + gitolite) _gitolite "${source_}" ;; + repo) echo "${source_}" ;; + '#'*) : ;; + *) { echo -n "${type_}"; [ -n "${source_}" ] && echo -n " ${source_}"; echo; } ;; + esac + done +} + + +_gitolite() { + { ssh -n "$1" info -p || return 1; } | awk -F'\t' '/^\s*R/{ print "'"$1"'/"$2 }' +} + + +_mirror() { + local failed=0 + while read repo; do + if ! _update "${repo}"; then + failed=1 + fi + done + return ${failed} +} + + _path() { local path="$(url %h%p $1)" case "${path}" in @@ -40,12 +68,6 @@ while getopts :v opt; do esac done shift $(( ${OPTIND} - 1 )) -list="${1:-repositories.list}" +list="${1:-repositories.mirror}" test -f "${list}" || exit 1 -failed=0 -while read repo; do - if ! _update "${repo}"; then # TODO: Parallelize this without DDOSing the hosts - failed=1 - fi -done <"${list}" -exit ${failed} +_interpret <"${list}" | _mirror |