installShellFiles: init (#65211)
This is a new package that provides a shell hook to make it easy to declare manpages and shell completions in a manner that doesn't require remembering where to actually install them. Basic usage looks like { stdenv, installShellFiles, ... }: stdenv.mkDerivation { # ... nativeBuildInputs = [ installShellFiles ]; postInstall = '' installManPage doc/foobar.1 installShellCompletion --bash share/completions/foobar.bash installShellCompletion --fish share/completions/foobar.fish installShellCompletion --zsh share/completions/_foobar ''; # ... } See source comments for more details on the functions.
This commit is contained in:
parent
37e333af9a
commit
43dade238f
4 changed files with 214 additions and 0 deletions
|
@ -2714,6 +2714,49 @@ nativeBuildInputs = [ breakpointHook ];
|
|||
</note>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
installShellFiles
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
This hook helps with installing manpages and shell completion files. It
|
||||
exposes 2 shell functions <literal>installManPage</literal> and
|
||||
<literal>installShellCompletion</literal> that can be used from your
|
||||
<literal>postInstall</literal> hook.
|
||||
</para>
|
||||
<para>
|
||||
The <literal>installManPage</literal> function takes one or more paths
|
||||
to manpages to install. The manpages must have a section suffix, and may
|
||||
optionally be compressed (with <literal>.gz</literal> suffix). This
|
||||
function will place them into the correct directory.
|
||||
</para>
|
||||
<para>
|
||||
The <literal>installShellCompletion</literal> function takes one or more
|
||||
paths to shell completion files. By default it will autodetect the shell
|
||||
type from the completion file extension, but you may also specify it by
|
||||
passing one of <literal>--bash</literal>, <literal>--fish</literal>, or
|
||||
<literal>--zsh</literal>. These flags apply to all paths listed after
|
||||
them (up until another shell flag is given). Each path may also have a
|
||||
custom installation name provided by providing a flag <literal>--name
|
||||
NAME</literal> before the path. If this flag is not provided, zsh
|
||||
completions will be renamed automatically such that
|
||||
<literal>foobar.zsh</literal> becomes <literal>_foobar</literal>.
|
||||
<programlisting>
|
||||
nativeBuildInputs = [ installShellFiles ];
|
||||
postInstall = ''
|
||||
installManPage doc/foobar.1 doc/barfoo.3
|
||||
# explicit behavior
|
||||
installShellCompletion --bash --name foobar.bash share/completions.bash
|
||||
installShellCompletion --fish --name foobar.fish share/completions.fish
|
||||
installShellCompletion --zsh --name _foobar share/completions.zsh
|
||||
# implicit behavior
|
||||
installShellCompletion share/completions/foobar.{bash,fish,zsh}
|
||||
'';
|
||||
</programlisting>
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
libiconv, libintl
|
||||
|
|
4
pkgs/build-support/install-shell-files/default.nix
Normal file
4
pkgs/build-support/install-shell-files/default.nix
Normal file
|
@ -0,0 +1,4 @@
|
|||
{ makeSetupHook }:
|
||||
|
||||
# See the header comment in ../setup-hooks/install-shell-files.sh for example usage.
|
||||
makeSetupHook { name = "install-shell-files"; } ../setup-hooks/install-shell-files.sh
|
165
pkgs/build-support/setup-hooks/install-shell-files.sh
Normal file
165
pkgs/build-support/setup-hooks/install-shell-files.sh
Normal file
|
@ -0,0 +1,165 @@
|
|||
#!/bin/bash
|
||||
# Setup hook for the `installShellFiles` package.
|
||||
#
|
||||
# Example usage in a derivation:
|
||||
#
|
||||
# { …, installShellFiles, … }:
|
||||
# stdenv.mkDerivation {
|
||||
# …
|
||||
# nativeBuildInputs = [ installShellFiles ];
|
||||
# postInstall = ''
|
||||
# installManPage share/doc/foobar.1
|
||||
# installShellCompletion share/completions/foobar.{bash,fish,zsh}
|
||||
# '';
|
||||
# …
|
||||
# }
|
||||
#
|
||||
# See comments on each function for more details.
|
||||
|
||||
# installManPage <path> [...<path>]
|
||||
#
|
||||
# Each argument is checked for its man section suffix and installed into the appropriate
|
||||
# share/man<n>/ directory. The function returns an error if any paths don't have the man section
|
||||
# suffix (with optional .gz compression).
|
||||
installManPage() {
|
||||
local path
|
||||
for path in "$@"; do
|
||||
if (( "${NIX_DEBUG:-0}" >= 1 )); then
|
||||
echo "installManPage: installing $path"
|
||||
fi
|
||||
if test -z "$path"; then
|
||||
echo "installManPage: error: path cannot be empty" >&2
|
||||
return 1
|
||||
fi
|
||||
local basename
|
||||
basename=$(stripHash "$path") # use stripHash in case it's a nix store path
|
||||
local trimmed=${basename%.gz} # don't get fooled by compressed manpages
|
||||
local suffix=${trimmed##*.}
|
||||
if test -z "$suffix" -o "$suffix" = "$trimmed"; then
|
||||
echo "installManPage: error: path missing manpage section suffix: $path" >&2
|
||||
return 1
|
||||
fi
|
||||
local outRoot
|
||||
if test "$suffix" = 3; then
|
||||
outRoot=${!outputDevman:?}
|
||||
else
|
||||
outRoot=${!outputMan:?}
|
||||
fi
|
||||
install -Dm644 -T "$path" "${outRoot}/share/man/man$suffix/$basename" || return
|
||||
done
|
||||
}
|
||||
|
||||
# installShellCompletion [--bash|--fish|--zsh] ([--name <name>] <path>)...
|
||||
#
|
||||
# Each path is installed into the appropriate directory for shell completions for the given shell.
|
||||
# If one of `--bash`, `--fish`, or `--zsh` is given the path is assumed to belong to that shell.
|
||||
# Otherwise the file extension will be examined to pick a shell. If the shell is unknown a warning
|
||||
# will be logged and the command will return a non-zero status code after processing any remaining
|
||||
# paths. Any of the shell flags will affect all subsequent paths (unless another shell flag is
|
||||
# given).
|
||||
#
|
||||
# If the shell completion needs to be renamed before installing the optional `--name <name>` flag
|
||||
# may be given. Any name provided with this flag only applies to the next path.
|
||||
#
|
||||
# For zsh completions, if the `--name` flag is not given, the path will be automatically renamed
|
||||
# such that `foobar.zsh` becomes `_foobar`.
|
||||
#
|
||||
# This command accepts multiple shell flags in conjunction with multiple paths if you wish to
|
||||
# install them all in one command:
|
||||
#
|
||||
# installShellCompletion share/completions/foobar.{bash,fish} --zsh share/completions/_foobar
|
||||
#
|
||||
# However it may be easier to read if each shell is split into its own invocation, especially when
|
||||
# renaming is involved:
|
||||
#
|
||||
# installShellCompletion --bash --name foobar.bash share/completions.bash
|
||||
# installShellCompletion --fish --name foobar.fish share/completions.fish
|
||||
# installShellCompletion --zsh --name _foobar share/completions.zsh
|
||||
#
|
||||
# If any argument is `--` the remaining arguments will be treated as paths.
|
||||
installShellCompletion() {
|
||||
local shell='' name='' retval=0 parseArgs=1 arg
|
||||
while { arg=$1; shift; }; do
|
||||
# Parse arguments
|
||||
if (( parseArgs )); then
|
||||
case "$arg" in
|
||||
--bash|--fish|--zsh)
|
||||
shell=${arg#--}
|
||||
continue;;
|
||||
--name)
|
||||
name=$1
|
||||
shift || {
|
||||
echo 'installShellCompletion: error: --name flag expected an argument' >&2
|
||||
return 1
|
||||
}
|
||||
continue;;
|
||||
--name=*)
|
||||
# treat `--name=foo` the same as `--name foo`
|
||||
name=${arg#--name=}
|
||||
continue;;
|
||||
--?*)
|
||||
echo "installShellCompletion: warning: unknown flag ${arg%%=*}" >&2
|
||||
retval=2
|
||||
continue;;
|
||||
--)
|
||||
# treat remaining args as paths
|
||||
parseArgs=0
|
||||
continue;;
|
||||
esac
|
||||
fi
|
||||
if (( "${NIX_DEBUG:-0}" >= 1 )); then
|
||||
echo "installShellCompletion: installing $arg${name:+ as $name}"
|
||||
fi
|
||||
# if we get here, this is a path
|
||||
# Identify shell
|
||||
local basename
|
||||
basename=$(stripHash "$arg")
|
||||
local curShell=$shell
|
||||
if [[ -z "$curShell" ]]; then
|
||||
# auto-detect the shell
|
||||
case "$basename" in
|
||||
?*.bash) curShell=bash;;
|
||||
?*.fish) curShell=fish;;
|
||||
?*.zsh) curShell=zsh;;
|
||||
*)
|
||||
if [[ "$basename" = _* && "$basename" != *.* ]]; then
|
||||
# probably zsh
|
||||
echo "installShellCompletion: warning: assuming path \`$arg' is zsh; please specify with --zsh" >&2
|
||||
curShell=zsh
|
||||
else
|
||||
echo "installShellCompletion: warning: unknown shell for path: $arg" >&2
|
||||
retval=2
|
||||
continue
|
||||
fi;;
|
||||
esac
|
||||
fi
|
||||
# Identify output path
|
||||
local outName sharePath
|
||||
outName=${name:-$basename}
|
||||
case "$curShell" in
|
||||
bash) sharePath=bash-completion/completions;;
|
||||
fish) sharePath=fish/vendor_completions.d;;
|
||||
zsh)
|
||||
sharePath=zsh/site-functions
|
||||
# only apply automatic renaming if we didn't have a manual rename
|
||||
if test -z "$name"; then
|
||||
# convert a name like `foo.zsh` into `_foo`
|
||||
outName=${outName%.zsh}
|
||||
outName=_${outName#_}
|
||||
fi;;
|
||||
*)
|
||||
# Our list of shells is out of sync with the flags we accept or extensions we detect.
|
||||
echo 'installShellCompletion: internal error' >&2
|
||||
return 1;;
|
||||
esac
|
||||
# Install file
|
||||
install -Dm644 -T "$arg" "${!outputBin:?}/share/$sharePath/$outName" || return
|
||||
# Clear the name, it only applies to one path
|
||||
name=
|
||||
done
|
||||
if [[ -n "$name" ]]; then
|
||||
echo 'installShellCompletion: error: --name flag given with no path' >&2
|
||||
return 1
|
||||
fi
|
||||
return $retval
|
||||
}
|
|
@ -360,6 +360,8 @@ in
|
|||
inherit url;
|
||||
};
|
||||
|
||||
installShellFiles = callPackage ../build-support/install-shell-files {};
|
||||
|
||||
lazydocker = callPackage ../tools/misc/lazydocker { };
|
||||
|
||||
ld-is-cc-hook = makeSetupHook { name = "ld-is-cc-hook"; }
|
||||
|
|
Loading…
Reference in a new issue