Browse Source

Rewrite mklinks and dotfiles structure

New version aims to simplify main vault and support deeper merging
strategies.  We'll see...
Alois Mahdal 7 years ago
parent
commit
bac52e5f42

+ 7
- 1
.gitignore View File

@@ -3,5 +3,11 @@
3 3
 .netrwhist
4 4
 */gittum/private.gitconfig
5 5
 */vim/bundle/private/*
6
-dotfiles.config/imapdomo/private
6
+dotfiles/config/imapdomo/private
7 7
 external/*
8
+
9
+dotfiles/bash/host/*
10
+dotfiles/bmo/ini.d/*
11
+dotfiles/config/Xlib/host/*
12
+dotfiles/config/imapdomo/host/*
13
+dotfiles/gittum/host/*

+ 0
- 1
dotfiles.config/Xlib/host View File

@@ -1 +0,0 @@
1
-../../external/dotfiles.config/Xlib/host

+ 0
- 1
dotfiles.config/imapdomo/host View File

@@ -1 +0,0 @@
1
-../../external/dotfiles.config/imapdomo/host

+ 0
- 1
dotfiles.config/vimb View File

@@ -1 +0,0 @@
1
-../external/dotfiles.config/vimb

+ 0
- 1
dotfiles/bash/host View File

@@ -1 +0,0 @@
1
-../../external/dotfiles/bash/host

+ 1
- 0
dotfiles/bash/host/README View File

@@ -0,0 +1 @@
1
+put host-specific configs here

+ 0
- 1
dotfiles/bmo/ini.d View File

@@ -1 +0,0 @@
1
-../../external/dotfiles/bmo/ini.d

+ 1
- 0
dotfiles/bmo/ini.d/README View File

@@ -0,0 +1 @@
1
+put host-specific configs here

dotfiles.config/Xlib/bin/setup → dotfiles/config/Xlib/bin/setup View File


dotfiles.config/Xlib/colorscheme/collar.Xdefaults → dotfiles/config/Xlib/colorscheme/collar.Xdefaults View File


dotfiles.config/Xlib/colorscheme/mkdemo → dotfiles/config/Xlib/colorscheme/mkdemo View File


dotfiles.config/Xlib/colorscheme/stucco.Xdefaults → dotfiles/config/Xlib/colorscheme/stucco.Xdefaults View File


dotfiles.config/Xlib/colorscheme/tango.Xdefaults → dotfiles/config/Xlib/colorscheme/tango.Xdefaults View File


dotfiles.config/Xlib/colorscheme/zenburn.Xdefaults → dotfiles/config/Xlib/colorscheme/zenburn.Xdefaults View File


dotfiles.config/Xlib/global.Xdefaults → dotfiles/config/Xlib/global.Xdefaults View File


+ 1
- 0
dotfiles/config/Xlib/host/README View File

@@ -0,0 +1 @@
1
+Put host-specific Xlib configs here

dotfiles.config/dunst/dunstrc → dotfiles/config/dunst/dunstrc View File


+ 1
- 0
dotfiles/config/imapdomo/host/README View File

@@ -0,0 +1 @@
1
+put host-specific configs here

dotfiles.config/imapdomo/private/README → dotfiles/config/imapdomo/private/README View File


+ 0
- 1
dotfiles/gnucash View File

@@ -1 +0,0 @@
1
-../../../st/config/dotfiles/gnucash

+ 0
- 1
dotfiles/task/data View File

@@ -1 +0,0 @@
1
-../../external/dotfiles/task/data

+ 1
- 1
dotfiles/task/head.taskrc View File

@@ -1,2 +1,2 @@
1
-data.location=~/.task/data
1
+data.location=~/.taskdata
2 2
 include ~/.task/main.taskrc

+ 0
- 1
dotfiles/weechat View File

@@ -1 +0,0 @@
1
-../../../st/config/dotfiles/weechat

+ 320
- 80
mklinks View File

@@ -1,84 +1,324 @@
1
-#!/usr/bin/perl
2
-
3
-# ============================================
4
-# mklinks
5
-# --------------------------------------------
6
-#
7
-# usage: mklinks DOTROOT [PREFIX]
8
-#
9
-#
10
-# This script will go through each file or
11
-# sub-folder of DOTROOT and create symbolic
12
-# link to it under your HOME named with "."
13
-# prefix.
14
-#
15
-# This is useful for sharing your dotfiles
16
-# (e.g. using service like Dropbox or keeping
17
-# them in a shared VCS repository like git)
18
-#
19
-#    DOTROOT - path where your shared dot-files
20
-#              are.
21
-#    PREFIX  - where you want your links to
22
-#              dot-files to be created ($HOME
23
-#              by default)
24
-#
25
-# --------------------------------------------
26
-# By Alois Mahdal; no warranty
27
-# ============================================
28
-
29
-
30
-use strict;
31
-use warnings;
32
-use Getopt::Long;
33
-use File::Spec;
34
-
35
-sub usage { print STDERR "usage: $0: DOTROOT [PREFIX]\n"; exit 1; }
36
-
37
-my $dotroot;
38
-my $prefix;
39
-my @masks;
40
-
41
-my $opts = GetOptions(
42
-    'dotroot=s' => \$dotroot,
43
-    'prefix=s'  => \$prefix,
44
-    'masks=s'   => \@masks
45
-) or usage;
46
-
47
-@masks = @masks ? @masks : qw ( .config .local/share );
48
-
49
-$dotroot = $dotroot // shift;
50
-$prefix = $prefix // shift;
51
-$prefix = $prefix // $ENV{HOME};
52
-$dotroot or usage;
53
-
54
-sub mklinks {
55
-    my $dotroot = shift;
56
-    my $mask = shift;
57
-    $dotroot =~ s|/?$||;
58
-    if ($mask) {
59
-        $dotroot .= $mask;
1
+#!/bin/bash
2
+
3
+warn() {
4
+    echo "$@" >&2
5
+}
6
+
7
+think() {
8
+    $Verbose || return
9
+    warn "$@"
10
+}
11
+
12
+die() {
13
+    warn "$@"
14
+    exit 3
15
+}
16
+
17
+usage() {
18
+    warn "usage: $0 init     VAULT SUBVAULT"
19
+    warn "usage: $0 explore  VAULT SUBVAULT"
20
+    exit 2
21
+}
22
+
23
+debug() {
24
+    $Debug || return
25
+    local msg
26
+    for msg in "$@";
27
+    do
28
+        warn "debug:$msg"
29
+    done
30
+}
31
+
32
+debugv() {
33
+    $Debug || return
34
+    local vn
35
+    local vd
36
+    for vn in "$@";
37
+    do
38
+        if vd=$(declare -p "$vn" 2>/dev/null);
39
+        then
40
+            warn "debug:${vd#declare ?? }"
41
+        else
42
+            warn "debug:$vn #Unset"
43
+        fi
44
+    done
45
+}
46
+
47
+debugc() {
48
+    $Debug || return
49
+    debug "-- cmd begin: $*"
50
+    Debug=false "$@" | sed -e 's/^/debug:/' >&2
51
+    debug "-- cmd end --"
52
+}
53
+
54
+lssv() {
55
+    #
56
+    # List sub-vaults
57
+    #
58
+    # Sub-vault is a sub-path of vault directory that contains items
59
+    # that should be linked separately, to a similar $HOME subpath,
60
+    # rather than linking the whole sub-tree.  This is typical for
61
+    # .config directory specified by XDG standard.
62
+    #
63
+    # For example, imagine vault like this:
64
+    #
65
+    #     dotfiles/
66
+    #     ├── config
67
+    #     │   ├── dunst
68
+    #     │   │   └── dunstrc
69
+    #     │   └── uzbl
70
+    #     │       ├── config
71
+    #     │       └── style.css
72
+    #     ├── i3
73
+    #     │   └── config
74
+    #     ├── i3status.conf
75
+    #     └── vimrc
76
+    #
77
+    # Without sub-vault, the "config" would be linked as "$HOME/.config":
78
+    #
79
+    #     $HOME/.config         -> dotfiles/.config
80
+    #     $HOME/.i3             -> dotfiles/i3
81
+    #     $HOME/.i3status.conf  -> dotfiles/i3status.conf
82
+    #     $HOME/.vimrc          -> dotfiles/vimrc
83
+    #
84
+    # This is impractical in most cases, as normally you want to select
85
+    # applications to link--some dotfiles could be specific to some
86
+    # hosts or even private.
87
+    #
88
+    # Setting 'config' as sub-vault will tell mklinks that you don't
89
+    # want to link this item directly but rather each of its items:
90
+    #
91
+    #     $HOME/.config/dunst   -> dotfiles/config/dunst
92
+    #     $HOME/.config/uzbl    -> dotfiles/config/uzbl
93
+    #     $HOME/.i3             -> dotfiles/i3
94
+    #     $HOME/.i3status.conf  -> dotfiles/i3status.conf
95
+    #     $HOME/.vimrc          -> dotfiles/vimrc
96
+    #
97
+    # This way, you can have other items under "$HOME/.config" that
98
+    # are either purely local or linked to another vault.
99
+    #
100
+    # Note that the subvault can be deeper than one level, i.e.
101
+    # subvault "local/share" also works:
102
+    #
103
+    #     $HOME/.local/share/klavaro -> dotfiles/local/share/klavaro
104
+    #
105
+    local sv
106
+    test -n "${SubVaults[0]}" && {
107
+        think "using sub-vaults from command line"
108
+        for sv in "${SubVaults[@]}";
109
+        do
110
+            echo "$sv"
111
+        done
112
+        return
60 113
     }
61
-    if (not -d $dotroot) { warn "not a directory: $dotroot\n"; return }
62
-    my @dirs = `ls $dotroot`;
63
-    foreach my $dir (@dirs) {
64
-        chomp $dir;
65
-        my $source = File::Spec->rel2abs("$dotroot/$dir");
66
-        my $target;
67
-        if ($mask) {
68
-            $target = "$prefix/$mask/$dir";
69
-            `mkdir -p $prefix/$mask`;
70
-        } else {
71
-            $target = "$prefix/.$dir";
72
-            `mkdir -p $prefix`;
73
-        }
74
-        if (-e $target) {
75
-            warn "target exists: $target\n";
76
-        } else {
77
-#           $source = File::Spec->abs2rel($source, $target);
78
-            `ln -sr $source $target`;
79
-        }
114
+    test -f "$Vault/dotvault/subvaults" && {
115
+        think "reading subvaults from file: $Vault/dotvault/subvaults"
116
+        grep . "$Vault/dotvault/subvaults" \
117
+          | grep -v "^#.*"
118
+        return
80 119
     }
120
+    think "using hard-coded list of subvaults"
121
+    echo config
122
+}
123
+
124
+lsvault() {
125
+    #
126
+    # List all vaults and subvaults, depth-first
127
+    #
128
+    {
129
+        echo "$Vault"
130
+        lssv \
131
+          | while IFS= read -r sv;
132
+            do
133
+                test -e "$Vault/$sv" || {
134
+                    think "ignoring non-existent sub-vault: $sv"
135
+                    continue
136
+                }
137
+                test -d "$Vault/$sv" || {
138
+                    warn "ignoring non-directory sub-vault: $sv"
139
+                    continue
140
+                }
141
+                echo "$Vault/$sv"
142
+            done
143
+    } \
144
+      | LC_ALL=C sort \
145
+      | tac
146
+}
147
+
148
+istarget() {
149
+    #
150
+    # True if item $1 is possible target
151
+    #
152
+    # Item is obviously not a possible target if it's
153
+    # a (sub-)vault.
154
+    #
155
+    # A less obvious case is when item is an intermediate directory
156
+    # on a path leading to a sub-vault.  Such item cannot be a target!
157
+    #
158
+    # For example: there are sub-vaults:
159
+    #
160
+    #     foo
161
+    #     foo/bar/baz
162
+    #
163
+    # and a tree:
164
+    #
165
+    #     foo
166
+    #     ├── A
167
+    #     └── bar
168
+    #         └── baz
169
+    #             └── B
170
+    #
171
+    # Items A and B could both be targets, but baz could not be!
172
+    #
173
+    #TODO: write an explanation
174
+    #
175
+    local item=$1
176
+    debugv item
177
+    Verbose=false lsvault | grep -qxF "$item"   && return 1
178
+    Verbose=false lsvault | grep -qx "$item/.*" && return 1
179
+    return 0
180
+}
181
+
182
+pfxpath() {
183
+    #
184
+    # Prefix paths with $1
185
+    #
186
+    # Just like `sed "s/^/$1/" but works with any characters
187
+    # in $1 excepr newline, which is not allowed in paths..
188
+    #
189
+    local pfx="$1"
190
+    local path
191
+    while IFS= read -r path;
192
+    do
193
+        echo "$pfx$path"
194
+    done
195
+}
196
+
197
+lstarget() {
198
+    #
199
+    # List potential items in vault $1
200
+    #
201
+    local vlt=$1
202
+    debugv vlt
203
+    local item
204
+    find "$vlt" -mindepth 1 -maxdepth 1 -printf "%P\n" \
205
+      | pfxpath "$vlt/" \
206
+      | grep -v "$Vault/dotvault" \
207
+      | while IFS= read -r item;
208
+        do
209
+            istarget "$item" && echo "$item"
210
+        done
211
+}
212
+
213
+make_links() {
214
+    #
215
+    # Create all links
216
+    #
217
+    local slpath
218
+    local target
219
+    local vlt
220
+    lsvault \
221
+      | while IFS= read -r vlt;
222
+        do
223
+            lstarget "$vlt" \
224
+              | while IFS= read -r target;
225
+                do
226
+                    slpath=$(slpath "$target")
227
+                    if test -L "$slpath";
228
+                    then
229
+                        $ClobberLinks || {
230
+                            warn "skipping existing slpath: $slpath"
231
+                            continue
232
+                        }
233
+                        think "removing existing link: $slpath"
234
+                        maybe rm "$slpath"
235
+                    fi
236
+                    test -e "$slpath" && {
237
+                        warn "skipping existing non-link: $slpath"
238
+                        continue
239
+                    }
240
+                    maybe ln -sr "$target" "$slpath"
241
+                done
242
+        done
243
+}
244
+
245
+explore() {
246
+    #
247
+    # Show what would be done
248
+    #
249
+    local vlt
250
+    local tgt
251
+    local tgts
252
+    lsvault \
253
+      | sort \
254
+      | while IFS= read -r vlt;
255
+        do
256
+            tgts=$(lstarget "$vlt")
257
+            test -n "$tgts" || continue
258
+            if test "$vlt" == "$Vault";
259
+            then
260
+                echo "VAULT:$vlt:"
261
+            else
262
+                echo
263
+                echo "SUBVAULT:$vlt"
264
+            fi
265
+            sort <<<"$tgts" \
266
+              | while IFS= read -r tgt;
267
+                do
268
+                    echo "${tgt}:$(slpath "$tgt")"
269
+                done \
270
+              | sed -e "s|:$HOME|:=> ~|" \
271
+              | column -ts: \
272
+              | sed -e "s/^/    /"
273
+        done
274
+}
275
+
276
+maybe() {
277
+    #
278
+    # Maybe do things $@, maybe not (if in debug mode)
279
+    #
280
+    $Debug && { debug "WOULD: $*"; return; }
281
+    "$@"
282
+}
283
+
284
+slpath() {
285
+    #
286
+    # Print path where to create link for target $1
287
+    #
288
+    local item=$1
289
+    echo "$HOME/.${item#$Vault/}"
290
+}
291
+
292
+route() {
293
+    local Vault=$1; shift
294
+    local SubVaults=()
295
+    test -n "$Vault" || usage
296
+    test -e "$Vault" || die "vault does not exist: $Vault"
297
+    test -d "$Vault" || die "vault is not a directory: $Vault"
298
+    SubVaults=("$@")
299
+    case $Action in
300
+        init)       make_links  ;;
301
+        explore)    explore     ;;
302
+        *)          usage       ;;
303
+    esac
304
+}
305
+
306
+export LC_ALL=C
307
+
308
+main() {
309
+    local Action
310
+    local Debug=false
311
+    local Verbose=false
312
+    local ClobberLinks=false
313
+    while true; do case $1 in
314
+        -d) Debug=true;         shift ;;
315
+        -v) Verbose=true;       shift ;;
316
+        -f) ClobberLinks=true;  shift ;;
317
+        -*)                     usage ;;
318
+        *)                      break ;;
319
+    esac done
320
+    Action=$1; shift
321
+    route "$@"
81 322
 }
82 323
 
83
-mklinks($dotroot);
84
-mklinks($dotroot, $_) foreach (@masks);
324
+main "$@"