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