A small bash script to be run from your .bashrc. This is practical for multi-homed users - like myself - to keep ssh authorized keys, bookmarks, bash settings, aliases, etc. in sync amongst different accounts.
#!/bin/bash # # CVSHOME - small BASH script to be run from your .bashrc # this is practical for multi-homed users - like myself - # to keep ssh authorized keys, bookmarks, bash settings, # aliases, etc. in sync amongst different accounts. # # GPLv2 by Erno Rigo <mcree AT tricon DOT hu> # # you should place these exports in an external # file if you are planning to keep cvshome itself # in its own CVS repository! export CVS_RSH=ssh # enter your favorite RSH here export CVSROOT=:ext:tricon.hu/var/lib/cvs # enter your CVSROOT here... I'm combinig ssh-keychain with this so it's quite convenient - for me 8) export CVSHOME_ROOT=~mcree/.cvshome_root # local scratchpad export CVSHOME_FILES="/home/mcree/.bashrc /home/mcree/.crontab" # files to keep in cvs export CVSHOME_SAFEFILES="/home/mcree/.ssh/authorized_keys2" # files to keep in cvs, keeps user asked before upgrades export CVSHOME_KEY="trallalala" # cvs repository "key" - you should share this amongst your homes export CVSHOME_EDITOR="$EDITOR" # your favourite editor (used for conflict management) #export CVSHOME_DEBUG="yes" # comment out to disable DEBUG messages (recommended) export CVSHOME_NOTICE="yes" # comment out to disable NOTICE messages (not recommended) ###################################################################################### # BEWARE - DO NOT CROSS THIS LINE # cvshome_debug() { if [ $CVSHOME_DEBUG ]; then echo `date`" cvshome: DEBUG: "$@ fi } cvshome_fatal() { echo `date`" cvshome: FATAL: "$@ } cvshome_notice() { if [ $CVSHOME_NOTICE ]; then echo `date`" cvshome: NOTICE: "$@ fi } cvshome_update_base() { #copy files if they differ cvshome_debug "searching for repo changes..." for file in $CVSHOME_FILES; do if ! cmp "$file" "$CVSHOME_ROOT"/repo/"$file" > /dev/null; then cvshome_debug "changed in repo: $file" cp "$CVSHOME_ROOT"/repo/"$file" $file touch "$CVSHOME_ROOT"/need_commit fi done #take account of safe files for file in $CVSHOME_SAFEFILES; do if ! cmp "$file" "$CVSHOME_ROOT"/repo/"$file" > /dev/null; then cvshome_debug "changed in repo (SAFE): $file" mkdir -p "$CVSHOME_ROOT"/safe cp --parents "$file" "$CVSHOME_ROOT"/safe touch "$CVSHOME_ROOT"/need_commit fi done } cvshome_update_repo() { #copy files if they differ cvshome_debug "searching for local changes..." for file in $CVSHOME_FILES $CVSHOME_SAFEFILES; do if ! cmp "$file" "$CVSHOME_ROOT"/repo/"$file" > /dev/null; then cvshome_debug "changed locally: $file" cp --parents $file "$CVSHOME_ROOT"/repo touch "$CVSHOME_ROOT"/need_commit fi done } cvshome_update() { if [ -f "$CVSHOME_ROOT"/update_failed ]; then cvshome_fatal "last update failed, need manual cleanup!" return 0 fi cvshome_update_repo cvshome_debug "uptading from repo..." pushd "$CVSHOME_ROOT"/repo > /dev/null updateres=`cvs -Q update -A 2>&1` if [ ! -z "$updateres" ]; then cvshome_fatal "cannot update: $updateres" touch "$CVSHOME_ROOT"/update_failed return 0 fi popd > /dev/null cvshome_update_base cvshome_commit } cvshome_commit() { if [ -f "$CVSHOME_ROOT"/need_commit ]; then cvshome_debug "commiting..." pushd "$CVSHOME_ROOT"/repo > /dev/null cvs -Q commit -m `date +%s` popd > /dev/null rm -f "$CVSHOME_ROOT"/need_commit else cvshome_debug "no need to commit." fi } cvshome_bg() { cvshome_debug "background init..." mkdir -p "$CVSHOME_ROOT" export CVSHOME_REPO="cvshome_"$CVSHOME_KEY if [ ! -d "$CVSHOME_ROOT"/repo ]; then cvshome_debug "no local copy present trying to checkout..." pushd "$CVSHOME_ROOT" > /dev/null cvs -Q checkout -d repo -D now "$CVSHOME_REPO" 2>/dev/null 1>/dev/null popd > /dev/null fi if [ ! -d "$CVSHOME_ROOT"/repo ]; then cvshome_debug "no existing repository... creating one for you" mkdir -p "$CVSHOME_ROOT"/"$CVSHOME_REPO" for file in $CVSHOME_FILES $CVSHOME_SAFEFILES; do cvshome_debug "initial copy: $file" cp --parents $file "$CVSHOME_ROOT"/"$CVSHOME_REPO" done cvshome_debug "importing..." pushd "$CVSHOME_ROOT"/"$CVSHOME_REPO" > /dev/null cvs -Q import -m "initial" "$CVSHOME_REPO" "$CVSHOME_REPO" "initial" popd > /dev/null cvshome_debug "checking out..." pushd "$CVSHOME_ROOT" > /dev/null cvs -Q checkout -d repo -D now "$CVSHOME_REPO" popd > /dev/null if [ ! -d "$CVSHOME_ROOT"/repo ]; then cvshome_fatal "cannot checkout: cvs checkout -d repo -D now $CVSHOME_REPO" return 0 fi rm -rf "$CVSHOME_ROOT"/"$CVSHOME_REPO" cvshome_notice "new repository was created as $CVSHOME_REPO" fi cvshome_update } cvshome_prompt() { while read -p "$1 ["`echo "$2" | tr ' ' '/' `"] " ans; do for pos in $2; do if [ "$pos" == "$ans" ]; then echo "$ans" return; fi done done } cvshome_init() { # check for CVS conflicts if [ -f "$CVSHOME_ROOT"/update_failed ]; then cvshome_debug "previous update failed, searching for conflicts..." corrfile=`mktemp` echo "no" > $corrfile; exec 3<&0 find "$CVSHOME_ROOT"/repo -regex ".*/Entries" | while read file; do grep -h "/[^/]*/[^/]*/[^+/]*+[^/]*/" "$file" | while read entry; do realdir=`dirname "$file"` realdir=`dirname "$realdir"` realfile="$realdir/"`echo "$entry" | cut -f2 -d '/'` ans=`cvshome_prompt "CVS conflict detected in: $realfile. Correct it?" "yes no" <&3` if [ "$ans" == "yes" ]; then $CVSHOME_EDITOR "$realfile" <&3 else echo "yes" > $corrfile; fi done done exec 3>&- if [ `cat $corrfile` == "no" ]; then rm -f "$CVSHOME_ROOT"/update_failed fi rm -f $corrfile fi # check for changed SAFE files if [ -d "$CVSHOME_ROOT"/safe ]; then cvshome_debug "searching for changed SAFE files..." pushd "$CVSHOME_ROOT"/safe >/dev/null exec 3<&0 find . -type f | while read file; do diff -ruN "/$file" "$CVSHOME_ROOT"/repo/"$file" ans=`cvshome_prompt "SAFE file changed: $file. Update locally?" "yes no abort" <&3` if [ "$ans" == "abort" ]; then touch "$CVSHOME_ROOT"/update_failed elif [ "$ans" == "no" ]; then cvshome_notice "forcing local file version to CVS" cp --parents "/$file" "$CVSHOME_ROOT"/repo/"$file" touch "$CVSHOME_ROOT"/need_commit else cvshome_notice "upgrading file from CVS" rm -f "$CVSHOME_ROOT"/safe/"$file" fi done exec 3>&- popd >/dev/null fi } # actions requiring user interaction cvshome_init # start background processing... for faster prompts 8) cvshome_bg &