Added local.patch support for easy minor tweaks on the central theme.
authorW. Trevor King <wking@drexel.edu>
Wed, 26 Nov 2008 17:48:00 +0000 (12:48 -0500)
committerW. Trevor King <wking@drexel.edu>
Wed, 26 Nov 2008 17:48:00 +0000 (12:48 -0500)
See the README comming next commit for motivation and more details.

Makefile
diff.sh
fixup.sh

index f831f945184fe246fc618e12e298648ed135695e..e5e1f37b07c790164d7996de7b380011a91e72e6 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -27,7 +27,14 @@ merge:
        ./merge.sh
 
 override:
-       ./fixup.sh -f
+       ./fixup.sh --force
 
+# Print a diff between the local installation and .dotfiles
+# i.e. What changes will `make override' effect
 localdiff:
-       ./diff.sh
+       ./diff.sh --local
+
+# Save a diff between .dotfiles and the local installation
+# i.e. What specialization do I want compared to the central .dotfiles
+localpatch:
+       ./diff.sh > local.patch
diff --git a/diff.sh b/diff.sh
index 411929e14264280b5277467fe89f5b7eba8942e2..2adf29c21cf3bc16ae234dc4e903f36ff0a09df7 100755 (executable)
--- a/diff.sh
+++ b/diff.sh
@@ -1,7 +1,24 @@
 #!/bin/bash
 #
-# Print diffs for each _FILE / ~/.FILE pair
+# Print diffs for each _FILE, ~/.FILE pair
+#
+# There are two modes, local and standard. In standard mode, we show the
+# transition ~/.file -> _file, which shows the changes effected by
+# `make override`.  In local mode we show the transition _file -> ~/.file,
+# which shows the changes we need to apply to the .dotfiles to create
+# your current local installation.  The --local option selects local mode.
+
+LOCAL="no" # Select diff ordering
 
+# parse options
+while [ -n "$1" ]; do
+    case "$1" in
+       "--local")
+       LOCAL="yes"
+       ;;
+    esac
+    shift
+done
 
 # Show the changes we'd apply on installation
 #
 # dotfile - The file it should be linked to in ~/, e.g. '.foo'
 function handleFile( )
 {
-    diff -ru $2 $1
+    if [ $LOCAL == "yes" ]; then
+       diff -ru $2 $1
+    else
+       diff -ru $1 $2
+    fi
 }
 
 # See if we can find any _files.
index ecbd72674c2eb72bf652c88f28fb3a2ef7e639cf..5a4ad7eaeb504860e33e919d5e22645a3354d570 100755 (executable)
--- a/fixup.sh
+++ b/fixup.sh
 # Link each _FILE in the current directory to ~/.FILE
 #
 # Originally by Steve Kemp (http://www.steve.org.uk/)
+#
+# By default, fixup only replaces missing files and simlinks.  You can
+# optionally overwrite any local files and directories by passing the
+# --force option.
 
-FORCE="no" # If "yes", overwrite existing .files
+FORCE="no"   # If "yes", overwrite existing .files
+DRY_RUN="no" # If "yes", disable any actions that change the filesystem
 
 # parse options
 while [ -n "$1" ]; do
     case "$1" in
-       "-f")
+       "--force")
        FORCE="yes"
        ;;
+       "--dry-run")
+       DRY_RUN="yes"
+       ;;
     esac
     shift
 done
 
 # Create the symbolic link.
 #
-# handleFile( $file, $dotfile )
+# linkFiles( $file, $dotfile )
 #
 # Parameters:
 # file - The file we're processing '_foo'
 # dotfile - The file it should be linked to in ~/, e.g. '.foo'
-function handleFile( )
+function linkFiles ( )
 {
     file=$1
     dotfile=$2
     ln -s `pwd`/$file ~/$dotfile
 }
 
