This repository has been archived by the owner on Jan 23, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
recache
executable file
·93 lines (80 loc) · 3.51 KB
/
recache
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#!/usr/bin/bash
#
# SPDX-FileCopyrightText: 2019 Dmytro Kolomoiets <amerlyq@gmail.com> and contributors
#
# SPDX-License-Identifier: Apache-2.0
#
# RENAME: xdg-db
#%SUMMARY: cache symlinks to all commands found under XDG paths
#%USAGE:(once): export APP_CACHE_DIR=$(app-xdg-cache app); exec app "$@"
#%PERF: first=37ms idle=23ms
set -fCueo pipefail
# DEV: clean-up cache dir from previous stale symlinks (and only symlinks -- keep other data)
# NEED: I need cleanup for old links
# <= earlier I had no such problem due to using text file recreated each time...
# MAYBE:IDEA: dump list of symlinks into stampfile and then cleanup from folder all links not in that file ?
# PERF:BAD: twice the work to recache
# MAYBE: also use ~/.local/share/wiw as fallback locations for some data e.g. user output templates ?
## ALT:
# [[ ${GUARDED+x} ]] || GUARDED="$0" exec flock --exclusive --no-fork "$0" "$0" "$@"
# unset GUARDED
# set -r
# FIXED: concurrent caching on very first run by two piped processes $ app ... | app ...
# EXPL: detect concurrent process, wait until it releases lock, do not try to recache again
exec {lock_fd}< "$0"
if ! flock --exclusive --no-fork --nonblock "$lock_fd"; then
flock --exclusive --no-fork "$lock_fd"
exec "$@" {lock_fd}>&-
fi
dcache=${SUITE_CACHE_HOME:?}
execpath=${SUITE_LIBEXEC_PATH:?}
# ATT: don't try to read STDIN directly -- "./$0" is part of global chain
nl=$'\n'
exec <<< "${execpath//:/$nl}"
dirs_validate(){ declare -rn ds=$1; ds=()
while IFS= read -r d; do [[ -d $d ]] && ds+=("$d"); done
((${#ds[@]})) || return 1
}
# shellcheck disable=SC2178
dirs_merge(){ declare -rn ds=$1; shift
find -H "${ds[@]}" -mindepth 1 -xdev \( -name '_*' -o -name '.git' \) -prune -o \
"$@" -printf '%P:%p\n' | awk -F: '!a[$1]++ && $2'
}
## ERROR: must only create symlinks to "./exefile" and other "abspath-symlinks" without resolution
## !! all "relative-symlinks" pointing inside suite must be copied as-is !!
#
# if [[ -L $d/$nm && -L $pth ]]; then
# src=$(readlink -- "$pth")
# dst=$(readlink -- "$d/$nm")
# [[ $src == "$dst" ]] && continue
# fi
cache_exe(){ local -r d=$1; shift
while IFS=: read -r nm pth; do
# DEBUG: >&2 echo "$nm : $pth : $d/${nm%/*}"
[[ $d/$nm -ef $pth ]] && continue
[[ $nm =~ / ]] && mkdir -p "$d/${nm%/*}"
command ln -sfPT -- "$pth" "$d/$nm"
done
}
# THINK:BET: only allow symlinks pointing inside "lpath" -- use XDG_LIBEXEC_DIRS for other locations
# OR?BAD: anywhere (so user could deploy by symlinks) ?
# MAYBE: symlinks to dir -- inside "lpath", but symlinks to file -- anywhere ?
# NICE: you can symlink your private extensions into std dirs instead of modifying ENV paths
# BAD:SECU: end-file can be uncontrollably replaced by something harmful
# PERF:RFC: apply "realpath" to many files in one go -- then find "diff/comm" between two files and apply "cp" to it
copy_symlinks(){ local d=$1 src dst; shift
while IFS=: read -r nm pth; do
## NOTE: copying dangling symlinks is actually OK -- they can be aliases to another layer of suite
src=$(realpath -m --relative-base="${pth%/$nm}" -- "$pth")
[[ $src == /* ]] && >&2 echo "Warn: ignoring external symlink=$pth" && continue
dst=$(realpath -m --relative-base="$d" -- "$d/$nm")
[[ $src == "$dst" ]] && continue
[[ $nm =~ / ]] && mkdir -p "$d/${nm%/*}"
command cp -afPT -- "$pth" "$d/$nm"
done
}
dirs_validate lpath
dirs_merge lpath -xtype f -executable | cache_exe "$dcache"
dirs_merge lpath -type l | copy_symlinks "$dcache"
# ALT: flock --unlock "$lock_fd"
exec "$@" {lock_fd}>&-