... | ... |
@@ -9,6 +9,10 @@ each other's toes, when the native configuration language does not support |
9 | 9 |
functionality equivalent to `include config.d/*`. In essence, it is a glorified |
10 | 10 |
`cat config.d/* > config`. |
11 | 11 |
|
12 |
+The generated file is compared against any pre-existing file, if they differ a |
|
13 |
+warning is printed and the pre-existing file is moved to a backup file whose |
|
14 |
+name includes a time stamp. |
|
15 |
+ |
|
12 | 16 |
[`dotd`]: https://git.rcrnstn.net/rcrnstn/dotd |
13 | 17 |
|
14 | 18 |
## Usage |
... | ... |
@@ -41,11 +45,13 @@ options: |
41 | 45 |
|
42 | 46 |
-c, --comment <comment> |
43 | 47 |
If non-empty, adds comments starting with <comment> that the file is |
44 |
- auto-generated and which fragment corresponds to which file. |
|
48 |
+ auto-generated and which fragment corresponds to which file. E.g. |
|
49 |
+ // |
|
45 | 50 |
[default: ] |
46 | 51 |
|
47 | 52 |
-g, --glob <glob> |
48 |
- Shell glob used to find fragment files, relative to <dir>. |
|
53 |
+ Shell glob used to find fragment files, relative to <dir>. E.g |
|
54 |
+ *.h |
|
49 | 55 |
[default: *] |
50 | 56 |
|
51 | 57 |
-v, --validate <validate> |
... | ... |
@@ -57,10 +63,13 @@ options: |
57 | 63 |
|
58 | 64 |
## Dependencies |
59 | 65 |
|
60 |
-All dependencies are [POSIX][] and are highly likely to be installed by default |
|
61 |
-(e.g. they all have the [Debian priority][] `required`). |
|
66 |
+All dependencies are [POSIX][] (except `mktemp`, but most Unix-like systems |
|
67 |
+have some version), and are highly likely to be installed by default (e.g. they |
|
68 |
+all have the [Debian priority][] `required`). |
|
62 | 69 |
|
63 | 70 |
- `sh` (e.g. from [`bash`][] or [`dash`][]) |
71 |
+- `rm`, `mv`, `tail`, `date`, `mktemp` (e.g. from [`coreutils`][]) |
|
72 |
+- `cmp` (e.g. from [`diffutils`][]) |
|
64 | 73 |
- `sed` (e.g. from [`sed`][]) |
65 | 74 |
- `awk` (e.g. from [`mawk`][]) |
66 | 75 |
|
... | ... |
@@ -68,6 +77,8 @@ All dependencies are [POSIX][] and are highly likely to be installed by default |
68 | 77 |
[Debian priority]: https://www.debian.org/doc/debian-policy/ch-archive.html#s-priorities |
69 | 78 |
[`bash`]: https://packages.debian.org/bash |
70 | 79 |
[`dash`]: https://packages.debian.org/dash |
80 |
+[`coreutils`]: https://packages.debian.org/coreutils |
|
81 |
+[`diffutils`]: https://packages.debian.org/diffutils |
|
71 | 82 |
[`sed`]: https://packages.debian.org/sed |
72 | 83 |
[`mawk`]: https://packages.debian.org/mawk |
73 | 84 |
|
... | ... |
@@ -26,11 +26,13 @@ set -euC |
26 | 26 |
#//// |
27 | 27 |
####/ -c, --comment <comment> |
28 | 28 |
#//// If non-empty, adds comments starting with <comment> that the file is |
29 |
-#//// auto-generated and which fragment corresponds to which file. |
|
29 |
+#//// auto-generated and which fragment corresponds to which file. E.g. |
|
30 |
+#//// // |
|
30 | 31 |
#//// [default: ] |
31 | 32 |
#//// |
32 | 33 |
####/ -g, --glob <glob> |
33 |
-#//// Shell glob used to find fragment files, relative to <dir>. |
|
34 |
+#//// Shell glob used to find fragment files, relative to <dir>. E.g. |
|
35 |
+#//// *.h |
|
34 | 36 |
#//// [default: *] |
35 | 37 |
#//// |
36 | 38 |
####/ -v, --validate <validate> |
... | ... |
@@ -84,3 +86,68 @@ dir="${1-}"; shift $(($#>0)); |
84 | 86 |
|
85 | 87 |
## Parse unrecognized arguments |
86 | 88 |
[ $# -eq 0 ] || parse "unrecognized argument: '$1'" |
89 |
+ |
|
90 |
+## Helpers |
|
91 |
+first='y' |
|
92 |
+comment_last="$(printf '%s' "$comment" | tail -c 1)" |
|
93 |
+empty() |
|
94 |
+{ |
|
95 |
+ ! [ "$first" ] && [ "$comment" ] || return 0 |
|
96 |
+ printf '\n' |
|
97 |
+} |
|
98 |
+comment() |
|
99 |
+{ |
|
100 |
+ [ "$comment" ] || return 0 |
|
101 |
+ printf '%s\n' "$1" |
|
102 |
+ first='' |
|
103 |
+} |
|
104 |
+action() |
|
105 |
+{ |
|
106 |
+ eval "$action" "'$1'" |
|
107 |
+ first='' |
|
108 |
+} |
|
109 |
+ |
|
110 |
+## Set dir |
|
111 |
+if ! [ "$dir" ] |
|
112 |
+then |
|
113 |
+ [ "$file" != "-" ] || error "must specify <dir> when printing to stdout" |
|
114 |
+ dir="$file.d" |
|
115 |
+fi |
|
116 |
+ |
|
117 |
+## Generate temporary file |
|
118 |
+file_tmp="$(mktemp)" |
|
119 |
+{ |
|
120 |
+ comment "$comment This file was auto-generated from '$dir/$glob'." |
|
121 |
+ for path in $dir/$glob |
|
122 |
+ do |
|
123 |
+ [ -r "$path" ] || continue |
|
124 |
+ empty |
|
125 |
+ comment "$comment$comment_last BEGIN $path" |
|
126 |
+ action "$path" |
|
127 |
+ comment "$comment END $path" |
|
128 |
+ done |
|
129 |
+} >> "$file_tmp" |
|
130 |
+ |
|
131 |
+## Validate |
|
132 |
+if [ "$validate" ] && ! eval "$validate" "'$file_tmp'" |
|
133 |
+then |
|
134 |
+ rm "$file_tmp" |
|
135 |
+ error "validation failed: $validate" |
|
136 |
+fi |
|
137 |
+ |
|
138 |
+## Optionally print to stdout |
|
139 |
+if [ "$file" = "-" ] |
|
140 |
+then |
|
141 |
+ cat "$file_tmp" |
|
142 |
+ rm "$file_tmp" |
|
143 |
+ exit 0 |
|
144 |
+fi |
|
145 |
+ |
|
146 |
+## Otherwise move files |
|
147 |
+if [ -e "$file" ] && ! cmp -s "$file_tmp" "$file" |
|
148 |
+then |
|
149 |
+ file_bak="$(mktemp "$file.$(date "+%Y-%m-%d_%H:%M:%S").XXXX.bak")" |
|
150 |
+ warning "moving '$file' to '$file_bak'" |
|
151 |
+ mv "$file" "$file_bak" |
|
152 |
+fi |
|
153 |
+mv -f "$file_tmp" "$file" |