chiark / gitweb /
6bcf4d94ae2855e0e1636199ff04d78f9929082a
[ian-dotfiles.git] / infra / makelinks
1 #!/bin/bash
2 #
3 # To start tracking a file,
4 #   cp ~/.screenrc dot/screenrc
5 #
6 # To sort out symlinks when things are clean
7 #   infra/makelinks install
8
9 set -e -o posix -o pipefail
10
11 badusage () {
12     echo >&2 "usage: $0 [-n|-v] list|setup|dirimport|dirmove|clean"
13     exit 18
14 }
15
16 real_act=''
17
18 while true; do
19     if [ $# = 0 ]; then break; fi
20     case "$1" in
21     -n) real_act=log_only ;;
22     -v) real_act=with_log ;;
23     -*) badusage ;;
24     *) break ;;
25     esac
26     shift
27 done
28
29 case "$#.$1" in
30 1.list|1.setup|1.import|1.dirimport|1.clean) ;;
31 *)  badusage ;;
32 esac
33
34 mode=$1; shift
35
36 dots=$( find dot -mindepth 1 -maxdepth 1 -name '[0-9a-zA-Z]*[0-9a-zA-Z]' )
37
38 basepath=$(pwd)
39 basepath=${basepath#$HOME/}
40
41 estatus=0
42
43 show () {
44     printf "%s\n" "$1"
45 }
46
47 good () {
48     if [ $mode = list ]; then
49         show "good: $dot: $1"
50     fi
51 }
52
53 bad () {
54     estatus=16
55     show "bad: $dot: $1" >&2
56 }
57
58 needs () {
59     if [ $mode = $1 ]; then
60         act=$real_act
61         show "DOING $1: $prhome ($2)"
62     else
63         show "needs $1: $prhome: $2"
64         act=:
65     fi
66 }
67
68 log_only () {
69     echo "x $*"
70 }
71
72 with_log () {
73     log_only "$@"
74     "$@"
75 }
76
77 for dot in $dots; do
78     underhome=".${dot#dot/}"
79     inhome="$HOME/$underhome"
80     prhome="~/$underhome"
81     if [ "$inhome" -ef "$dot" ]; then
82         good "already symlinked here"
83     elif [ -h "$inhome" ]; then
84         bad "wrong symlink target"
85     elif ! [ -e "$inhome" ]; then
86         needs setup "absent here"
87         $act ln -s "$basepath/$dot" "$inhome"
88     elif [ -f "$inhome" ] && [ -f "$dot" ]; then
89         if cmp -s "$dot" "$inhome"; then
90             needs setup "identical here but not yet symlinked"
91             $act rm -f "$inhome"~
92             $act ln -s "$basepath/$dot" "$inhome"~
93             $act mv -f "$inhome"~ "$inhome"
94         else
95             needs import "modified here"
96             $act rm -f "$dot"~
97             $act cp "$inhome" "$dot"~
98             $act mv -f "$dot"~ "$dot"
99         fi
100     elif [ -d "$inhome" ] && [ -d "$dot" ]; then
101         needs dirimport "directory here not yet symlinked"
102         $act mv "$dot" "$dot~"
103         $act ln -s "$basepath/$dot" "$inhome"~
104         $act mv "$inhome" "$dot"
105         $act mv "$inhome~" "$inhome"
106         $act rm -rf "$dot~"
107     else
108         bad "mismatched file types"
109     fi
110 done
111
112 brokens=$(
113     cd $HOME
114     find -L .[0-9a-zA-Z]* -maxdepth 0 -xdev -type l -lname "$basepath/dot/*"
115 )
116 for underhome in $brokens; do
117     inhome="$HOME/$underhome"
118     prhome="~/$underhome"
119     needs clean "symlink to removed file in dot/"
120     $act rm -f "$inhome"
121 done