OILS / spec / ysh-stdlib-args.test.sh View on Github | oilshell.org

333 lines, 213 significant
1## our_shell: ysh
2## oils_failures_allowed: 1
3
4#### args.ysh example usage
5source --builtin args.ysh
6
7parser (&spec) {
8 flag -v --verbose (help="Verbosely") # default is Bool, false
9
10 flag -P --max-procs ('int', default=-1, help='''
11 Run at most P processes at a time
12 ''')
13
14 flag -i --invert ('bool', default=true, help='''
15 Long multiline
16 Description
17 ''')
18
19 arg src (help='Source')
20 arg dest (help='Dest')
21
22 rest files
23}
24
25var args = parseArgs(spec, :| mysrc -P 12 mydest a b c |)
26
27echo "Verbose $[args.verbose]"
28pp line (args)
29## STDOUT:
30Verbose false
31(Dict) {"src":"mysrc","max-procs":12,"dest":"mydest","files":["a","b","c"],"verbose":false,"invert":true}
32## END
33
34#### Bool flag, positional args, more positional
35
36source --builtin args.ysh
37
38parser (&spec) {
39 flag -v --verbose ('bool')
40 arg src
41 arg dst
42
43 rest more # allow more args
44}
45#json write (spec)
46
47var argv = ['-v', 'src/path', 'dst/path', 'x', 'y', 'z']
48
49var args = parseArgs(spec, argv)
50
51pp line (args)
52
53if (args.verbose) {
54 echo "$[args.src] -> $[args.dst]"
55 write -- @[args.more]
56}
57
58## STDOUT:
59(Dict) {"verbose":true,"src":"src/path","dst":"dst/path","more":["x","y","z"]}
60src/path -> dst/path
61x
62y
63z
64## END
65
66#### Test multiple ARGVs against a parser
67
68source --builtin args.ysh
69
70parser (&spec) {
71 flag -v --verbose ('bool', default=false)
72 flag -c --count ('int', default=120)
73 arg file
74}
75
76var argsCases = [
77 :| -v --count 120 example.sh |,
78 :| -v --count 120 example.sh -v |, # duplicate flags are ignored
79 :| -v --count 120 example.sh -v --count 150 |, # the last duplicate has precedence
80]
81
82for args in (argsCases) {
83 var args_str = join(args, ' ')
84 echo "---------- $args_str ----------"
85 echo "\$ bin/ysh example.sh $args_str"
86 pp line (parseArgs(spec, args))
87
88 echo
89}
90## STDOUT:
91---------- -v --count 120 example.sh ----------
92$ bin/ysh example.sh -v --count 120 example.sh
93(Dict) {"verbose":true,"count":120,"file":"example.sh"}
94
95---------- -v --count 120 example.sh -v ----------
96$ bin/ysh example.sh -v --count 120 example.sh -v
97(Dict) {"verbose":true,"count":120,"file":"example.sh"}
98
99---------- -v --count 120 example.sh -v --count 150 ----------
100$ bin/ysh example.sh -v --count 120 example.sh -v --count 150
101(Dict) {"verbose":true,"count":150,"file":"example.sh"}
102
103## END
104
105#### Basic help message
106
107source --builtin args.ysh
108
109parser (&spec) {
110 # TODO: implement description, prog and help message
111 description '''
112 Reference Implementation
113 '''
114 prog "program-name"
115
116 arg -v --verbose (Bool, help = "Verbose")
117 arg src
118 arg dst
119}
120var argv = ['-h', 'src', 'dst']
121
122# Help
123var args = parseArgs(spec, argv)
124
125## STDOUT:
126usage: program-name [-h] [-v] src dst
127
128Reference Implementation
129
130positional arguments:
131 src
132 dst
133
134options:
135 -h, --help show this help message and exit
136 -v, --verbose Verbose
137## END
138
139#### Compare parseArgs() vs Python argparse
140
141source --builtin args.ysh
142
143var spec = {
144 flags: [
145 {short: '-v', long: '--verbose', name: 'verbose', type: null, default: '', help: 'Enable verbose logging'},
146 {short: '-c', long: '--count', name: 'count', type: 'int', default: 80, help: 'Maximum line length'},
147 ],
148 args: [
149 {name: 'file', type: 'str', help: 'File to check line lengths of'}
150 ],
151 rest: null,
152}
153
154var argsCases = [
155 :| -v --count 120 example.sh |,
156 :| -v --count 120 example.sh -v |, # duplicate flags are ignored
157 :| -v --count 120 example.sh -v --count 150 |, # the last duplicate has precedence
158]
159
160var argparse_py = '''
161import argparse
162import sys
163
164spec = argparse.ArgumentParser()
165spec.add_argument("filename")
166spec.add_argument("-c", "--count")
167spec.add_argument("-v", "--verbose",
168 action="store_true")
169
170result = spec.parse_args(sys.argv[1:])
171print(result)
172'''
173
174for args in (argsCases) {
175 var args_str = args->join(" ")
176 echo "---------- $args_str ----------"
177 echo "\$ bin/ysh example.sh $args_str"
178 pp line (parseArgs(spec, args))
179
180 echo
181 echo "\$ python3 example.py $args_str"
182 python3 -c $argparse_py @args
183
184 echo
185}
186## STDOUT:
187---------- -v --count 120 example.sh ----------
188$ bin/ysh example.sh -v --count 120 example.sh
189(Dict) {"verbose":true,"count":120,"file":"example.sh"}
190
191$ python3 example.py -v --count 120 example.sh
192Namespace(filename='example.sh', count='120', verbose=True)
193
194---------- -v --count 120 example.sh -v ----------
195$ bin/ysh example.sh -v --count 120 example.sh -v
196(Dict) {"verbose":true,"count":120,"file":"example.sh"}
197
198$ python3 example.py -v --count 120 example.sh -v
199Namespace(filename='example.sh', count='120', verbose=True)
200
201---------- -v --count 120 example.sh -v --count 150 ----------
202$ bin/ysh example.sh -v --count 120 example.sh -v --count 150
203(Dict) {"verbose":true,"count":150,"file":"example.sh"}
204
205$ python3 example.py -v --count 120 example.sh -v --count 150
206Namespace(filename='example.sh', count='150', verbose=True)
207
208## END
209
210#### Define spec and print it
211
212source --builtin args.ysh
213
214parser (&spec) {
215 flag -v --verbose ('bool')
216 arg src
217 arg dst
218
219 rest more # allow more args
220}
221
222json write (spec)
223## STDOUT:
224{
225 "flags": [
226 {
227 "short": "-v",
228 "long": "--verbose",
229 "name": "verbose",
230 "type": "bool",
231 "default": false,
232 "help": null
233 }
234 ],
235 "args": [
236 {
237 "name": "src",
238 "help": null
239 },
240 {
241 "name": "dst",
242 "help": null
243 }
244 ],
245 "rest": "more"
246}
247## END
248
249#### Default values
250source --builtin args.ysh
251
252parser (&spec) {
253 flag -S --sanitize ('bool', default=false)
254 flag -v --verbose ('bool', default=false)
255 flag -P --max-procs ('int') # Will set to null (the default default)
256}
257
258var args = parseArgs(spec, [])
259
260pp line (args)
261## STDOUT:
262(Dict) {"sanitize":false,"verbose":false,"max-procs":null}
263## END
264
265#### Duplicate argument/flag names
266source --builtin args.ysh
267
268try {
269 parser (&spec) {
270 flag -n --name
271 flag -N --name
272 }
273}
274echo status=$_status
275
276try {
277 parser (&spec) {
278 flag -n --name
279 arg name
280 }
281}
282echo status=$_status
283
284try {
285 parser (&spec) {
286 arg name
287 flag -o --other
288 arg name
289 }
290}
291echo status=$_status
292## STDOUT:
293status=3
294status=3
295status=3
296## END
297
298#### Error cases
299source --builtin args.ysh
300
301parser (&spec) {
302 flag -v --verbose
303 flag -n --num ('int', required=true)
304
305 arg action
306 arg other (required=false)
307}
308
309try { call parseArgs(spec, :| -n 10 action other extra |) }
310echo status=$_status
311
312try { call parseArgs(spec, :| -n |) }
313echo status=$_status
314
315try { call parseArgs(spec, :| -n -v |) }
316echo status=$_status
317
318try { = parseArgs(spec, :| -n 10 |) }
319echo status=$_status
320
321try { call parseArgs(spec, :| -v action |) }
322echo status=$_status
323
324try { call parseArgs(spec, :| --unknown |) }
325echo status=$_status
326## STDOUT:
327status=2
328status=2
329status=2
330status=2
331status=2
332status=2
333## END