| ... | ... |
@@ -11,6 +11,66 @@ functionality equivalent to `include config.d/*`. In essence, it is a glorified |
| 11 | 11 |
|
| 12 | 12 |
[`dotd`]: https://git.rcrnstn.net/rcrnstn/dotd |
| 13 | 13 |
|
| 14 |
+## Usage |
|
| 15 |
+ |
|
| 16 |
+`dotd --help`: |
|
| 17 |
+ |
|
| 18 |
+``` |
|
| 19 |
+dotd 1.0 |
|
| 20 |
+ |
|
| 21 |
+Generate a file from fragment files in a directory. |
|
| 22 |
+ |
|
| 23 |
+usage: |
|
| 24 |
+ dotd [options] [--] <file> [<dir>] |
|
| 25 |
+ dotd -h|--help |
|
| 26 |
+ dotd --version |
|
| 27 |
+ |
|
| 28 |
+arguments: |
|
| 29 |
+ <file> |
|
| 30 |
+ File to generate. Specify - to print to stdout instead. |
|
| 31 |
+ |
|
| 32 |
+ <dir> |
|
| 33 |
+ Directory containing fragment files. <file>.d is used if not |
|
| 34 |
+ specified. |
|
| 35 |
+ |
|
| 36 |
+options: |
|
| 37 |
+ -a, --action <action> |
|
| 38 |
+ Action to perform on each fragment file. E.g. |
|
| 39 |
+ printf "#include \"%s\"\n" |
|
| 40 |
+ [default: cat] |
|
| 41 |
+ |
|
| 42 |
+ -c, --comment <comment> |
|
| 43 |
+ If non-empty, adds comments starting with <comment> that the file is |
|
| 44 |
+ auto-generated and which fragment corresponds to which file. |
|
| 45 |
+ [default: ] |
|
| 46 |
+ |
|
| 47 |
+ -g, --glob <glob> |
|
| 48 |
+ Shell glob used to find fragment files, relative to <dir>. |
|
| 49 |
+ [default: *] |
|
| 50 |
+ |
|
| 51 |
+ -v, --validate <validate> |
|
| 52 |
+ Command to run on the (temporary) generated file. Only if the command |
|
| 53 |
+ returns success is the file moved to its final destination. E.g. |
|
| 54 |
+ /usr/sbin/sshd -t -f |
|
| 55 |
+ [default: ] |
|
| 56 |
+``` |
|
| 57 |
+ |
|
| 58 |
+## Dependencies |
|
| 59 |
+ |
|
| 60 |
+All dependencies are [POSIX][] and are highly likely to be installed by default |
|
| 61 |
+(e.g. they all have the [Debian priority][] `required`). |
|
| 62 |
+ |
|
| 63 |
+- `sh` (e.g. from [`bash`][] or [`dash`][]) |
|
| 64 |
+- `sed` (e.g. from [`sed`][]) |
|
| 65 |
+- `awk` (e.g. from [`mawk`][]) |
|
| 66 |
+ |
|
| 67 |
+[POSIX]: https://en.wikipedia.org/wiki/POSIX |
|
| 68 |
+[Debian priority]: https://www.debian.org/doc/debian-policy/ch-archive.html#s-priorities |
|
| 69 |
+[`bash`]: https://packages.debian.org/bash |
|
| 70 |
+[`dash`]: https://packages.debian.org/dash |
|
| 71 |
+[`sed`]: https://packages.debian.org/sed |
|
| 72 |
+[`mawk`]: https://packages.debian.org/mawk |
|
| 73 |
+ |
|
| 14 | 74 |
## Related projects |
| 15 | 75 |
|
| 16 | 76 |
- [Ansible][]'s [`assemble` module][]. |
| 17 | 77 |
new file mode 100755 |
| ... | ... |
@@ -0,0 +1,86 @@ |
| 1 |
+#!/bin/sh |
|
| 2 |
+set -euC |
|
| 3 |
+ |
|
| 4 |
+##/// dotd 1.0 |
|
| 5 |
+#//// |
|
| 6 |
+#//// Generate a file from fragment files in a directory. |
|
| 7 |
+#//// |
|
| 8 |
+###// usage: |
|
| 9 |
+#//// dotd [options] [--] <file> [<dir>] |
|
| 10 |
+#//// dotd -h|--help |
|
| 11 |
+#//// dotd --version |
|
| 12 |
+#//// |
|
| 13 |
+###// arguments: |
|
| 14 |
+####/ <file> |
|
| 15 |
+#//// File to generate. Specify - to print to stdout instead. |
|
| 16 |
+#//// |
|
| 17 |
+####/ <dir> |
|
| 18 |
+#//// Directory containing fragment files. <file>.d is used if not |
|
| 19 |
+#//// specified. |
|
| 20 |
+#//// |
|
| 21 |
+###// options: |
|
| 22 |
+####/ -a, --action <action> |
|
| 23 |
+#//// Action to perform on each fragment file. E.g. |
|
| 24 |
+#//// printf "#include \"%s\"\n" |
|
| 25 |
+#//// [default: cat] |
|
| 26 |
+#//// |
|
| 27 |
+####/ -c, --comment <comment> |
|
| 28 |
+#//// If non-empty, adds comments starting with <comment> that the file is |
|
| 29 |
+#//// auto-generated and which fragment corresponds to which file. |
|
| 30 |
+#//// [default: ] |
|
| 31 |
+#//// |
|
| 32 |
+####/ -g, --glob <glob> |
|
| 33 |
+#//// Shell glob used to find fragment files, relative to <dir>. |
|
| 34 |
+#//// [default: *] |
|
| 35 |
+#//// |
|
| 36 |
+####/ -v, --validate <validate> |
|
| 37 |
+#//// Command to run on the (temporary) generated file. Only if the command |
|
| 38 |
+#//// returns success is the file moved to its final destination. E.g. |
|
| 39 |
+#//// /usr/sbin/sshd -t -f |
|
| 40 |
+#//// [default: ] |
|
| 41 |
+ |
|
| 42 |
+## Messages |
|
| 43 |
+help() { sed -n 's|^#[#/]*/ \?||p' "$0"; exit 0; }
|
|
| 44 |
+version() { help | awk '/^$/{++p;next}p==0'; exit 0; }
|
|
| 45 |
+usage() { help | awk '/^$/{++p;next}p==2'; exit 0; }
|
|
| 46 |
+parse() { printf '%s: error: %s\n' "$0" "$1"; usage; exit 1; } >&2
|
|
| 47 |
+error() { printf '%s: error: %s\n' "$0" "$1"; exit 1; } >&2
|
|
| 48 |
+warning() { printf '%s: warning: %s\n' "$0" "$1"; } >&2
|
|
| 49 |
+opt() { [ $# -gt 1 ] || parse "option '$1' value not provided"; }
|
|
| 50 |
+arg() { [ $# -gt 1 ] || parse "argument '$1' not provided"; }
|
|
| 51 |
+ |
|
| 52 |
+## Parse special options |
|
| 53 |
+case "${1-}"
|
|
| 54 |
+in |
|
| 55 |
+ '-h'|'--help') help; ;; |
|
| 56 |
+ '--version') version; ;; |
|
| 57 |
+esac |
|
| 58 |
+ |
|
| 59 |
+## Parse options |
|
| 60 |
+action='cat' |
|
| 61 |
+comment='' |
|
| 62 |
+glob='*' |
|
| 63 |
+validate='' |
|
| 64 |
+while [ $# -gt 0 ] |
|
| 65 |
+do |
|
| 66 |
+ case "$1" |
|
| 67 |
+ in |
|
| 68 |
+ '-a'|'--action') shift; opt 'action' "$@"; action="$1"; ;; |
|
| 69 |
+ '-c'|'--comment') shift; opt 'comment' "$@"; comment="$1"; ;; |
|
| 70 |
+ '-g'|'--glob') shift; opt 'glob' "$@"; glob="$1"; ;; |
|
| 71 |
+ '-v'|'--validate') shift; opt 'validate' "$@"; validate="$1"; ;; |
|
| 72 |
+ '--') shift; break; ;; |
|
| 73 |
+ '-'?*) parse "unrecognized option '$1'"; ;; |
|
| 74 |
+ *) break; ;; |
|
| 75 |
+ esac |
|
| 76 |
+ shift |
|
| 77 |
+done |
|
| 78 |
+ |
|
| 79 |
+## Parse required arguments |
|
| 80 |
+arg 'file' "$@"; file="$1"; shift; |
|
| 81 |
+ |
|
| 82 |
+## Parse optional arguments |
|
| 83 |
+dir="${1-}"; shift $(($#>0));
|
|
| 84 |
+ |
|
| 85 |
+## Parse unrecognized arguments |
|
| 86 |
+[ $# -eq 0 ] || parse "unrecognized argument: '$1'" |