#!/bin/bash shellfu import pretty _dottum__slstatus() { # # Print status of slpath $1 # local slpath=$1 local tlink=0 local texis=0 test -L "$slpath"; tlink=$? test -e "$slpath"; texis=$? case $tlink:$texis in 0:0) echo symlink ;; 0:1) echo broken ;; 1:0) echo nonlink ;; 1:1) echo nothing ;; *) warn "strange resiult: tlink=$tlink texis=$texis" ;; esac } dottum__lssv() { # # List sub-vaults # # Sub-vault is a sub-path of vault directory that contains items # that should be linked separately, to a similar $HOME subpath, # rather than linking the whole sub-tree. This is typical for # .config directory specified by XDG standard. # # For example, imagine vault like this: # # dotfiles/ # ├── config # │   ├── dunst # │   │   └── dunstrc # │   └── uzbl # │      ├── config # │      └── style.css # ├── i3 # │   └── config # ├── i3status.conf # └── vimrc # # Without sub-vault, the "config" would be linked as "$HOME/.config": # # $HOME/.config -> dotfiles/.config # $HOME/.i3 -> dotfiles/i3 # $HOME/.i3status.conf -> dotfiles/i3status.conf # $HOME/.vimrc -> dotfiles/vimrc # # This is impractical in most cases, as normally you want to select # applications to link--some dotfiles could be specific to some # hosts or even private. # # Setting 'config' as sub-vault will tell mklinks that you don't # want to link this item directly but rather each of its items: # # $HOME/.config/dunst -> dotfiles/config/dunst # $HOME/.config/uzbl -> dotfiles/config/uzbl # $HOME/.i3 -> dotfiles/i3 # $HOME/.i3status.conf -> dotfiles/i3status.conf # $HOME/.vimrc -> dotfiles/vimrc # # This way, you can have other items under "$HOME/.config" that # are either purely local or linked to another vault. # # Note that the subvault can be deeper than one level, i.e. # subvault "local/share" also works: # # $HOME/.local/share/klavaro -> dotfiles/local/share/klavaro # local sv test -n "${SubVaults[0]}" && { think "using sub-vaults from command line" for sv in "${SubVaults[@]}"; do echo "$sv" done return } test -f "$Vault/dotvault/subvaults" && { think "reading subvaults from file: $Vault/dotvault/subvaults" grep . "$Vault/dotvault/subvaults" \ | grep -v "^#.*" return } think "using hard-coded list of subvaults" echo config } dottum__lsvault() { # # List all vaults and subvaults, depth-first # { echo "$Vault" dottum__lssv \ | while IFS= read -r sv; do test -e "$Vault/$sv" || { think "ignoring non-existent sub-vault: $sv" continue } test -d "$Vault/$sv" || { warn "ignoring non-directory sub-vault: $sv" continue } echo "$Vault/$sv" done } \ | LC_ALL=C sort \ | tac } dottum__istarget() { # # True if item $1 is possible target # # Item is obviously not a possible target if it's # a (sub-)vault. # # A less obvious case is when item is an intermediate directory # on a path leading to a sub-vault. Such item cannot be a target! # # For example: there are sub-vaults: # # foo # foo/bar/baz # # and a tree: # # foo # ├── A # └── bar # └── baz # └── B # # Items A and B could both be targets, but baz could not be! # #TODO: write an explanation # local item=$1 debug -v item Verbose=false dottum__lsvault | grep -qxF "$item" && return 1 Verbose=false dottum__lsvault | grep -qx "$item/.*" && return 1 return 0 } dottum__pfxpath() { # # Prefix paths with $1 # # Just like `sed "s/^/$1/" but works with any characters # in $1 excepr newline, which is not allowed in paths.. # local pfx="$1" local path while IFS= read -r path; do echo "$pfx$path" done } dottum__lstarget() { # # List potential items in vault $1 # local vlt=$1 debug -v vlt local item find "$vlt" -mindepth 1 -maxdepth 1 -printf "%P\n" \ | dottum__pfxpath "$vlt/" \ | grep -v "$Vault/dotvault" \ | while IFS= read -r item; do dottum__istarget "$item" && echo "$item" done } dottum__make_links() { # # Create all links # local slpath local target local vlt local slstatus dottum__lsvault \ | while IFS= read -r vlt; do dottum__lstarget "$vlt" \ | while IFS= read -r target; do slpath=$(dottum__slpath "$target") slstatus=$(_dottum__slstatus "$slpath") debug -v slpath slstatus case $slstatus in nonlink) warn "skipping existing non-link: $slpath" continue ;; broken) if $ClobberLinks || $ClobberBroken; then think "removing existing broken link: $slpath" dottum__maybe rm "$slpath" else warn "skipping existing broken link: $slpath" continue fi ;; symlink) if $ClobberLinks; then think "removing existing link: $slpath" dottum__maybe rm "$slpath" else warn "skipping existing slpath: $slpath" continue fi ;; esac dottum__maybe ln -sr "$target" "$slpath" done done } dottum__explore() { # # Show what would be done # local vlt local tgt local tgts dottum__lsvault \ | sort \ | while IFS= read -r vlt; do tgts=$(dottum__lstarget "$vlt") test -n "$tgts" || continue if test "$vlt" == "$Vault"; then echo "VAULT:$vlt:" else echo echo "SUBVAULT:$vlt" fi sort <<<"$tgts" \ | while IFS= read -r tgt; do echo "${tgt}:$(dottum__slpath "$tgt")" done \ | sed -e "s|:$HOME|:=> ~|" \ | column -ts: \ | sed -e "s/^/ /" done } dottum__maybe() { # # Maybe do things $@, maybe not (if in debug mode) # $PRETTY_DEBUG && { debug "MAYBE:$*"; return; } "$@" } dottum__slpath() { # # Print path where to create link for target $1 # local item=$1 echo "$HOME/.${item#$Vault/}" }