Skip to content

Instantly share code, notes, and snippets.

@ilyaevseev
Last active August 29, 2015 14:12
Show Gist options
  • Save ilyaevseev/d34ade484e6782d71db1 to your computer and use it in GitHub Desktop.
Save ilyaevseev/d34ade484e6782d71db1 to your computer and use it in GitHub Desktop.
Backup filelist to Mercurial repository.

configs2git

Copies selected configs to Git or Hg repository. It is better than track entire /etc with tons of garbage.

Example:

Prepare once:

echo '
/boot/grub/grub.cfg
/etc/apt/sources.list.d/
/etc/fstab
/etc/group
/etc/passwd
/etc/shadow
/etc/rc.local
/root/.ssh/
' > myconfigs.lst

git init myconfigs

Do periodically:

configs2git myconfigs.lst myconfigs/

Mercurial support

When script is named as configs2hg, it tries to use Mercurial instead of Git.

Todo

  • support wildcards
  • helpers for OpenVZ and LXC
#!/bin/sh
#
# configs2git
# configs2git -- backup filelist to Git/Mercurial repository.
#
# Required utilities: hg or git, rsync, mail (with "admins" alias)
#
# Written at Dec-2014 by [email protected]
# Distributed as public domain.
#
INSTALL_ME_SO='
cd /usr/local/bin &&
wget -qO configs2git https://gist.githubusercontent.com/ilyaevseev/d34ade484e6782d71db1/raw/79ecef988737c5f1860a1c4482ce194619279f17/configs2git &&
chmod +x configs2git
'
ROOTDIR="/"
DELMODE="warn"
MYNAME="$(basename $0)"
Err() {
echo "$@" | mail -s "$MYNAME" admins
logger -p user.err -t "$MYNAME" -s "$@"
}
Fail() { Err "$@"; exit 1; }
case "$MYNAME" in
*git* ) BASESYS="git" ;;
*hg* | *mercurial* ) BASESYS="hg" ;;
* ) Fail "my name is not configs2hg nor configs2git" ;;
esac
HgFail() { Fail "$BASESYS $@ failed in $DESTDIR"; }
Doit() {
test -n "$VERBOSE" && echo "$@"
test -n "$DRY_RUN" || "$@"
}
while test $# != 0; do
case "$1" in
--trace ) shift; set -x ;;
--dry ) shift; VERBOSE=1 ; DRY_RUN=1 ;;
--verbose ) shift; VERBOSE=1 ;;
--rootdir ) shift; test $# = 0 && Fail "missing --rootdir value"; ROOTDIR="$1"; shift ;;
--delmode ) shift; test $# = 0 && Fail "missing --delmode value"; DELMODE="$1"; shift ;;
-* ) Fail "wrong cmdline: $1" ;;
* ) break ;;
esac
done
test $# = 2 || Fail "usage: $0 filelist destdir"
FILELIST="$1"
DESTDIR="$2"
test -d "$DESTDIR/.$BASESYS" || Fail "Missing subdir $DESTDIR/.$BASESYS"
NOT_EMPTY=
while read fn; do
fn=${fn%%#*} # ..strip comments
test "$fn" = "" && continue # ..skip empty lines. todo!!! trim spaces???
NOT_EMPTY=1
# todo??? support wildcards!!!
src="$ROOTDIR/$fn"
dst="$DESTDIR/$fn"
if test -e "$dst" -a -e "$src"; then
srctype="$(LANG=C stat -c '%F' "$src" 2>/dev/null)"
dsttype="$(LANG=C stat -c '%F' "$dst" 2>/dev/null)"
test "$srctype" = "$dsttype" || Fail "type changed: src:$src:$srctype dst:$dst:$dsttype"
fi
if test -d "$src/."; then
mkdir -p "$dst" || Fail "mkdir $dst"
Doit rsync -auq --delete --numeric-ids "$src/" "$dst/" || Fail "rsync $src $dst"
# todo!!! use cp instead of rsync???
elif test -e "$src"; then
Doit mkdir -p "$(dirname $dst)" || Fail "mkdir dirname $dst"
Doit cp -auf "$src" "$dst" || Fail "cp $src $dst"
else
case "$DELMODE" in
stop ) Fail "missing file $src" ;;
skip ) ;;
warn ) Err "missing file $src" ;;
rm ) Doit rm -rf "$dst" ;;
* ) Fail "wrong DELMODE value: $DELMODE" ;;
esac
fi
done < $FILELIST
test -z "$NOT_EMPTY" && Fail "nothing readed from $FILELIST"
cd "$DESTDIR"
"$BASESYS" status >/dev/null || HgFail "status"
msg="$MYNAME: autocommit at $(date '+%Y-%m-%d_%H:%M:%S')"
case "$BASESYS" in
hg ) hg status | grep -q '' || exit # ..nothing to do
Doit hg addremove || HgFail "addremove"
Doit hg commit -m "$msg" || HgFail "commit"
;;
git ) git status | grep -qi 'nothing to commit' && exit
Doit git add -A || HgFail "add -A"
Doit git commit -am "$msg" || HgFail "commit"
;;
esac
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment