zfs completions: Factor out OpenZFS features and support

As of FreeBSD 13 (released April 2021), FreeBSD has rebased its zfs support on
top of the OpenZFS distribution previously used only/chiefly by Linux;
accordingly, it has gained support for some previously Linux-only completions.
This patch changes some completions previously predicated on a Linux ZFS
installation to the presence of an OpenZFS installation. Note that there
continue to be (and probably always will be) separate Linux-only and
FreeBSD-only completions (and not just when it comes to interacting with the
device subsystem, etc).
This commit is contained in:
Mahmoud Al-Qudsi
2022-02-07 12:49:02 -06:00
parent 06c474da2e
commit 8d386a27f3
2 changed files with 82 additions and 41 deletions

View File

@@ -1,16 +1,21 @@
# Fish completions for the OpenZFS zfs command
# TODO Possible enhancements:
# - add a test to propose iSCSI and Trusted Extensions completions only when such system is present;
# - Illumos man pages suggests that it does not support nbmand nor atime mount option, so these properties should be proposed only when available
# - generally, propose properties only when the current OS and ZFS versions support them;
# - for the promote command, propose only eligible filesystems;
# - for the rollback command, propose only the most recent snapshot for each dataset, as it will not accept an intermediary snapshot;
# - for the release command, complete with existing tags;
# - for the diff command, complete the destination dataset of the diff;
# - for the program command, complete the script to be executed
# - for commands accepting several arguments of different types, propose arguments in the right order: for get, once the ZFS parameters have been given, only propose datasets
# Fish completions for the ZFS `zfs` command
#
# Possible enhancements:
# - Add a test to propose iSCSI and Trusted Extensions completions only when such system is present;
# - Illumos man pages suggests that it does not support nbmand nor atime mount option, so these
# properties should be proposed only when available;
# - Generally, propose properties only when the current OS and ZFS versions support them;
# - For the promote command, propose only eligible filesystems;
# - For the rollback command, propose only the most recent snapshot for each dataset, as it will not
# accept an intermediary snapshot;
# - For the release command, complete with existing tags;
# - For the diff command, complete the destination dataset of the diff;
# - For the program command, complete the script to be executed;
# - For commands accepting several arguments of different types, propose arguments in the right
# order: for get, once the ZFS parameters have been given, only propose datasets.
set -l OS ""
set -l freebsd_version ""
switch (uname)
case Linux
set OS Linux
@@ -18,6 +23,7 @@ switch (uname)
set OS macOS
case FreeBSD
set OS FreeBSD
set freebsd_version (uname -U)
case SunOS
set OS SunOS
# Others?
@@ -25,6 +31,14 @@ switch (uname)
set OS unknown
end
# Certain functionality is exclusive to platforms using OpenZFS. This used to be just Linux, but it
# now includes FreeBSD 13 and above.
if not type -q __fish_is_openzfs
function __fish_is_openzfs --inherit-variable freebsd_version --inherit-variable OS
test $OS = Linux || test $OS = FreeBSD -a $freebsd_version -gt 1300000
end
end
# Does the current invocation need a command?
function __fish_zfs_needs_command
set -l bookmark ""
@@ -261,7 +275,8 @@ if test $OS = SunOS # This is currently only supported under Illumos, but that w
complete -c zfs -f -n __fish_zfs_needs_command -a program -d 'Execute a ZFS Channel Program'
end
# Completions hereafter try to follow the man pages commands order, for maintainability, at the cost of multiple if statements
# Completions hereafter try to follow the man pages commands order, for maintainability, at the cost
# of multiple if statements.
# create completions
complete -c zfs -f -n '__fish_zfs_using_command create' -s p -d 'Create all needed non-existing parent datasets'
@@ -270,16 +285,20 @@ if test $OS = Linux # Only Linux supports the comma-separated format; others nee
else
complete -c zfs -x -n '__fish_zfs_using_command create' -s o -d 'Dataset property' -a '(__fish_complete_zfs_rw_properties; __fish_complete_zfs_write_once_properties)'
end
# create completions for volumes; as -V is necessary to zfs to recognize a volume creation request, we use it as a condition to propose volume creation completions
# If -V is typed after -s or -b, zfs should accept it, but fish won't propose -s or -b, but, as these options are for volumes only, it seems reasonable to expect the user to ask for a volume, with -V, before giving its characteristics with -s or -b
# create completions for volumes; as -V is necessary to zfs to recognize a volume creation request,
# we use it as a condition to propose volume creation completions.
# If -V is typed after -s or -b, zfs should accept it, but fish won't propose -s or -b, but, as
# these options are for volumes only, it seems reasonable to expect the user to ask for a volume,
# with -V, before giving its characteristics with -s or -b
complete -c zfs -x -n '__fish_zfs_using_command create' -s V -d 'Volume size'
complete -c zfs -f -n '__fish_zfs_using_command create; and __fish_contains_opt -s V' -s s -d 'Create a sparse volume'
complete -c zfs -x -n '__fish_zfs_using_command create; and __fish_contains_opt -s V' -s b -d Blocksize
# new dataset completions, applicable for both regular datasets and volumes; must start with pool and may optionally
# be a child of a pre-existing dataset.
# new dataset completions, applicable for both regular datasets and volumes; must start with pool
# and may optionally be a child of a pre-existing dataset.
complete -c zfs -x -n '__fish_zfs_using_command create' -a '(printf "%s/\n" (__fish_print_zfs_filesystems))'
# destroy completions; as the dataset is the last item, we can't know yet if it's a snapshot, a bookmark or something else, so we can't separate snapshot-specific options from others
# destroy completions; as the dataset is the last item, we can't know yet if it's a snapshot, a
# bookmark or something else, so we can't separate snapshot-specific options from others.
complete -c zfs -f -n '__fish_zfs_using_command destroy' -s r -d 'Recursively destroy children'
complete -c zfs -f -n '__fish_zfs_using_command destroy' -s R -d 'Recursively destroy all dependents'
complete -c zfs -f -n '__fish_zfs_using_command destroy' -s f -d 'Force unmounting'
@@ -316,14 +335,16 @@ complete -c zfs -x -n '__fish_zfs_using_command clone' -d 'Snapshot to clone' -a
# promote completions
complete -c zfs -x -n '__fish_zfs_using_command promote' -d 'Clone to promote' -a '(__fish_print_zfs_filesystems)'
# rename completions; as the dataset is the last item, we can't know yet if it's a snapshot or not, we can't separate snapshot-specific option from others
# rename completions; as the dataset is the last item, we can't know yet if it's a snapshot or not,
# we can't separate snapshot-specific option from others.
complete -c zfs -f -n '__fish_zfs_using_command rename' -s p -d 'Create all needed non-existing parent datasets'
complete -c zfs -f -n '__fish_zfs_using_command rename' -s r -d 'Recursively rename children snapshots'
if test $OS = Linux
if __fish_is_openzfs
complete -c zfs -f -n '__fish_zfs_using_command rename' -s f -d 'Force unmounting if needed'
else if test $OS = FreeBSD
end
# These FreeBSD completions are in addition to any added via the OpenZFS check above
if test $OS = FreeBSD
complete -c zfs -f -n '__fish_zfs_using_command rename' -s u -d 'Do not remount filesystems during rename'
complete -c zfs -f -n '__fish_zfs_using_command rename; and __fish_not_contain_opt -s u' -s f -d 'Force unmounting if needed'
end
complete -c zfs -x -n '__fish_zfs_using_command rename' -d 'Dataset to rename' -a '(__fish_print_zfs_filesystems; __fish_print_zfs_volumes; __fish_print_zfs_snapshots)'

