chiark / gitweb /
f3b051053bd73b2a643e2c09bee83e9695082b07
[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: $dot: $1"
48     fi
49 }
50
51 bad () {
52     estatus=16
53     show "bad: $dot: $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     if [ "$inhome" -ef "$ours" ]; then
80         good "already symlinked here"
81     elif [ -h "$inhome" ]; then
82         bad "wrong symlink target"
83     elif ! [ -e "$inhome" ]; then
84         needs setup "absent here"
85         $act ln -s "$linktarget" "$inhome"
86     elif [ -f "$inhome" ] && [ -f "$ours" ]; then
87         if cmp -s "$ours" "$inhome"; then
88             needs setup "identical here but not yet symlinked"
89             $act rm -f "$inhome"~
90             $act ln -s "$linktarget" "$inhome"~
91             $act mv -f "$inhome"~ "$inhome"
92         else
93             needs import "modified here"
94             $act rm -f "$ours"~
95             $act cp "$inhome" "$ours"~
96             $act mv -f "$ours"~ "$ours"
97         fi
98     elif [ -d "$inhome" ] && [ -d "$ours" ]; then
99         needs dirimport "directory here not yet symlinked"
100         $act mv "$ours" "$ours~"
101         $act ln -s "$linktarget" "$inhome"~
102         $act mv "$inhome" "$ours"
103         $act mv "$inhome~" "$inhome"
104         $act rm -rf "$ours~"
105     else
106         bad "mismatched file types"
107     fi
108 }
109
110 dots=$( find dot -mindepth 1 -maxdepth 1 -name '[0-9a-zA-Z]*[0-9a-zA-Z]' )
111
112 for dot in $dots; do
113     ours="$dot"
114     underhome=".${dot#dot/}"
115     process_object
116 done
117
118 brokens=$(
119     cd $HOME
120     find -L .[0-9a-zA-Z]* -maxdepth 0 -xdev -type l -lname "$basepath/dot/*"
121 )
122 for underhome in $brokens; do
123     inhome="$HOME/$underhome"
124     prhome="~/$underhome"
125     needs clean "symlink to removed file in dot/"
126     $act rm -f "$inhome"
127 done