dottum.sh 7.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. #!/bin/bash
  2. shellfu import pretty
  3. #
  4. # Should broken links be silently overwritten?
  5. #
  6. DOTTUM__CLOBBER_BROKEN=false
  7. #
  8. # Should all links be silently overwritten?
  9. #
  10. DOTTUM__CLOBBER_LINKS=false
  11. #
  12. # List of subvalults passed on command line
  13. #
  14. # This is added to the front of list in *subvalults* file.
  15. #
  16. DOTTUM__SUBVAULTS=()
  17. #
  18. # Vault to process
  19. #
  20. DOTTUM__VAULT=""
  21. _dottum__slstatus() {
  22. #
  23. # Print status of slpath $1
  24. #
  25. local slpath=$1
  26. local tlink=0
  27. local texis=0
  28. test -L "$slpath"; tlink=$?
  29. test -e "$slpath"; texis=$?
  30. case $tlink:$texis in
  31. 0:0) echo symlink ;;
  32. 0:1) echo broken ;;
  33. 1:0) echo nonlink ;;
  34. 1:1) echo nothing ;;
  35. *) warn "strange resiult: tlink=$tlink texis=$texis" ;;
  36. esac
  37. }
  38. dottum__lssv() {
  39. #
  40. # List sub-vaults
  41. #
  42. # Sub-vault is a sub-path of vault directory that contains items
  43. # that should be linked separately, to a similar $HOME subpath,
  44. # rather than linking the whole sub-tree. This is typical for
  45. # .config directory specified by XDG standard.
  46. #
  47. # For example, imagine vault like this:
  48. #
  49. # dotfiles/
  50. # ├── config
  51. # │   ├── dunst
  52. # │   │   └── dunstrc
  53. # │   └── uzbl
  54. # │      ├── config
  55. # │      └── style.css
  56. # ├── i3
  57. # │   └── config
  58. # ├── i3status.conf
  59. # └── vimrc
  60. #
  61. # Without sub-vault, the "config" would be linked as "$HOME/.config":
  62. #
  63. # $HOME/.config -> dotfiles/.config
  64. # $HOME/.i3 -> dotfiles/i3
  65. # $HOME/.i3status.conf -> dotfiles/i3status.conf
  66. # $HOME/.vimrc -> dotfiles/vimrc
  67. #
  68. # This is impractical in most cases, as normally you want to select
  69. # applications to link--some dotfiles could be specific to some
  70. # hosts or even private.
  71. #
  72. # Setting 'config' as sub-vault will tell mklinks that you don't
  73. # want to link this item directly but rather each of its items:
  74. #
  75. # $HOME/.config/dunst -> dotfiles/config/dunst
  76. # $HOME/.config/uzbl -> dotfiles/config/uzbl
  77. # $HOME/.i3 -> dotfiles/i3
  78. # $HOME/.i3status.conf -> dotfiles/i3status.conf
  79. # $HOME/.vimrc -> dotfiles/vimrc
  80. #
  81. # This way, you can have other items under "$HOME/.config" that
  82. # are either purely local or linked to another vault.
  83. #
  84. # Note that the subvault can be deeper than one level, i.e.
  85. # subvault "local/share" also works:
  86. #
  87. # $HOME/.local/share/klavaro -> dotfiles/local/share/klavaro
  88. #
  89. local sv
  90. test -n "${DOTTUM__SUBVAULTS[0]}" && {
  91. think "using sub-vaults from command line"
  92. for sv in "${DOTTUM__SUBVAULTS[@]}";
  93. do
  94. echo "$sv"
  95. done
  96. return
  97. }
  98. test -f "$DOTTUM__VAULT/dotvault/subvaults" && {
  99. think "reading subvaults from file: $DOTTUM__VAULT/dotvault/subvaults"
  100. grep . "$DOTTUM__VAULT/dotvault/subvaults" \
  101. | grep -v "^#.*"
  102. return
  103. }
  104. think "using hard-coded list of subvaults"
  105. echo config
  106. }
  107. dottum__lsvault() {
  108. #
  109. # List all vaults and subvaults, depth-first
  110. #
  111. {
  112. echo "$DOTTUM__VAULT"
  113. dottum__lssv \
  114. | while IFS= read -r sv;
  115. do
  116. test -e "$DOTTUM__VAULT/$sv" || {
  117. think "ignoring non-existent sub-vault: $sv"
  118. continue
  119. }
  120. test -d "$DOTTUM__VAULT/$sv" || {
  121. warn "ignoring non-directory sub-vault: $sv"
  122. continue
  123. }
  124. echo "$DOTTUM__VAULT/$sv"
  125. done
  126. } \
  127. | LC_ALL=C sort \
  128. | tac
  129. }
  130. dottum__istarget() {
  131. #
  132. # True if item $1 is possible target
  133. #
  134. # Item is obviously not a possible target if it's
  135. # a (sub-)vault.
  136. #
  137. # A less obvious case is when item is an intermediate directory
  138. # on a path leading to a sub-vault. Such item cannot be a target!
  139. #
  140. # For example: there are sub-vaults:
  141. #
  142. # foo
  143. # foo/bar/baz
  144. #
  145. # and a tree:
  146. #
  147. # foo
  148. # ├── A
  149. # └── bar
  150. # └── baz
  151. # └── B
  152. #
  153. # Items A and B could both be targets, but baz could not be!
  154. #
  155. #TODO: write an explanation
  156. #
  157. local item=$1
  158. debug -v item
  159. Verbose=false dottum__lsvault | grep -qxFe "$item" && return 1
  160. Verbose=false dottum__lsvault | grep -qxe "$item/.*" && return 1
  161. return 0
  162. }
  163. dottum__pfxpath() {
  164. #
  165. # Prefix paths with $1
  166. #
  167. # Just like `sed "s/^/$1/" but works with any characters
  168. # in $1 excepr newline, which is not allowed in paths..
  169. #
  170. local pfx="$1"
  171. local path
  172. while IFS= read -r path;
  173. do
  174. echo "$pfx$path"
  175. done
  176. }
  177. dottum__lstarget() {
  178. #
  179. # List potential items in vault $1
  180. #
  181. local vlt=$1
  182. debug -v vlt
  183. local item
  184. find "$vlt" -mindepth 1 -maxdepth 1 -printf "%P\n" \
  185. | dottum__pfxpath "$vlt/" \
  186. | grep -ve "$DOTTUM__VAULT/dotvault" \
  187. | while IFS= read -r item;
  188. do
  189. dottum__istarget "$item" && echo "$item"
  190. done
  191. }
  192. dottum__make_links() {
  193. #
  194. # Create all links
  195. #
  196. local slpath
  197. local target
  198. local vlt
  199. local slstatus
  200. dottum__lsvault \
  201. | while IFS= read -r vlt;
  202. do
  203. dottum__lstarget "$vlt" \
  204. | while IFS= read -r target;
  205. do
  206. slpath=$(dottum__slpath "$target")
  207. slstatus=$(_dottum__slstatus "$slpath")
  208. debug -v slpath slstatus
  209. case $slstatus in
  210. nonlink)
  211. warn "skipping existing non-link: $slpath"
  212. continue
  213. ;;
  214. broken)
  215. if $DOTTUM__CLOBBER_LINKS || $DOTTUM__CLOBBER_BROKEN; then
  216. think "removing existing broken link: $slpath"
  217. dottum__maybe rm "$slpath"
  218. else
  219. warn "skipping existing broken link: $slpath"
  220. continue
  221. fi
  222. ;;
  223. symlink)
  224. if $DOTTUM__CLOBBER_LINKS; then
  225. think "removing existing link: $slpath"
  226. dottum__maybe rm "$slpath"
  227. else
  228. warn "skipping existing slpath: $slpath"
  229. continue
  230. fi
  231. ;;
  232. esac
  233. dottum__maybe ln -sr "$target" "$slpath"
  234. done
  235. done
  236. }
  237. dottum__explore() {
  238. #
  239. # Show what would be done
  240. #
  241. local vlt
  242. local tgt
  243. local tgts
  244. dottum__lsvault \
  245. | sort \
  246. | while IFS= read -r vlt;
  247. do
  248. tgts=$(dottum__lstarget "$vlt")
  249. test -n "$tgts" || continue
  250. if test "$vlt" == "$DOTTUM__VAULT";
  251. then
  252. echo "VAULT:$vlt:"
  253. else
  254. echo
  255. echo "SUBVAULT:$vlt"
  256. fi
  257. sort <<<"$tgts" \
  258. | while IFS= read -r tgt;
  259. do
  260. echo "${tgt}:$(dottum__slpath "$tgt")"
  261. done \
  262. | sed -e "s|:$HOME|:=> ~|" \
  263. | column -ts: \
  264. | sed -e "s/^/ /"
  265. done
  266. }
  267. dottum__maybe() {
  268. #
  269. # Maybe do things $@, maybe not (if in debug mode)
  270. #
  271. $PRETTY_DEBUG && { debug "MAYBE:$*"; return; }
  272. "$@"
  273. }
  274. dottum__slpath() {
  275. #
  276. # Print path where to create link for target $1
  277. #
  278. local item=$1
  279. echo "$HOME/.${item#$DOTTUM__VAULT/}"
  280. }