View File

@@ -1,10 +1,15 @@
# Fish completions for the OpenZFS zpool command
# Fish completions for the ZFS `zpool` command
#
# Possible improvements:
# - whenever possible, propose designation of vdevs using their GUID
# - for eligible commands, with arguments of different types, only propose second type completions after the first have been selected; for instance, only propose pool members for offline command
# - this has been written mainly from manpages, which are known to be out-of-sync with the real feature set; some discrepancies have been addressed, but it is highly likely that others still lie
# - Whenever possible, propose designation of vdevs using their GUID.
# - For eligible commands, with arguments of different types, only propose second type completions
# after the first have been selected; for instance, only propose pool members for offline command.
# - This has been written mainly from manpages, which are known to be out-of-sync with the real
# feature set; some discrepancies have been addressed, but it is highly likely that others still
# lie.
set -l OS ""
set -l freebsd_version ""
switch (uname)
case Linux
set OS Linux
@@ -12,6 +17,7 @@ switch (uname)
set OS macOS
case FreeBSD
set OS FreeBSD
set freebsd_version (uname -U)
case SunOS
set OS SunOS
# Others?
@@ -19,6 +25,14 @@ switch (uname)
set OS unknown
end
# Certain functionality is exclusive to platforms using OpenZFS. This used to be just Linux, but it
# now includes FreeBSD 13 and above.
if not type -q __fish_is_openzfs
function __fish_is_openzfs --inherit-variable freebsd_version --inherit-variable OS
test $OS = Linux || test $OS = FreeBSD -a $freebsd_version -gt 1300000
end
end
# Does the current invocation need a command?
function __fish_zpool_needs_command
not __fish_seen_subcommand_from \? add attach clear create destroy detach events get history import iostat labelclear list offline online reguid reopen remove replace scrub set split status upgrade
@@ -53,8 +67,11 @@ function __fish_zpool_list_available_vdevs -V OS
end
function __fish_zpool_complete_vdevs
# As this function is to be called for completions only when necessary, we don't need to verify that it is relevant for the specified command; this is to be decided by calling, or not, the current function for command completions
# We can display the physical devices, as they are relevant whereas we are in a vdev definition or not
# As this function is to be called for completions only when necessary, we don't need to verify
# that it is relevant for the specified command; this is to be decided by calling, or not, the
# current function for command completions.
# We can display the physical devices, as they are relevant whereas we are in a vdev definition
# or not.
__fish_zpool_list_available_vdevs
# First, reverse token list to analyze it from the end
set -l tokens 0
@@ -80,14 +97,17 @@ function __fish_zpool_complete_vdevs
__fish_zpool_list_vdev_types
end
return
# Here, we accept any possible zpool command; this way, the developper will not have to augment or reduce the list when adding the current function to or removing it from the completions for the said command
# Here, we accept any possible zpool command; this way, the developer will not have
# to augment or reduce the list when adding the current function to or removing it
# from the completions for the said command.
case \? add attach clear create destroy detach events get history import iostat labelclear list offline online reguid reopen remove replace scrub set split status upgrade
__fish_zpool_list_vdev_types
return
case "" # Au cas où
echo "" >/dev/null
case "-*" "*=*" "*,*"
# The token is an option or an option argument; as no option uses a vdev as its argument, we can abandon commandline parsing
# The token is an option or an option argument; as no option uses a vdev as its
# argument, we can abandon commandline parsing.
__fish_zpool_list_vdev_types
return
end
@@ -174,7 +194,7 @@ complete -c zpool -f -n __fish_zpool_needs_command -a clear -d 'Clear devices er
complete -c zpool -f -n __fish_zpool_needs_command -a create -d 'Create a new storage pool'
complete -c zpool -f -n __fish_zpool_needs_command -a destroy -d 'Destroy a storage pool'
complete -c zpool -f -n __fish_zpool_needs_command -a detach -d 'Detach virtual device from a mirroring pool'
if test $OS = Linux
if __fish_is_openzfs
complete -c zpool -f -n __fish_zpool_needs_command -a events -d 'Display pool event log'
end
complete -c zpool -f -n __fish_zpool_needs_command -a export -d 'Export a pool'
@@ -199,7 +219,7 @@ complete -c zpool -f -n __fish_zpool_needs_command -a upgrade -d 'List upgradeab
# add completions
complete -c zpool -f -n '__fish_zpool_using_command add' -s f -d 'Force use of virtual device'
complete -c zpool -f -n '__fish_zpool_using_command add' -s n -d 'Dry run: only display resulting configuration'
if test $OS = Linux
if __fish_is_openzfs
complete -c zpool -f -n '__fish_zpool_using_command add' -s g -d 'Display virtual device GUID instead of device name'
complete -c zpool -f -n '__fish_zpool_using_command add' -s L -d 'Resolve device path symbolic links'
complete -c zpool -f -n '__fish_zpool_using_command add' -s P -d 'Display device full path'
@@ -210,7 +230,7 @@ complete -c zpool -x -n '__fish_zpool_using_command add; and not __fish_prev_arg
# attach completions
complete -c zpool -f -n '__fish_zpool_using_command attach' -s f -d 'Force use of virtual device'
if test $OS = Linux
if __fish_is_openzfs
complete -c zpool -x -n '__fish_zpool_using_command attach' -s o -d 'Pool property' -a '(__fish_zpool_list_device_properties)'
end
complete -c zpool -x -n '__fish_zpool_using_command attach' -d 'Pool to attach virtual device to' -a '(__fish_complete_zfs_pools)'
@@ -236,7 +256,7 @@ complete -c zpool -x -n '__fish_zpool_using_command create' -s o -d 'Pool proper
complete -c zpool -x -n '__fish_zpool_using_command create' -s O -d 'Root filesystem property' -a '(__fish_complete_zfs_ro_properties; __fish_complete_zfs_rw_properties; __fish_complete_zfs_write_once_properties)'
complete -c zpool -r -n '__fish_zpool_using_command create' -s R -d 'Equivalent to "-o cachefile=none,altroot=ROOT"'
complete -c zpool -x -n '__fish_zpool_using_command create' -s m -d 'Root filesystem mountpoint' -a 'legacy none'
if test $OS = Linux
if __fish_is_openzfs
complete -c zpool -x -n '__fish_zpool_using_command create' -s t -d 'Set a different in-core pool name'
end
complete -c zpool -x -n '__fish_zpool_using_command create' -d 'Virtual device to add' -a '(__fish_zpool_complete_vdevs)'
@@ -250,7 +270,7 @@ complete -c zpool -x -n '__fish_zpool_using_command clear' -d 'Pool to detach de
complete -c zpool -x -n '__fish_zpool_using_command clear' -d 'Physical device to detach' -a '(__fish_zpool_list_used_vdevs)'
# events completions
if test $OS = Linux
if __fish_is_openzfs
complete -c zpool -f -n '__fish_zpool_using_command events' -s v -d 'Print verbose event information'
complete -c zpool -f -n '__fish_zpool_using_command events' -s H -d 'Print output in a machine-parsable format'
complete -c zpool -f -n '__fish_zpool_using_command events' -s f -d 'Output appended data as the log grows'
@@ -259,7 +279,7 @@ if test $OS = Linux
end
# export completions
if test $OS = Linux
if __fish_is_openzfs
complete -c zpool -f -n '__fish_zpool_using_command export' -s a -d 'Export all pools'
end
complete -c zpool -f -n '__fish_zpool_using_command export' -s f -d 'Force unmounting of all contained datasets'
@@ -292,7 +312,7 @@ complete -c zpool -f -n '__fish_zpool_using_command import' -s m -d 'Ignore miss
complete -c zpool -r -n '__fish_zpool_using_command import' -s R -d 'Equivalent to "-o cachefile=none,altroot=ROOT"'
complete -c zpool -f -n '__fish_zpool_using_command import' -s N -d 'Do not mount contained filesystems'
complete -c zpool -f -n '__fish_zpool_using_command import; and __fish_contains_opt -s F' -s n -d 'Dry run: only determine if the recovery is possible, without attempting it'
if test $OS = Linux
if __fish_is_openzfs
complete -c zpool -f -n '__fish_zpool_using_command import; and __fish_contains_opt -s F' -s X -d 'Roll back to a previous TXG (hazardous)'
complete -c zpool -r -n '__fish_zpool_using_command import' -s T -d 'TXG to roll back to (implies -FX)'
complete -c zpool -f -n '__fish_zpool_using_command import' -s t -d 'Specify, as the last argument, a temporary pool name'
@@ -301,7 +321,7 @@ complete -c zpool -f -n '__fish_zpool_using_command import; and __fish_not_conta
# iostat completions
complete -c zpool -x -n '__fish_zpool_using_command iostat' -s T -d 'Display a timestamp using specified format'
if test $OS = Linux
if __fish_is_openzfs
complete -c zpool -f -n '__fish_zpool_using_command iostat' -s g -d 'Display virtual device GUID instead of device name'
complete -c zpool -f -n '__fish_zpool_using_command iostat' -s L -d 'Resolve device path symbolic links'
complete -c zpool -f -n '__fish_zpool_using_command iostat' -s P -d 'Display device full path'
@@ -316,7 +336,7 @@ complete -c zpool -x -n '__fish_zpool_using_command labelclear' -d 'Device to cl
# list completions
complete -c zpool -f -n '__fish_zpool_using_command list' -s H -d 'Print output in a machine-parsable format'
if test $OS = Linux
if __fish_is_openzfs
complete -c zpool -f -n '__fish_zpool_using_command list' -s g -d 'Display virtual device GUID instead of device name'
complete -c zpool -f -n '__fish_zpool_using_command list' -s L -d 'Resolve device path symbolic links'
end
@@ -348,7 +368,7 @@ complete -c zpool -x -n '__fish_zpool_using_command reopen' -d 'Pool which devic
# replace completions
complete -c zpool -f -n '__fish_zpool_using_command replace' -s f -d 'Force use of virtual device'
if test $OS = Linux
if __fish_is_openzfs
complete -c zpool -x -n '__fish_zpool_using_command replace' -s o -d 'Pool property' -a '(__fish_zpool_list_device_properties)'
end
complete -c zpool -x -n '__fish_zpool_using_command replace' -d 'Pool to replace device' -a '(__fish_complete_zfs_pools)'
@@ -367,7 +387,7 @@ complete -c zpool -x -n '__fish_zpool_using_command set' -d 'Property to set' -a
complete -c zpool -x -n '__fish_zpool_using_command set' -d 'Pool which property is to be set' -a '(__fish_complete_zfs_pools)'
# split completions
if test $OS = Linux
if __fish_is_openzfs
complete -c zpool -f -n '__fish_zpool_using_command split' -s g -d 'Display virtual device GUID instead of device name'
complete -c zpool -f -n '__fish_zpool_using_command split' -s L -d 'Resolve device path symbolic links'
complete -c zpool -f -n '__fish_zpool_using_command split' -s P -d 'Display device full path'
@@ -381,7 +401,7 @@ end
complete -c zpool -x -n '__fish_zpool_using_command split' -d 'Pool to split' -a '(__fish_complete_zfs_pools)'
# status completions
if test $OS = Linux
if __fish_is_openzfs
complete -c zpool -f -n '__fish_zpool_using_command status' -s g -d 'Display virtual device GUID instead of device name'
complete -c zpool -f -n '__fish_zpool_using_command status' -s L -d 'Resolve device path symbolic links'
complete -c zpool -f -n '__fish_zpool_using_command status' -s P -d 'Display device full path'