+# Check if a file is patch controlled
+#
+# isPatchFile( $file, $patchfiles)
+#
+# Parameters:
+# file - The file we're processing '_foo'
+# patchfiles - A string list of patchfiles
+function isPatchFile( )
+{
+    file=$1
+    shift
+    patchfiles=$*
+    
+    for patchfile in $patchfiles; do
+       if [ $file == $patchfile ]; then
+           return 0
+       fi
+    done    
+    return 1
+}
+
+# Check if a file is controlled by the dotfiles framework
+#
+# isControlledFile( $file, $patchfiles )
+#
+# Parameters:
+# file - The file we're processing '_foo'
+# patchfiles - A string list of patchfiles
+function isControlledFile( )
+{
+    file=$1
+    shift
+    patchfiles=$*
+    dotfile=.${file/_/}
+    
+    if [ ! -e ~/$dotfile ]; then
+       #echo "~/$dotfile is controlled (does not exist)"
+       return 0
+    elif [ -h ~/$dotfile ]; then
+       #echo "~/$dotfile is controlled (a symlink)"
+       return 0
+    elif isPatchFile $file $patchfiles; then
+       #echo "~/$dotfile is controlled (a patchfile)"
+       return 0
+    fi    
+    #echo "~/$dotfile is not controlled"
+    return 1
+}
+
+# Check if the installed file matches the dotfiles version
+#
+# fileChanged( $file, $dotfile )
+#
+# Parameters:
+# file - The file we're processing '_foo'
+# dotfile - The file it should be linked to in ~/, e.g. '.foo'
+function fileChanged()
+{
+    file=$1
+    dotfile=$2
+    DIFF=`diff -r ~/$dotfile $file`
+    [ -z "$DIFF" ]
+    return $?
+}
+
+# Prettyprint a list of files
+#
+# listFiles( $title, $list )
+#
+# Parameters:
+# title - The name of the list
+# list - The files in the list
+function listFiles()
+{
+    title=$1
+    shift
+    files=$*
+    if [ $# -gt 0 ]; then
+       echo "$title: ($#)"
+       for file in $files; do
+           echo "  $file"
+       done
+    fi
+}
+
+
 # See if we can find any _files.
 found=0
-for i in _*; do
-    if [ -e $i ]; then
+for file in _*; do
+    if [ -e $file ]; then
         found=`expr $found + 1`
     fi
 done
@@ -44,48 +138,94 @@ if [ "$found" -lt 1 ]; then
     exit
 fi
 
+# If a local.patch file exists, apply it's changes to our dotfiles
+# files.  We catch the output of this to get a list of the files under
+# local.patch control
+if [ -f "local.patch" ]; then
+    patchoption=""
+    if [ $DRY_RUN == "yes" ]; then
+       patchoption="--dry-run"
+    fi
+    echo "\$ patch $patchoption -i local.patch"
+    patchout=`patch $patchoption -i local.patch || exit 1`
+    echo "$patchout"
+    echo ""
+    # e.g. patchout:
+    # patching file _emacs
+    # patching file _gnuplot
+    PATCHFILES=`echo "$patchout" | sed -n 's/patching file //p'`
+    #listFiles "Patched files" $PATCHFILES
+fi
+
+IGNORED=""
+NOT_CHANGED=""
+UPDATED=""
+ADDED=""
+
 # For each file in this directory.
-for i in _*; do
+for file in _*; do
     # Create .dotfile version.
-    dotfile=.${i/_/}
+    dotfile=.${file/_/}
     
-    # If the file/directory exists and we're overriding it, remove it now
-    if [ -e ~/$dotfile ] && [ $FORCE == "yes" ]; then
-       rm -rvf ~/$dotfile
+    # Decide what to do with files we don't normally control
+    OVERRIDDEN="no"
+    if ! isControlledFile $file $PATCHFILES; then
+       if [ $FORCE == "yes" ]; then
+           OVERRIDDEN="yes"
+           UPDATED="$UPDATED ~/$dotfile"
+           if [ $DRY_RUN == "no" ]; then
+                # Back up the ~/$dotfile
+               mv ~/$dotfile ~/$dotfile.bak
+           fi
+       else
+           IGNORED="$IGNORED ~/$dotfile"
+           continue
+       fi
     fi
-    
-    # If this is a file.
-    if [ -f $i ]; then
-        
-        # If it is a symlink, then remove it.
-        if [ -h ~/$dotfile ]; then
-            # Remove the old link, and create a new one.
-            rm ~/$dotfile
-        fi
-        
-        # It is a normal file.
-        if [ -e ~/$dotfile ]; then
-            echo "~/$dotfile exists - ignoring it."
-        else
-            # File doesn't exist, create the link.
-            handleFile $i $dotfile
-        fi
+
+    # Targets getting to this point should be controlled
+    if [ -e ~/$dotfile ]; then
+       # The target exists, see if it has changed
+       if fileChanged $file $dotfile; then
+           NOT_CHANGED="$NOT_CHANGED ~/$dotfile"
+           continue
+       else
+           if [ $OVERRIDDEN == "no" ]; then
+               UPDATED="$UPDATED ~/$dotfile"
+           fi
+           if [ $DRY_RUN == "no" ]; then
+                # Back up the ~/$dotfile
+               mv ~/$dotfile ~/$dotfile.bak
+           fi
+       fi
+    else
+       echo "no ~/$dotfile" 
+       if [ $OVERRIDDEN == "no" ]; then
+           ADDED="$ADDED ~/$dotfile"
+       fi
+    fi
+    if isPatchFile $file $PATCHFILES; then
+       if [ $DRY_RUN == "no" ]; then
+            # Install the patched ~/$dotfile
+           cp $file ~/$dotfile
+       fi
     else
-        # The file _foo is a directory.
-        
-        # If that directory doesn't exist in ~/ then create it.
-        if [ ! -d ~/$dotfile ]; then
-            echo "Creating new directory in ~";
-            mkdir ~/$dotfile
-        fi
-       
-        # Now link all non-linked files up.
-        for s in $i/*; do
-            file=`basename $s`
-       
-            if [ ! -h ~/$dotfile/$file ]; then
-                ln -s `pwd`/$s ~/$dotfile/$file
-            fi
-        done
+       if [ $DRY_RUN == "no" ]; then
+            # Install a symlink ~/$dotfile     
+           linkFiles $file $dotfile
+       fi
     fi
 done
+
+listFiles "Added" $ADDED
+listFiles "Updated" $UPDATED
+listFiles "NotChanged" $NOT_CHANGED
+listFiles "Ignored" $IGNORED
+
+# Revert the action of the patch on our dotfiles files now that we've
+# installed the patched versions.
+if [ -f "local.patch" ] && [ $DRY_RUN == "no" ]; then
+    echo ""
+    echo '$ patch -i local.patch -R'
+    patch -i local.patch -R
+fi