mirror of
https://github.com/fish-shell/fish-shell.git
synced 2026-06-01 13:01:21 -03:00
Add --all option to path
- Add --all option to path - Add tests - Add doc
This commit is contained in:
committed by
Johannes Altmanninger
parent
8c5de9acfb
commit
7fe92be405
@@ -13,7 +13,7 @@ Synopsis
|
||||
path extension GENERAL_OPTIONS [PATH ...]
|
||||
path filter GENERAL_OPTIONS [-v | --invert]
|
||||
[-d] [-f] [-l] [-r] [-w] [-x]
|
||||
[(-t | --type) TYPE] [(-p | --perm) PERMISSION] [PATH ...]
|
||||
[(-t | --type) TYPE] [(-p | --perm) PERMISSION] [--all] [PATH ...]
|
||||
path is GENERAL_OPTIONS [(-v | --invert)] [(-t | --type) TYPE]
|
||||
[-d] [-f] [-l] [-r] [-w] [-x]
|
||||
[(-p | --perm) PERMISSION] [PATH ...]
|
||||
@@ -22,7 +22,7 @@ Synopsis
|
||||
path resolve GENERAL_OPTIONS [PATH ...]
|
||||
path change-extension GENERAL_OPTIONS EXTENSION [PATH ...]
|
||||
path sort GENERAL_OPTIONS [-r | --reverse]
|
||||
[-u | --unique] [--key=basename|dirname|path] [PATH ...]
|
||||
[-u | --unique] [--key=(basename | dirname | path)] [PATH ...]
|
||||
|
||||
GENERAL_OPTIONS
|
||||
[-z | --null-in] [-Z | --null-out] [-q | --quiet]
|
||||
@@ -148,7 +148,7 @@ Examples
|
||||
> echo $path$extension
|
||||
# reconstructs the original path again.
|
||||
./foo.mp4
|
||||
|
||||
|
||||
.. _cmd-path-filter:
|
||||
|
||||
"filter" subcommand
|
||||
@@ -158,7 +158,7 @@ Examples
|
||||
|
||||
path filter [-z | --null-in] [-Z | --null-out] [-q | --quiet] \
|
||||
[-d] [-f] [-l] [-r] [-w] [-x] \
|
||||
[-v | --invert] [(-t | --type) TYPE] [(-p | --perm) PERMISSION] [PATH ...]
|
||||
[-v | --invert] [(-t | --type) TYPE] [(-p | --perm) PERMISSION] [--all] [PATH ...]
|
||||
|
||||
``path filter`` returns all of the given paths that match the given checks. In all cases, the paths need to exist, nonexistent paths are always filtered.
|
||||
|
||||
@@ -180,6 +180,10 @@ When a path starts with ``-``, ``path filter`` will prepend ``./`` to avoid it b
|
||||
|
||||
It returns 0 if at least one path passed the filter.
|
||||
|
||||
With ``--all``, return status 0 (true) if all paths pass the filter, and status 1 (false) if any path fails. This is equivalent to ``not path filter -v``. It produces no output, only a status.
|
||||
|
||||
When ``--all`` combined with ``--invert``, it returns status 0 (true) if all paths fail the filter and status 1 (false) if any path passes.
|
||||
|
||||
``path is`` is shorthand for ``path filter -q``, i.e. just checking without producing output, see :ref:`The is subcommand <cmd-path-is>`.
|
||||
|
||||
Examples
|
||||
@@ -211,6 +215,9 @@ Examples
|
||||
>_ path filter -fx $PATH/*
|
||||
# Prints all possible commands - the first entry of each name is what fish would execute!
|
||||
|
||||
>_ path filter --all /usr/bin /usr/argagagji
|
||||
# This returns 1 (false) because not all paths pass the filter.
|
||||
|
||||
.. _cmd-path-is:
|
||||
|
||||
"is" subcommand
|
||||
|
||||
@@ -154,6 +154,9 @@ struct Options<'args> {
|
||||
|
||||
no_ext_valid: bool,
|
||||
no_ext: bool,
|
||||
|
||||
all_valid: bool,
|
||||
all: bool,
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -201,14 +204,13 @@ fn construct_short_opts(opts: &Options) -> WString {
|
||||
if opts.no_ext_valid {
|
||||
short_opts.push('E');
|
||||
}
|
||||
|
||||
short_opts
|
||||
}
|
||||
|
||||
/// Note that several long flags share the same short flag. That is okay. The caller is expected
|
||||
/// to indicate that a max of one of the long flags sharing a short flag is valid.
|
||||
/// Remember: adjust the completions in share/completions/ when options change
|
||||
const LONG_OPTIONS: [WOption<'static>; 11] = [
|
||||
const LONG_OPTIONS: [WOption<'static>; 12] = [
|
||||
wopt(L!("quiet"), NoArgument, 'q'),
|
||||
wopt(L!("null-in"), NoArgument, 'z'),
|
||||
wopt(L!("null-out"), NoArgument, 'Z'),
|
||||
@@ -220,6 +222,7 @@ fn construct_short_opts(opts: &Options) -> WString {
|
||||
wopt(L!("unique"), NoArgument, 'u'),
|
||||
wopt(L!("key"), RequiredArgument, NON_OPTION_CHAR),
|
||||
wopt(L!("no-extension"), NoArgument, 'E'),
|
||||
wopt(L!("all"), NoArgument, '\x02'),
|
||||
];
|
||||
|
||||
fn parse_opts<'args>(
|
||||
@@ -339,6 +342,11 @@ fn parse_opts<'args>(
|
||||
opts.key = w.woptarg;
|
||||
continue;
|
||||
}
|
||||
|
||||
'\x02' if opts.all_valid => {
|
||||
opts.all = true;
|
||||
continue;
|
||||
}
|
||||
_ => {
|
||||
path_unknown_option(parser, streams, cmd, args_read[w.wopt_index - 1]);
|
||||
return Err(STATUS_INVALID_ARGS);
|
||||
@@ -846,6 +854,7 @@ fn path_filter_maybe_is(
|
||||
opts.types_valid = true;
|
||||
opts.perms_valid = true;
|
||||
opts.invert_valid = true;
|
||||
opts.all_valid = true;
|
||||
let mut optind = 0;
|
||||
|
||||
parse_opts(&mut opts, &mut optind, 0, args, parser, streams)?;
|
||||
@@ -873,7 +882,10 @@ fn path_filter_maybe_is(
|
||||
None
|
||||
};
|
||||
|
||||
for (arg, _) in arguments.filter(|(f, _)| {
|
||||
// Collect arguments into a Vec so we can use .len()
|
||||
let arguments_vec: Vec<_> = arguments.collect();
|
||||
|
||||
for (arg, _) in arguments_vec.iter().cloned().filter(|(f, _)| {
|
||||
(opts.perms.is_none() && opts.types.is_none())
|
||||
|| (filter_path(&opts, f, uid, gid) != opts.invert)
|
||||
}) {
|
||||
@@ -881,10 +893,20 @@ fn path_filter_maybe_is(
|
||||
if opts.perms.is_none() && opts.types.is_none() {
|
||||
let ok = waccess(&arg, F_OK) == 0;
|
||||
if ok == opts.invert {
|
||||
// For --all, fail early if any path does not match the filter.
|
||||
if opts.all {
|
||||
return Err(STATUS_CMD_ERROR);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
n_transformed += 1;
|
||||
|
||||
if opts.all {
|
||||
// For --all, do not output paths, just check all must match.
|
||||
continue;
|
||||
}
|
||||
// We *know* this is a filename,
|
||||
// and so if it starts with a `-` we *know* it is relative
|
||||
// to $PWD. So we can add `./`.
|
||||
@@ -895,12 +917,16 @@ fn path_filter_maybe_is(
|
||||
} else {
|
||||
path_out(streams, &opts, arg);
|
||||
}
|
||||
n_transformed += 1;
|
||||
if opts.quiet {
|
||||
return Ok(SUCCESS);
|
||||
};
|
||||
}
|
||||
|
||||
if opts.all && n_transformed != arguments_vec.len() {
|
||||
// We have a filter and some paths didn't match.
|
||||
// Return Err if we have a filter and some paths didn't match.
|
||||
return Err(STATUS_CMD_ERROR);
|
||||
}
|
||||
if n_transformed > 0 {
|
||||
Ok(SUCCESS)
|
||||
} else {
|
||||
@@ -922,7 +948,6 @@ pub fn path(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr]) -> Bui
|
||||
return Err(STATUS_INVALID_ARGS);
|
||||
};
|
||||
let argc = args.len();
|
||||
|
||||
if argc <= 1 {
|
||||
streams
|
||||
.err
|
||||
|
||||
@@ -105,6 +105,21 @@ path filter -vf bin argagagji
|
||||
# CHECK: bin
|
||||
# CHECK: argagagji
|
||||
|
||||
# With --all, return true if all paths are passed.
|
||||
path filter --all bin bin/bash
|
||||
echo $status
|
||||
# CHECK: 0
|
||||
path filter --all bin argagagji
|
||||
echo $status
|
||||
# CHECK: 1
|
||||
# With --all and --invert, return true if none of paths is passed.
|
||||
path filter --all --invert bin bin/bash
|
||||
echo $status
|
||||
# CHECK: 1
|
||||
path filter --all --invert argagagji argagagji2
|
||||
echo $status
|
||||
# CHECK: 0
|
||||
|
||||
path filter --type file bin bin/fish
|
||||
# Only fish is a file
|
||||
# CHECK: bin/fish
|
||||
@@ -273,8 +288,6 @@ path sort --unique --key=basename {def,abc}/{456,123,789} def/{abc,def,0} abc/{f
|
||||
# CHECK: def/def
|
||||
# CHECK: abc/foo
|
||||
|
||||
|
||||
|
||||
# Symlink loop.
|
||||
# It goes brrr.
|
||||
ln -s target link
|
||||
@@ -288,13 +301,12 @@ test (path resolve link) = (pwd -P)/link
|
||||
and echo link resolves to link
|
||||
# CHECK: link resolves to link
|
||||
|
||||
|
||||
# path mtime
|
||||
# These tests deal with *time*, so we have to account
|
||||
# for slow systems (like CI).
|
||||
# So we should only test with a lot of slack.
|
||||
|
||||
echo bananana >> foo
|
||||
echo bananana >>foo
|
||||
test (math abs (date +%s) - (path mtime foo)) -lt 20
|
||||
or echo MTIME IS BOGUS
|
||||
|
||||
|
||||
Reference in New Issue
Block a user