Move path definitions forward in _bashrc
[dotfiles-framework.git] / fixup.sh
1 #!/bin/bash
2 #
3 # Link each _FILE in the current directory to ~/.FILE
4 #
5 # Originally by Steve Kemp (http://www.steve.org.uk/)
6 #
7 # By default, fixup only replaces missing files and simlinks.  You can
8 # optionally overwrite any local files and directories by passing the
9 # --force option.
10
11 FORCE="no"   # If "yes", overwrite existing .files
12 DRY_RUN="no" # If "yes", disable any actions that change the filesystem
13
14 # parse options
15 while [ -n "$1" ]; do
16     case "$1" in
17         "--force")
18         FORCE="yes"
19         ;;
20         "--dry-run")
21         DRY_RUN="yes"
22         ;;
23     esac
24     shift
25 done
26
27 # Create the symbolic link.
28 #
29 # linkFiles( $file, $dotfile )
30 #
31 # Parameters:
32 # file - The file we're processing '_foo'
33 # dotfile - The file it should be linked to in ~/, e.g. '.foo'
34 function linkFiles ( )
35 {
36     file=$1
37     dotfile=$2
38     ln -s `pwd`/$file ~/$dotfile
39 }
40
41 # Check if a file is patch controlled
42 #
43 # isPatchFile( $file, $patchfiles)
44 #
45 # Parameters:
46 # file - The file we're processing '_foo'
47 # patchfiles - A string list of patchfiles
48 function isPatchFile( )
49 {
50     file=$1
51     shift
52     patchfiles=$*
53     
54     for patchfile in $patchfiles; do
55         if [ $file == $patchfile ]; then
56             return 0
57         fi
58     done    
59     return 1
60 }
61
62 # Check if a file is controlled by the dotfiles framework
63 #
64 # isControlledFile( $file, $patchfiles )
65 #
66 # Parameters:
67 # file - The file we're processing '_foo'
68 # patchfiles - A string list of patchfiles
69 function isControlledFile( )
70 {
71     file=$1
72     shift
73     patchfiles=$*
74     dotfile=.${file/_/}
75     
76     if [ ! -e ~/$dotfile ]; then
77         #echo "~/$dotfile is controlled (does not exist)"
78         return 0
79     elif [ -h ~/$dotfile ]; then
80         #echo "~/$dotfile is controlled (a symlink)"
81         return 0
82     elif isPatchFile $file $patchfiles; then
83         #echo "~/$dotfile is controlled (a patchfile)"
84         return 0
85     fi    
86     #echo "~/$dotfile is not controlled"
87     return 1
88 }
89
90 # Check if the installed file matches the dotfiles version
91 #
92 # fileChanged( $file, $dotfile )
93 #
94 # Parameters:
95 # file - The file we're processing '_foo'
96 # dotfile - The file it should be linked to in ~/, e.g. '.foo'
97 function fileChanged()
98 {
99     file=$1
100     dotfile=$2
101     DIFF=`diff -r ~/$dotfile $file`
102     [ -z "$DIFF" ]
103     return $?
104 }
105
106 # Prettyprint a list of files
107 #
108 # listFiles( $title, $list )
109 #
110 # Parameters:
111 # title - The name of the list
112 # list - The files in the list
113 function listFiles()
114 {
115     title=$1
116     shift
117     files=$*
118     if [ $# -gt 0 ]; then
119         echo "$title: ($#)"
120         for file in $files; do
121             echo "  $file"
122         done
123     fi
124 }
125
126
127 # See if we can find any _files.
128 found=0
129 for file in _*; do
130     if [ -e $file ]; then
131         found=`expr $found + 1`
132     fi
133 done
134
135 # If we found none then exit
136 if [ "$found" -lt 1 ]; then
137     echo "WARNING: No files matching _* were found"
138     exit
139 fi
140
141 # If a local.patch file exists, apply it's changes to our dotfiles
142 # files.  We catch the output of this to get a list of the files under
143 # local.patch control
144 if [ -f "local.patch" ]; then
145     patchoption=""
146     if [ $DRY_RUN == "yes" ]; then
147         patchoption="--dry-run"
148     fi
149     echo "\$ patch $patchoption -i local.patch"
150     patchout=`patch $patchoption -i local.patch || exit 1`
151     echo "$patchout"
152     echo ""
153     # e.g. patchout:
154     # patching file _emacs
155     # patching file _gnuplot
156     PATCHFILES=`echo "$patchout" | sed -n 's/patching file //p'`
157     #listFiles "Patched files" $PATCHFILES
158 fi
159
160 IGNORED=""
161 NOT_CHANGED=""
162 UPDATED=""
163 ADDED=""
164
165 # For each dotfile in this directory.
166 for file in _*; do
167     # Create .dotfile version.
168     dotfile=.${file/_/}
169     
170     # Decide what to do with files we don't normally control
171     OVERRIDDEN="no"
172     if ! isControlledFile $file $PATCHFILES; then
173         if [ $FORCE == "yes" ]; then
174             OVERRIDDEN="yes"
175             UPDATED="$UPDATED ~/$dotfile"
176             if [ $DRY_RUN == "no" ]; then
177                 # Back up the ~/$dotfile
178                 mv ~/$dotfile ~/$dotfile.bak
179             fi
180         else
181             IGNORED="$IGNORED ~/$dotfile"
182             continue
183         fi
184     fi
185
186     # Targets getting to this point should be controlled
187     if [ -e ~/$dotfile ]; then
188         # The target exists, see if it has changed
189         if fileChanged $file $dotfile; then
190             NOT_CHANGED="$NOT_CHANGED ~/$dotfile"
191             continue
192         else
193             if [ $OVERRIDDEN == "no" ]; then
194                 UPDATED="$UPDATED ~/$dotfile"
195             fi
196             if [ $DRY_RUN == "no" ]; then
197                 # Back up the ~/$dotfile
198                 mv ~/$dotfile ~/$dotfile.bak
199             fi
200         fi
201     else
202         if [ $OVERRIDDEN == "no" ]; then
203             ADDED="$ADDED ~/$dotfile"
204         fi
205     fi
206     if isPatchFile $file $PATCHFILES; then
207         if [ $DRY_RUN == "no" ]; then
208             # Install the patched ~/$dotfile
209             cp $file ~/$dotfile
210         fi
211     else
212         if [ $DRY_RUN == "no" ]; then
213             # Install a symlink ~/$dotfile      
214             linkFiles $file $dotfile
215         fi
216     fi
217 done
218
219 listFiles "Added" $ADDED
220 listFiles "Updated" $UPDATED
221 listFiles "NotChanged" $NOT_CHANGED
222 listFiles "Ignored" $IGNORED
223
224 # Revert the action of the patch on our dotfiles files now that we've
225 # installed the patched versions.
226 if [ -f "local.patch" ] && [ $DRY_RUN == "no" ]; then
227     echo ""
228     echo '$ patch -i local.patch -R'
229     patch -i local.patch -R
230 fi