Add link-conf program to project itself

link-conf is a little shell script I wrote to recursively hard-link and
make directories following the structure of a "config directory". This
allows me to have a "clean" working git repository but edit config files
as usual ignoring the fact they are part of a git project and located in
another place.

Use "link-conf.sh --help" to see how the program is called. If you are
unsure you can always use the "-d -v" options together to see what the
program would propose to link, create, and safely remove. There is an
option "-f" that will force removal of files while it recursively
links. This is in the case where the config dir and the target exist as
files and the target file is not referenced by any hard-link and thus if
removed will be gone forever. Do not use "-f" or "--force" if you don't
know what you're doing.

This program could be cleaned up a bit and it would be nice if it was
run after every commit (use a git hook in .git/hooks/).

Signed-off-by: Collin J. Doering <rekahsoft@gmail.com>
This commit is contained in:
Collin J. Doering 2014-10-23 04:47:10 -04:00 committed by Collin J. Doering
parent a8582a7d4e
commit 11eaff99d3

223
.bin/link-conf.sh Executable file
View File

@ -0,0 +1,223 @@
#!/bin/sh
# (C) Copyright Collin Doering 2011
#
# 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/>.
# File: link-conf.sh
# Author: Collin J. Doering <rekahsoft@gmail.com>
# Date: Jun 4, 2011
# TODO: * add support for a 'interactive' option [ -i | --interactive ]
# * add support for a link-to option so you can link the given config-dir files to
# somewhere other then $HOME
# lnfrec takes:
# $1: the config dir in question
# $2: the current directory in the recursive call (used internally to recurse the config dir)
# $3: boolean specifying option relink
# $4: boolean specifying option clean
# $5: boolean specifying option verbose
# $6: boolean specifying option force
# $7: boolean specifying option dry
function lnfrec () {
# for each file in $1 directory do link (default), relink ($3) or clean ($4) along with options
# verbose ($5) and force ($6)
for f in `ls -aA $1/$2`; do
case "$f" in
.)
;;
..)
;;
*/.)
;;
*/..)
;;
*~)
;;
.git)
;;
.gitignore)
;;
*)
# If the current file being recursed on from the given config dir ($1) is a directory
if [[ -d "$1$2/$f" ]]; then
# If the file currently being recursed on from the config dir ($1) in $HOME is not a directory
# (that is $HOME$2/$f); then create the directory $HOME$2/$f
if [[ ! -d "$HOME$2/$f" ]]; then
$5 && echo "Creating dir $HOME$2/$f"
! $7 && mkdir "$HOME$2/$f"
fi
# recurse further into config dir to $1$2/$f
lnfrec "$1" "$2/$f" $3 $4 $5 $6 $7
# If the current file being recursed on from the given config dir ($1) in $HOME is not a directory
# and is not a file or a link, then create a hardlink from $1$2/$f to $HOME$2/$f
elif [[ ! -e "$HOME$2/$f" && ! -L "$HOME$2/$f" ]]; then
$5 && echo "Linked $1$2/$f -> $HOME$2/$f"
! $7 && ln "$1$2/$f" "$HOME$2/$f"
# Otherwise: the file exists ($HOME$2/$f)
else
NUM_LINKS=$(ls -al "$HOME$2/$f" | cut -d' ' -f2)
# If the relink option is set
if $3; then
# check if the config file $HOME$2/$f has more then one hardlink; if so then relink
if [[ $NUM_LINKS -gt 1 ]]; then
$5 && echo "Re-linking $1$2/$f -> $HOME$2/$f"
! $7 && rm "$HOME$2/$f"
! $7 && ln "$1$2/$f" "$HOME$2/$f"
# if the force option is set (along with the relink option)
elif $6; then
echo "Warning! Removing regular file $HOME$2/$f"
! $7 && rm "$HOME$2/$f"
$5 && echo "Re-linking $1$2/$f -> $HOME$2/$f"
! $7 && ln "$1$2/$f" "$HOME$2/$f"
else
$5 && echo "$HOME$2/$f only has one file reference! Skipping.."
fi
# If the clean option is set
elif $4; then
# Check if the config file $HOME$2/$f has more then one hardlink; if so then clean the file from home
if [[ $NUM_LINKS -gt 1 ]]; then
$5 && echo "Cleaning $HOME$2/$f"
! $7 && rm "$HOME$2/$f"
# If the force option is set (along with clean)
elif $6; then
echo "Warning! Forcing removal of $HOME$2/$f"
$5 && echo "Cleaning $HOME$2/$f"
! $7 && rm "$HOME$2/$f"
else
$5 && echo "$HOME$2/$f only has one file reference! Skipping.."
fi
else
$5 && echo "$HOME$2/$f already linked! Skipping.."
fi # will fault if not given proper arguments! Internal usage only!
fi
;;
esac
done
}
function displayHelp () {
echo "Usage: link-conf [-r|--relink] [-f|--force] [-c|--clean] [-v|--verbose] [-d|--dry] [-h|--help] config-dir"
}
# Option variables set when parsing cli parameters
RELINK=false
CLEAN=false
VERBOSE=false
FORCE=false
DRY=false
CONFIG_DIR=""
# Use getopt to parse given cli arguments
args=`getopt -n link-conf -o rcfvdh -l relink,clean,force,verbose,dry,help -- $*`
if [ ! $? ]; then
echo "Failed to parse arguments!"
displayHelp
exit 1
fi
# Set arguments to the new ones done by using getopt
set -- $args
while true; do
case "$1" in
-r | --relink)
if $CLEAN; then
echo "Error! Cannot specify relink and clean at once!"
exit 1
elif [ !$RELINK ]; then
RELINK=true
else
echo "Error! -r | --relink used more then once!"
exit 1
fi
;;
-c | --clean)
if $RELINK; then
echo "Error! Cannot specify relink and clean at once!"
exit 1
elif [ !$CLEAN ]; then
CLEAN=true
else
echo "Error! -c | --clean used more then once!"
exit 1
fi
;;
-v | --verbose)
if [ !$VERBOSE ]; then
VERBOSE=true
else
echo "Error! -v | --verbose used more then once!"
exit 1
fi
;;
-f | --force)
if [ !$FORCE ]; then
FORCE=true
else
echo "Error! -f | --force used more then once!"
exit 1
fi
;;
-d | --dry)
if [ !$DRY ]; then
DRY=true
else
echo "Error! -d | --dry used more then once!"
exit 1
fi
;;
-h | --help)
displayHelp
exit 0
;;
--)
shift
for arg; do
maybe_dir=$(echo $arg | sed "s/^\([\']\)\(.*\)\1\$/\2/g")
if [ "$CONFIG_DIR" == "" ]; then
if [[ -d "$maybe_dir" ]]; then
CONFIG_DIR="$maybe_dir"
else
echo "Error! The path given \"$maybe_dir\" is not a valid directory!"
exit 1
fi
else
echo "Error! More then one config dir was given!"
displayHelp
exit 1
fi
done
break
;;
*)
echo "Internal error!"
exit 1
;;
esac
shift
done
# Notify the user if it is a dry run
if $DRY; then
echo "Dry run.."
fi
# Run the recursive hard linking algorithm
lnfrec "$CONFIG_DIR" "" $RELINK $CLEAN $VERBOSE $FORCE $DRY
# exit gracefully
exit 0