summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--Makefile3
-rw-r--r--mirror.115
-rw-r--r--mirror.559
-rw-r--r--mirror.sh40
5 files changed, 102 insertions, 17 deletions
diff --git a/.gitignore b/.gitignore
index 9eddb41..9705bf1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,2 @@
mirror
-*.list
+*.mirror
diff --git a/Makefile b/Makefile
index d45757c..15661a0 100644
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/mirror.1 b/mirror.1
index a7af5b8..d595da6 100644
--- a/mirror.1
+++ b/mirror.1
@@ -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)
diff --git a/mirror.sh b/mirror.sh
index d3bb652..88ed524 100644
--- a/mirror.sh
+++ b/mirror.sh
@@ -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