File: path.fish

package info (click to toggle)
fish 4.2.1-3.1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 35,980 kB
  • sloc: python: 6,972; javascript: 1,407; sh: 1,009; xml: 411; ansic: 230; objc: 78; makefile: 20
file content (339 lines) | stat: -rw-r--r-- 7,778 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
#RUN: %fish %s
# 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

# 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
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 -E foo.txt /usr/local/foo.bar /foo.tar.gz
# CHECK: foo
# CHECK: foo
# CHECK: foo.tar

path basename --null-out bar baz | string escape
# CHECK: bar\x00baz\x00