python311Packages.moto: 4.2.6 -> 4.2.10
[NixPkgs.git] / pkgs / build-support / setup-hooks / install-shell-files.sh
blob194b408b105019886bf6c70c4d3ea8eccf5bde6a
1 # shellcheck shell=bash
2 # Setup hook for the `installShellFiles` package.
4 # Example usage in a derivation:
6 # { …, installShellFiles, … }:
7 # stdenv.mkDerivation {
8 # …
9 # nativeBuildInputs = [ installShellFiles ];
10 # postInstall = ''
11 # installManPage share/doc/foobar.1
12 # installShellCompletion share/completions/foobar.{bash,fish,zsh}
13 # '';
14 # …
15 # }
17 # See comments on each function for more details.
19 # installManPage <path> [...<path>]
21 # Each argument is checked for its man section suffix and installed into the appropriate
22 # share/man/man<n>/ directory. The function returns an error if any paths don't have the man
23 # section suffix (with optional .gz compression).
24 installManPage() {
25 local path
26 for path in "$@"; do
27 if (( "${NIX_DEBUG:-0}" >= 1 )); then
28 echo "installManPage: installing $path"
30 if test -z "$path"; then
31 echo "installManPage: error: path cannot be empty" >&2
32 return 1
34 local basename
35 basename=$(stripHash "$path") # use stripHash in case it's a nix store path
36 local trimmed=${basename%.gz} # don't get fooled by compressed manpages
37 local suffix=${trimmed##*.}
38 if test -z "$suffix" -o "$suffix" = "$trimmed"; then
39 echo "installManPage: error: path missing manpage section suffix: $path" >&2
40 return 1
42 local outRoot
43 if test "$suffix" = 3; then
44 outRoot=${!outputDevman:?}
45 else
46 outRoot=${!outputMan:?}
48 install -Dm644 -T "$path" "${outRoot}/share/man/man$suffix/$basename" || return
49 done
52 # installShellCompletion [--cmd <name>] ([--bash|--fish|--zsh] [--name <name>] <path>)...
54 # Each path is installed into the appropriate directory for shell completions for the given shell.
55 # If one of `--bash`, `--fish`, or `--zsh` is given the path is assumed to belong to that shell.
56 # Otherwise the file extension will be examined to pick a shell. If the shell is unknown a warning
57 # will be logged and the command will return a non-zero status code after processing any remaining
58 # paths. Any of the shell flags will affect all subsequent paths (unless another shell flag is
59 # given).
61 # If the shell completion needs to be renamed before installing the optional `--name <name>` flag
62 # may be given. Any name provided with this flag only applies to the next path.
64 # If all shell completions need to be renamed before installing the optional `--cmd <name>` flag
65 # may be given. This will synthesize a name for each file, unless overridden with an explicit
66 # `--name` flag. For example, `--cmd foobar` will synthesize the name `_foobar` for zsh and
67 # `foobar.bash` for bash.
69 # For zsh completions, if the `--name` flag is not given, the path will be automatically renamed
70 # such that `foobar.zsh` becomes `_foobar`.
72 # A path may be a named fd, such as produced by the bash construct `<(cmd)`. When using a named fd,
73 # the shell type flag must be provided, and either the `--name` or `--cmd` flag must be provided.
74 # This might look something like:
76 # installShellCompletion --zsh --name _foobar <($out/bin/foobar --zsh-completion)
78 # This command accepts multiple shell flags in conjunction with multiple paths if you wish to
79 # install them all in one command:
81 # installShellCompletion share/completions/foobar.{bash,fish} --zsh share/completions/_foobar
83 # However it may be easier to read if each shell is split into its own invocation, especially when
84 # renaming is involved:
86 # installShellCompletion --bash --name foobar.bash share/completions.bash
87 # installShellCompletion --fish --name foobar.fish share/completions.fish
88 # installShellCompletion --zsh --name _foobar share/completions.zsh
90 # Or to use shell newline escaping to split a single invocation across multiple lines:
92 # installShellCompletion --cmd foobar \
93 # --bash <($out/bin/foobar --bash-completion) \
94 # --fish <($out/bin/foobar --fish-completion) \
95 # --zsh <($out/bin/foobar --zsh-completion)
97 # If any argument is `--` the remaining arguments will be treated as paths.
98 installShellCompletion() {
99 local shell='' name='' cmdname='' retval=0 parseArgs=1 arg
100 while { arg=$1; shift; }; do
101 # Parse arguments
102 if (( parseArgs )); then
103 case "$arg" in
104 --bash|--fish|--zsh)
105 shell=${arg#--}
106 continue;;
107 --name)
108 name=$1
109 shift || {
110 echo 'installShellCompletion: error: --name flag expected an argument' >&2
111 return 1
113 continue;;
114 --name=*)
115 # treat `--name=foo` the same as `--name foo`
116 name=${arg#--name=}
117 continue;;
118 --cmd)
119 cmdname=$1
120 shift || {
121 echo 'installShellCompletion: error: --cmd flag expected an argument' >&2
122 return 1
124 continue;;
125 --cmd=*)
126 # treat `--cmd=foo` the same as `--cmd foo`
127 cmdname=${arg#--cmd=}
128 continue;;
129 --?*)
130 echo "installShellCompletion: warning: unknown flag ${arg%%=*}" >&2
131 retval=2
132 continue;;
134 # treat remaining args as paths
135 parseArgs=0
136 continue;;
137 esac
139 if (( "${NIX_DEBUG:-0}" >= 1 )); then
140 echo "installShellCompletion: installing $arg${name:+ as $name}"
142 # if we get here, this is a path or named pipe
143 # Identify shell and output name
144 local curShell=$shell
145 local outName=''
146 if [[ -z "$arg" ]]; then
147 echo "installShellCompletion: error: empty path is not allowed" >&2
148 return 1
149 elif [[ -p "$arg" ]]; then
150 # this is a named fd or fifo
151 if [[ -z "$curShell" ]]; then
152 echo "installShellCompletion: error: named pipe requires one of --bash, --fish, or --zsh" >&2
153 return 1
154 elif [[ -z "$name" && -z "$cmdname" ]]; then
155 echo "installShellCompletion: error: named pipe requires one of --cmd or --name" >&2
156 return 1
158 else
159 # this is a path
160 local argbase
161 argbase=$(stripHash "$arg")
162 if [[ -z "$curShell" ]]; then
163 # auto-detect the shell
164 case "$argbase" in
165 ?*.bash) curShell=bash;;
166 ?*.fish) curShell=fish;;
167 ?*.zsh) curShell=zsh;;
169 if [[ "$argbase" = _* && "$argbase" != *.* ]]; then
170 # probably zsh
171 echo "installShellCompletion: warning: assuming path \`$arg' is zsh; please specify with --zsh" >&2
172 curShell=zsh
173 else
174 echo "installShellCompletion: warning: unknown shell for path: $arg" >&2
175 retval=2
176 continue
177 fi;;
178 esac
180 outName=$argbase
182 # Identify output path
183 if [[ -n "$name" ]]; then
184 outName=$name
185 elif [[ -n "$cmdname" ]]; then
186 case "$curShell" in
187 bash|fish) outName=$cmdname.$curShell;;
188 zsh) outName=_$cmdname;;
190 # Our list of shells is out of sync with the flags we accept or extensions we detect.
191 echo 'installShellCompletion: internal error' >&2
192 return 1;;
193 esac
195 local sharePath
196 case "$curShell" in
197 bash) sharePath=bash-completion/completions;;
198 fish) sharePath=fish/vendor_completions.d;;
199 zsh)
200 sharePath=zsh/site-functions
201 # only apply automatic renaming if we didn't have a manual rename
202 if [[ -z "$name" && -z "$cmdname" ]]; then
203 # convert a name like `foo.zsh` into `_foo`
204 outName=${outName%.zsh}
205 outName=_${outName#_}
206 fi;;
208 # Our list of shells is out of sync with the flags we accept or extensions we detect.
209 echo 'installShellCompletion: internal error' >&2
210 return 1;;
211 esac
212 # Install file
213 local outDir="${!outputBin:?}/share/$sharePath"
214 local outPath="$outDir/$outName"
215 if [[ -p "$arg" ]]; then
216 # install handles named pipes on NixOS but not on macOS
217 mkdir -p "$outDir" \
218 && cat "$arg" > "$outPath"
219 else
220 install -Dm644 -T "$arg" "$outPath"
221 fi || return
222 # Clear the per-path flags
223 name=
224 done
225 if [[ -n "$name" ]]; then
226 echo 'installShellCompletion: error: --name flag given with no path' >&2
227 return 1
229 return $retval