This might be useful if you keep your settings (.bashrc
,
.subversion/config
, etc.) outside the home directory, like in a
Subversion repository. Just copy the following script to the repository
directory corresponding to $HOME and run
/path/to/make-links.sh
to create symlinks from ~
to each file in the repository,
recursively.
If you don't want to use meld to see
differences, just change the diff
variable near the top of the
code.
Edit 2 : Now actually does something useful if the target file
already exists or the target directory does not exist.
#!/bin/sh
#
# $Id: make-links.sh 1870 2009-11-10 08:56:35Z vengmark $
#
# NAME
# make-links.sh - Make symlinks to all user settings in repository
#
# SYNOPSIS
# make-links.sh [options]
#
# OPTIONS
# -v,--verbose Verbose output
# -d Specify the source and target directories for the symlinks
#
# EXAMPLE
# /path/to/make-links.sh -d ~/settings/user ~
#
# Create links in the home directory based on files in ~/settings/user
#
# /path/to/make-links.sh -v
#
# Create links in / based on files in the directory of make-links.sh
#
# DESCRIPTION
# If the file in the source directory doesn't exist in the target directory,
# a symlink is created directly.
# If the file exists, or the target directory does not exist, the user is
# given options to continue.
#
# BUGS
# Email bugs to victor dot engmark at gmail dot com. Please include the
# output of running this script in verbose mode (-v).
#
# COPYRIGHT AND LICENSE
# Copyright (C) 2008-2009 Victor Engmark
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
# Output error message
error()
{
if [ -z " $2 " ]
then
error_code = $EX_UNKNOWN
else
error_code = $2
fi
echo " $1 " > &2
exit $error_code
}
usage()
{
error "Usage: ${ cmdname } [-v|--verbose] [-d source target]" $EX_USAGE
}
verbose_echo()
{
if [ $verbose ]
then
echo " $* "
fi
}
# Use for mandatory directory checks
# $1 is the directory path
# $2 is the (optional) error message
directory_exists()
{
if [ ! -d $1 ]
then
error "No such directory ' ${ 1 } '
$2 " $EX_NO_SUCH_DIR
fi
}
# Make sure an executable is available
# $1 is the path to the executable
# $2 is the (optional) error message
executable_exists()
{
if [ ! -x $1 ]
then
error "No such executable ' ${ 1 } '
$2 " $EX_NO_SUCH_EXEC
fi
}
ifs_original = " $IFS " # Reset when done
IFS = "
" # Make sure paths with spaces don't make any trouble when looping
PATH = "/usr/bin:/bin"
cmdname = ` basename $0 `
directory = $( dirname $( readlink -f $0 ))
diff = /usr/bin/meld
source_base = " ${ directory } /home/ $( whoami ) /"
target_base = " $HOME "
# Exit codes from /usr/include/sysexits.h, as recommended by
# http://www.faqs.org/docs/abs/HTML/exitcodes.html
EX_OK = 0 # successful termination
EX_USAGE = 64 # command line usage error
EX_DATAERR = 65 # data format error
EX_NOINPUT = 66 # cannot open input
EX_NOUSER = 67 # addressee unknown
EX_NOHOST = 68 # host name unknown
EX_UNAVAILABLE = 69 # service unavailable
EX_SOFTWARE = 70 # internal software error
EX_OSERR = 71 # system error (e.g., can't fork)
EX_OSFILE = 72 # critical OS file missing
EX_CANTCREAT = 73 # can't create (user) output file
EX_IOERR = 74 # input/output error
EX_TEMPFAIL = 75 # temp failure; user is invited to retry
EX_PROTOCOL = 76 # remote error in protocol
EX_NOPERM = 77 # permission denied
EX_CONFIG = 78 # configuration error
# Custom errors
EX_UNKNOWN = 1
EX_NO_SUCH_DIR = 91
EX_NO_SUCH_EXEC = 92
# Process parameters
until [ $# -eq 0 ]
do
case $1 in
-v | --verbose )
verbose = 1
shift
;;
-d )
if [ -z " $2 " ] || [ -z " $3 " ]
then
usage_error
fi
source_base = $2
target_base = $3
shift 3
;;
* )
# Unknown parameter
usage
;;
esac
done
verbose_echo "Running $cmdname at ` date ` ."
# Make sure the directory paths don't end with a slash
source_base = " ${ source_base %\/ } "
target_base = " ${ target_base %\/ } "
# Preliminary checks
directory_exists " $source_base "
directory_exists " $target_base "
verbose_echo "Source directory: ' ${ source_base } '"
verbose_echo "Target directory: ' ${ target_base } '"
# Find files excluding .svn directories
for source_path in ` find " $source_base " -mindepth 1 -type f | grep -v "/.svn/" `
do
target_path = " ${ target_base }${ source_path # ${ source_base }} "
target_dir = " $( dirname " ${ target_path } " ) "
unset replace_file
unset create_dir
verbose_echo ""
verbose_echo "Source file: \" ${ source_path } \" ."
verbose_echo "Target file: \" ${ target_path } \" ."
# Trivial case
if [ -L " $target_path " ]
then
verbose_echo " \" ${ target_path } \" is already a symlink; skipping."
continue
fi
# File exists
if [ -f " $target_path " ]
then
# Make sure we skip or replace in the end
while ! expr " $replace_file " : "^[SsRr]$" > /dev/null
do
echo " \" ${ target_path } \" is a proper file. What do you want to do?"
read -p "[S]kip, [D]iff, [R]eplace: " replace_file
if expr " $replace_file " : "^[Dd]$" > /dev/null
then
verbose_echo "Diffing \" ${ source_path } \" and \" ${ target_path } \" "
$diff " $source_path " " $target_path "
fi
done
if expr " $replace_file " : "^[Rr]$"
then
verbose_echo "Removing ${ target_path } "
rm " $target_path "
else
continue
fi
fi
# Not a proper file
if [ -e " $target_path " ]
then
echo " \" ${ target_path } \" exists but is not a file; skipping."
continue
fi
# Directory missing; might have to create it
if [ ! -e " $target_dir " ]
then
while ! expr " $create_dir " : "^[SsCc]$" > /dev/null
do
echo " \" ${ target_dir } \" doesn't exist. What do you want to do?"
read -p "[S]kip or [C]reate: " create_dir
done
if expr " $create_dir " : "^[Cc]$" > /dev/null
then
mkdir -p " $target_dir "
else
continue
fi
fi
echo "Creating symlink at \" ${ target_path } \" ."
ln -s " $source_path " " $target_path "
done
verbose_echo "Cleaning up."
IFS = " $ifs_original "
verbose_echo " ${ cmdname } completed at ` date ` ."
exit $EX_OK