From: W. Trevor King Date: Wed, 26 Nov 2008 17:48:00 +0000 (-0500) Subject: Added local.patch support for easy minor tweaks on the central theme. X-Git-Tag: v0.3~101^2~1 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=e8b39dc82ef3367f10bd7c8845d80b3395bbdb41;p=dotfiles-framework.git Added local.patch support for easy minor tweaks on the central theme. See the README comming next commit for motivation and more details. --- diff --git a/Makefile b/Makefile index f831f94..e5e1f37 100644 --- 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 411929e..2adf29c 100755 --- 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 # @@ -12,7 +29,11 @@ # 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. diff --git a/fixup.sh b/fixup.sh index ecbd726..5a4ad7e 100755 --- a/fixup.sh +++ b/fixup.sh @@ -3,37 +3,131 @@ # 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