#!/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 . # File: link-conf.sh # Author: Collin J. Doering # 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