chiark / gitweb /
Get link target right for subdirs
[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 basepath=$(pwd)
37 basepath=${basepath#$HOME/}
38
39 estatus=0
40
41 show () {
42     printf "%s\n" "$1"
43 }
44
45 good () {
46     if [ $mode = list ]; then
47         show "good: $prhome: $1"
48     fi
49 }
50
51 bad () {
52     estatus=16
53     show "bad: $prhome: $1" >&2
54 }
55
56 needs () {
57     if [ $mode = $1 ]; then
58         act=$real_act
59         show "DOING $1: $prhome ($2)"
60     else
61         show "needs $1: $prhome: $2"
62         act=:
63     fi
64 }
65
66 log_only () {
67     echo "x $*"
68 }
69
70 with_log () {
71     log_only "$@"
72     "$@"
73 }
74
75 process_object () {
76     inhome="$HOME/$underhome"
77     prhome="~/$underhome"
78     linktarget="$basepath/$ours"
79     chompy="$underhome"
80     while true; do
81         case "$chompy" in
82         *?/?*)
83             linktarget="../$linktarget"
84             chompy="${chompy%/*}"
85             ;;
86         *)
87             break
88             ;;
89         esac
90     done
91     if [ "$inhome" -ef "$ours" ]; then
92         good "already symlinked here"
93     elif [ -h "$inhome" ]; then
94         bad "wrong symlink target"
95     elif ! [ -e "$inhome" ]; then
96         needs setup "absent here"
97         $act ln -s "$linktarget" "$inhome"
98     elif [ -f "$inhome" ] && [ -f "$ours" ]; then
99         if cmp -s "$ours" "$inhome"; then
100             needs setup "identical in this ~ but not yet symlinked"
101             $act rm -f "$inhome"~
102             $act ln -s "$linktarget" "$inhome"~
103             $act mv -f "$inhome"~ "$inhome"
104         else
105             needs import "modified here"
106             $act rm -f "$ours"~
107             $act cp "$inhome" "$ours"~
108             $act mv -f "$ours"~ "$ours"
109         fi
110     elif [ -d "$inhome" ] && [ -d "$ours" ]; then
111         needs dirimport "directory in this ~, not yet symlinked"
112         $act mv "$ours" "$ours~"
113         $act ln -s "$linktarget" "$inhome"~
114         $act mv "$inhome" "$ours"
115         $act mv "$inhome~" "$inhome"
116         $act rm -rf "$ours~"
117     else
118         bad "mismatched file types"
119     fi
120 }
121
122 dots=$( find dot -mindepth 1 -maxdepth 1 -name '[0-9a-zA-Z]*[0-9a-zA-Z]' )
123
124 for ours in $dots; do
125     underhome=".${ours#dot/}"
126     process_object
127 done
128
129 nondots=$( find home -mindepth 1 -maxdepth 1 -name '[0-9a-zA-Z]*[0-9a-zA-Z]' )
130
131 for ours in $nondots; do
132     underhome="${ours#home/}"
133     process_object
134 done
135
136 exec 3<correspondences
137 while read <&3 ours underhome; do
138     case "$ours" in
139     ''|'#'*) ;;
140     *)
141         case "$underhome" in
142         */*)
143             parent=${underhome%/*}
144             punderhome="$HOME/$parent"
145             prhome="~/${underhome%/*}"
146             if [ -d "$punderhome" ]; then
147                 good "directory exists"
148             elif ! [ -e "$punderhome" ]; then
149                 needs setup "directory does not exist"
150                 $act mkdir -p "$punderhome"
151             else
152                 bad "ought to be director but isn't"
153             fi
154             ;;
155         esac
156         process_object
157         ;;
158     esac
159 done
160
161 brokens=$(
162     cd $HOME
163     find -L .[0-9a-zA-Z]* -maxdepth 0 -xdev -type l \
164          \( -lname "$basepath/dot/*" -o -lname "$basepath/home/*" \)
165 )
166 for underhome in $brokens; do
167     inhome="$HOME/$underhome"
168     prhome="~/$underhome"
169     needs clean "symlink to removed file in dot/"
170     $act rm -f "$inhome"
171 done