mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-28 22:03:12 +00:00
8bf8b10f68
See the changelog additions for user-visible changes. Since we enable/disable terminal protocols whenever we pass terminal ownership, tests can no longer run in parallel on the same terminal. For the same reason, readline shortcuts in the gdb REPL will not work anymore. As a remedy, use gdbserver, or lobby for CSI u support in libreadline. Add sleep to some tests, otherwise they fall (both in CI and locally). There are two weird failures on FreeBSD remaining, disable them for now https://github.com/fish-shell/fish-shell/pull/10359/checks?check_run_id=23330096362 Design and implementation borrows heavily from Kakoune. In future, we should try to implement more of the kitty progressive enhancements. Closes #10359
322 lines
7.2 KiB
Fish
322 lines
7.2 KiB
Fish
#RUN: %fish %s | %filter-ctrlseqs
|
|
# The "path" builtin for dealing with paths
|
|
|
|
# Extension - for figuring out the file extension of a given path.
|
|
path extension /
|
|
or echo None
|
|
# CHECK:
|
|
# CHECK: None
|
|
|
|
# No extension
|
|
path extension /.
|
|
or echo Filename is just a dot, no extension
|
|
# CHECK:
|
|
# CHECK: Filename is just a dot, no extension
|
|
|
|
# No extension - ".foo" is the filename
|
|
path extension /.foo
|
|
or echo None again
|
|
# CHECK:
|
|
# CHECK: None again
|
|
|
|
path extension /foo
|
|
or echo None once more
|
|
# CHECK:
|
|
# CHECK: None once more
|
|
path extension /foo.txt
|
|
and echo Success
|
|
# CHECK: .txt
|
|
# CHECK: Success
|
|
path extension /foo.txt/bar
|
|
or echo Not even here
|
|
# CHECK:
|
|
# CHECK: Not even here
|
|
path extension . ..
|
|
or echo No extension
|
|
# CHECK:
|
|
# CHECK: No extension
|
|
path extension ./foo.mp4
|
|
# CHECK: .mp4
|
|
path extension ../banana
|
|
# CHECK:
|
|
# nothing, status 1
|
|
echo $status
|
|
# CHECK: 1
|
|
path extension ~/.config
|
|
# CHECK:
|
|
# nothing, status 1
|
|
echo $status
|
|
# CHECK: 1
|
|
path extension ~/.config.d
|
|
# CHECK: .d
|
|
path extension ~/.config.
|
|
echo $status
|
|
# status 0
|
|
# CHECK: .
|
|
# CHECK: 0
|
|
|
|
path change-extension '' ./foo.mp4
|
|
# CHECK: ./foo
|
|
path change-extension wmv ./foo.mp4
|
|
# CHECK: ./foo.wmv
|
|
path change-extension .wmv ./foo.mp4
|
|
# CHECK: ./foo.wmv
|
|
path change-extension '' ../banana
|
|
# CHECK: ../banana
|
|
# still status 0, because there was an argument
|
|
echo $status
|
|
# CHECK: 0
|
|
path change-extension '' ~/.config
|
|
# CHECK: {{.*}}/.config
|
|
echo $status
|
|
# CHECK: 0
|
|
|
|
path basename ./foo.mp4
|
|
# CHECK: foo.mp4
|
|
path basename ../banana
|
|
# CHECK: banana
|
|
path basename /usr/bin/
|
|
# CHECK: bin
|
|
path dirname ./foo.mp4
|
|
# CHECK: .
|
|
path basename ../banana
|
|
# CHECK: banana
|
|
path basename /usr/bin/
|
|
# CHECK: bin
|
|
|
|
cd $TMPDIR
|
|
mkdir -p bin
|
|
touch bin/{bash,bssh,chsh,dash,fish,slsh,ssh,zsh}
|
|
ln -s $TMPDIR/bin/bash bin/sh
|
|
|
|
chmod +x bin/*
|
|
# We need files from here on
|
|
path filter bin argagagji
|
|
# The (hopefully) nonexistent argagagji is filtered implicitly:
|
|
# CHECK: bin
|
|
|
|
# With --invert, the existing bin is filtered
|
|
path filter --invert bin argagagji
|
|
# CHECK: argagagji
|
|
|
|
# With --invert and a type, bin fails the type,
|
|
# and argagagji doesn't exist, so both are printed.
|
|
path filter -vf bin argagagji
|
|
# CHECK: bin
|
|
# CHECK: argagagji
|
|
|
|
path filter --type file bin bin/fish
|
|
# Only fish is a file
|
|
# CHECK: bin/fish
|
|
chmod 500 bin/fish
|
|
path filter --type file,dir --perm exec,write bin/fish .
|
|
# fish is a file, which passes, and executable, which passes,
|
|
# but not writable, which fails.
|
|
#
|
|
# . is a directory and both writable and executable, typically.
|
|
# So it passes.
|
|
# CHECK: .
|
|
|
|
mkdir -p sbin
|
|
touch sbin/setuid-exe sbin/setgid-exe
|
|
chmod u+s,a+x sbin/setuid-exe
|
|
path filter --perm suid sbin/*
|
|
# CHECK: sbin/setuid-exe
|
|
|
|
# On at least FreeBSD on our CI this fails with "permission denied".
|
|
# So we can't test it, and we fake the output instead.
|
|
if chmod g+s,a+x sbin/setgid-exe 2>/dev/null
|
|
path filter --perm sgid sbin/*
|
|
else
|
|
echo sbin/setgid-exe
|
|
end
|
|
# CHECK: sbin/setgid-exe
|
|
|
|
mkdir stuff
|
|
touch stuff/{read,write,exec,readwrite,readexec,writeexec,all,none}
|
|
chmod 400 stuff/read
|
|
chmod 200 stuff/write
|
|
chmod 100 stuff/exec
|
|
chmod 600 stuff/readwrite
|
|
chmod 500 stuff/readexec
|
|
chmod 300 stuff/writeexec
|
|
chmod 700 stuff/all
|
|
chmod 000 stuff/none
|
|
|
|
# Validate that globs are sorted.
|
|
test (path filter stuff/* | path sort | string join ",") = (path filter stuff/* | string join ",")
|
|
|
|
path filter --perm read stuff/*
|
|
# CHECK: stuff/all
|
|
# CHECK: stuff/read
|
|
# CHECK: stuff/readexec
|
|
# CHECK: stuff/readwrite
|
|
|
|
path filter -r stuff/*
|
|
# CHECK: stuff/all
|
|
# CHECK: stuff/read
|
|
# CHECK: stuff/readexec
|
|
# CHECK: stuff/readwrite
|
|
|
|
path filter --perm write stuff/*
|
|
# CHECK: stuff/all
|
|
# CHECK: stuff/readwrite
|
|
# CHECK: stuff/write
|
|
# CHECK: stuff/writeexec
|
|
|
|
path filter -w stuff/*
|
|
# CHECK: stuff/all
|
|
# CHECK: stuff/readwrite
|
|
# CHECK: stuff/write
|
|
# CHECK: stuff/writeexec
|
|
|
|
path filter --perm exec stuff/*
|
|
# CHECK: stuff/all
|
|
# CHECK: stuff/exec
|
|
# CHECK: stuff/readexec
|
|
# CHECK: stuff/writeexec
|
|
|
|
path filter -x stuff/*
|
|
# CHECK: stuff/all
|
|
# CHECK: stuff/exec
|
|
# CHECK: stuff/readexec
|
|
# CHECK: stuff/writeexec
|
|
|
|
path filter --perm read,write stuff/*
|
|
# CHECK: stuff/all
|
|
# CHECK: stuff/readwrite
|
|
|
|
path filter --perm read,exec stuff/*
|
|
# CHECK: stuff/all
|
|
# CHECK: stuff/readexec
|
|
|
|
path filter --perm write,exec stuff/*
|
|
# CHECK: stuff/all
|
|
# CHECK: stuff/writeexec
|
|
|
|
path filter --perm read,write,exec stuff/*
|
|
# CHECK: stuff/all
|
|
|
|
path filter stuff/*
|
|
# CHECK: stuff/all
|
|
# CHECK: stuff/exec
|
|
# CHECK: stuff/none
|
|
# CHECK: stuff/read
|
|
# CHECK: stuff/readexec
|
|
# CHECK: stuff/readwrite
|
|
# CHECK: stuff/write
|
|
# CHECK: stuff/writeexec
|
|
|
|
path normalize /usr/bin//../../etc/fish
|
|
# The "//" is squashed and the ".." components neutralize the components before
|
|
# CHECK: /etc/fish
|
|
path normalize /bin//bash
|
|
# The "//" is squashed, but /bin isn't resolved even if your system links it to /usr/bin.
|
|
# CHECK: /bin/bash
|
|
|
|
# Paths with "-" get a "./":
|
|
path normalize -- -/foo -foo/foo
|
|
# CHECK: ./-/foo
|
|
# CHECK: ./-foo/foo
|
|
path normalize -- ../-foo
|
|
# CHECK: ../-foo
|
|
|
|
# This goes for filter as well
|
|
touch -- -foo
|
|
path filter -f -- -foo
|
|
# CHECK: ./-foo
|
|
|
|
# We need to remove the rest of the path because we have no idea what its value looks like.
|
|
path resolve bin//sh | string match -r -- 'bin/bash$'
|
|
# The "//" is squashed, and the symlink is resolved.
|
|
# sh here is bash
|
|
# CHECK: bin/bash
|
|
|
|
# "../" cancels out even files.
|
|
path resolve bin//sh/../ | string match -r -- 'bin$'
|
|
# CHECK: bin
|
|
|
|
# `path resolve` with nonexistent paths
|
|
set -l path (path resolve foo/bar)
|
|
string match -rq "^"(pwd -P | string escape --style=regex)'/' -- $path
|
|
and echo It matches pwd!
|
|
or echo pwd is \'$PWD\' resolved path is \'$path\'
|
|
# CHECK: It matches pwd!
|
|
string replace -r "^"(pwd -P | string escape --style=regex)'/' "" -- $path
|
|
# CHECK: foo/bar
|
|
|
|
path resolve /banana//terracota/terracota/booooo/../pie
|
|
# CHECK: /banana/terracota/terracota/pie
|
|
|
|
path sort --key=basename {def,abc}/{456,123,789,abc,def,0} | path sort --key=dirname -r
|
|
# CHECK: def/0
|
|
# CHECK: def/123
|
|
# CHECK: def/456
|
|
# CHECK: def/789
|
|
# CHECK: def/abc
|
|
# CHECK: def/def
|
|
# CHECK: abc/0
|
|
# CHECK: abc/123
|
|
# CHECK: abc/456
|
|
# CHECK: abc/789
|
|
# CHECK: abc/abc
|
|
# CHECK: abc/def
|
|
|
|
path sort --unique --key=basename {def,abc}/{456,123,789} def/{abc,def,0} abc/{foo,bar,baz}
|
|
# CHECK: def/0
|
|
# CHECK: def/123
|
|
# CHECK: def/456
|
|
# CHECK: def/789
|
|
# CHECK: def/abc
|
|
# CHECK: abc/bar
|
|
# CHECK: abc/baz
|
|
# CHECK: def/def
|
|
# CHECK: abc/foo
|
|
|
|
|
|
|
|
# Symlink loop.
|
|
# It goes brrr.
|
|
ln -s target link
|
|
ln -s link target
|
|
|
|
test (path resolve target) = (pwd -P)/target
|
|
and echo target resolves to target
|
|
# CHECK: target resolves to target
|
|
|
|
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
|
|
test (math abs (date +%s) - (path mtime foo)) -lt 20
|
|
or echo MTIME IS BOGUS
|
|
|
|
sleep 2
|
|
|
|
set -l mtime (path mtime --relative foo)
|
|
test $mtime -ge 1
|
|
or echo mtime is too small
|
|
|
|
test $mtime -lt 20
|
|
or echo mtime is too large
|
|
|
|
touch -m -t 197001020000 epoch
|
|
set -l epochtime (path mtime epoch)
|
|
# Allow for timezone shenanigans
|
|
test $epochtime -gt 0 -a $epochtime -lt 180000
|
|
or echo Oops not mtime
|
|
|
|
path basename -Z foo bar baz | path sort
|
|
# CHECK: bar
|
|
# CHECK: baz
|
|
# CHECK: foo
|
|
|
|
path basename --null-out bar baz | string escape
|
|
# CHECK: bar\x00baz\x00
|