1 ## our_shell: ysh
2 ## oils_failures_allowed: 1
3
4 #### args.ysh example usage
5 source $LIB_YSH/args.ysh
6
7 parser (&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
25 var args = parseArgs(spec, :| mysrc -P 12 mydest a b c |)
26
27 echo "Verbose $[args.verbose]"
28 pp line (args)
29 ## STDOUT:
30 Verbose 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
36 source $LIB_YSH/args.ysh
37
38 parser (&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
47 var argv = ['-v', 'src/path', 'dst/path', 'x', 'y', 'z']
48
49 var args = parseArgs(spec, argv)
50
51 pp line (args)
52
53 if (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"]}
60 src/path -> dst/path
61 x
62 y
63 z
64 ## END
65
66 #### Test multiple ARGVs against a parser
67
68 source $LIB_YSH/args.ysh
69
70 parser (&spec) {
71 flag -v --verbose ('bool', default=false)
72 flag -c --count ('int', default=120)
73 arg file
74 }
75
76 var 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
82 for 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
107 source $LIB_YSH/args.ysh
108
109 parser (&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 }
120 var argv = ['-h', 'src', 'dst']
121
122 # Help
123 var args = parseArgs(spec, argv)
124
125 ## STDOUT:
126 usage: program-name [-h] [-v] src dst
127
128 Reference Implementation
129
130 positional arguments:
131 src
132 dst
133
134 options:
135 -h, --help show this help message and exit
136 -v, --verbose Verbose
137 ## END
138
139 #### Compare parseArgs() vs Python argparse
140
141 source $LIB_YSH/args.ysh
142
143 var 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
154 var 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
160 var argparse_py = '''
161 import argparse
162 import sys
163
164 spec = argparse.ArgumentParser()
165 spec.add_argument("filename")
166 spec.add_argument("-c", "--count")
167 spec.add_argument("-v", "--verbose",
168 action="store_true")
169
170 result = spec.parse_args(sys.argv[1:])
171 print(result)
172 '''
173
174 for 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
192 Namespace(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
199 Namespace(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
206 Namespace(filename='example.sh', count='150', verbose=True)
207
208 ## END
209
210 #### Define spec and print it
211
212 source $LIB_YSH/args.ysh
213
214 parser (&spec) {
215 flag -v --verbose ('bool')
216 arg src
217 arg dst
218
219 rest more # allow more args
220 }
221
222 json 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
250 source $LIB_YSH/args.ysh
251
252 parser (&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
258 var args = parseArgs(spec, [])
259
260 pp line (args)
261 ## STDOUT:
262 (Dict) {"sanitize":false,"verbose":false,"max-procs":null}
263 ## END
264
265 #### Duplicate argument/flag names
266 source $LIB_YSH/args.ysh
267
268 try {
269 parser (&spec) {
270 flag -n --name
271 flag -N --name
272 }
273 }
274 echo status=$_status
275
276 try {
277 parser (&spec) {
278 flag -n --name
279 arg name
280 }
281 }
282 echo status=$_status
283
284 try {
285 parser (&spec) {
286 arg name
287 flag -o --other
288 arg name
289 }
290 }
291 echo status=$_status
292 ## STDOUT:
293 status=3
294 status=3
295 status=3
296 ## END
297
298 #### Error cases
299 source $LIB_YSH/args.ysh
300
301 parser (&spec) {
302 flag -v --verbose
303 flag -n --num ('int', required=true)
304
305 arg action
306 arg other (required=false)
307 }
308
309 try { call parseArgs(spec, :| -n 10 action other extra |) }
310 echo status=$_status
311
312 try { call parseArgs(spec, :| -n |) }
313 echo status=$_status
314
315 try { call parseArgs(spec, :| -n -v |) }
316 echo status=$_status
317
318 try { = parseArgs(spec, :| -n 10 |) }
319 echo status=$_status
320
321 try { call parseArgs(spec, :| -v action |) }
322 echo status=$_status
323
324 try { call parseArgs(spec, :| --unknown |) }
325 echo status=$_status
326 ## STDOUT:
327 status=2
328 status=2
329 status=2
330 status=2
331 status=2
332 status=2
333 ## END