Skip to content

Commit f465660

Browse files
authored
Merge pull request #504 from DannyBen/fix/repeatable-arg-quotes
Refactor repeatable+unique args and flag args
2 parents 9cdfc33 + 08c361d commit f465660

File tree

20 files changed

+260
-37
lines changed

20 files changed

+260
-37
lines changed

lib/bashly/script/command.rb

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,9 +101,10 @@ def commands
101101
end
102102

103103
# Returns a flat array containing all the commands in this tree.
104-
# This includes self + children + grandchildres + ...
105-
def deep_commands
104+
# This includes children + grandchildren (recursive), and may include self
105+
def deep_commands(include_self: false)
106106
result = []
107+
result << self if include_self
107108
commands.each do |command|
108109
result << command
109110
if command.commands.any?
@@ -217,6 +218,16 @@ def grouped_commands
217218
result
218219
end
219220

221+
# Returns true if this command, or any subcommand (deep) as any arg or
222+
# flag with arg that is defined as unique
223+
def has_unique_args_or_flags?
224+
deep_commands(include_self: true).each do |command|
225+
return true if command.args.count(&:unique).positive? ||
226+
command.flags.count(&:unique).positive?
227+
end
228+
false
229+
end
230+
220231
# Returns a mode identifier
221232
def mode
222233
@mode ||= if global_flags? then :global_flags
Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,32 @@
11
= view_marker
22

33
condition = "if"
4-
args.each do |arg|
4+
args.each_with_index do |arg, index|
5+
if index == 0
6+
> escaped="$(printf '%q' "$1")"
7+
end
58
> {{ condition }} [[ -z ${args['{{ arg.name }}']+x} ]]; then
69
if arg.repeatable
7-
> args['{{ arg.name }}']="\"$1\""
8-
> shift
10+
> args['{{ arg.name }}']="$escaped"
911
if arg.unique
10-
> elif [[ ! "${args['{{ arg.name }}']}" =~ \"$1\" ]]; then
11-
> args['{{ arg.name }}']="${args[{{ arg.name }}]} \"$1\""
12-
> shift
13-
> else
14-
> shift
12+
> unique_lookup["{{ arg.name }}:$escaped"]=1
13+
end
14+
if arg.unique
15+
> elif [[ -z "${unique_lookup["{{ arg.name }}:$escaped"]:-}" ]]; then
16+
> args['{{ arg.name }}']="${args['{{ arg.name }}']} $escaped"
17+
> unique_lookup["{{ arg.name }}:$escaped"]=1
1518
else
1619
> else
17-
> args['{{ arg.name }}']="${args[{{ arg.name }}]} \"$1\""
18-
> shift
20+
> args['{{ arg.name }}']="${args['{{ arg.name }}']} $escaped"
1921
end
2022

2123
else
22-
> args['{{ arg.name }}']=$1
23-
> shift
24+
> args['{{ arg.name }}']="$1"
2425

2526
end
2627
condition = "elif"
2728
end
2829

2930
> fi
30-
>
31+
> shift
32+
>

lib/bashly/views/command/run.gtx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
> declare -a other_args=()
77
> declare -a env_var_names=()
88
> declare -a input=()
9+
if has_unique_args_or_flags?
10+
> declare -A unique_lookup=()
11+
end
912
> normalize_input "$@"
1013
> parse_requirements "${input[@]}"
1114
if user_file_exist?('before')
@@ -29,5 +32,3 @@ if user_file_exist?('after')
2932
end
3033

3134
> }
32-
33-

lib/bashly/views/flag/case_arg.gtx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,19 @@
33
> if [[ -n ${2+x} ]]; then
44

55
if repeatable
6+
> escaped="$(printf '%q' "$2")"
67
> if [[ -z ${args['{{ name }}']+x} ]]; then
7-
> args['{{ name }}']="\"$2\""
8+
> args['{{ name }}']="$escaped"
89
if unique
9-
> elif [[ ! "${args['{{ name }}']}" =~ \"$2\" ]]; then
10+
> elif [[ -z "${unique_lookup["{{ name }}:${escaped}"]:-}" ]]; then
1011
else
1112
> else
1213
end
13-
> args['{{ name }}']="${args['{{ name }}']} \"$2\""
14+
> args['{{ name }}']="${args['{{ name }}']} $escaped"
1415
> fi
16+
if unique
17+
> unique_lookup["{{ name }}:${escaped}"]=1
18+
end
1519

1620
else
1721
> args['{{ name }}']="$2"
@@ -25,4 +29,4 @@ end
2529
> exit 1
2630
> fi
2731
> ;;
28-
>
32+
>

spec/approvals/examples/repeatable-arg

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ files:
4747
upcase: CONTENT OF FILE1
4848

4949
args:
50-
- ${args[file]} = "file1"
50+
- ${args[file]} = file1
5151
+ ./upcase file1 file2
5252

5353
files:
@@ -59,7 +59,7 @@ files:
5959
upcase: CONTENT OF FILE2
6060

6161
args:
62-
- ${args[file]} = "file1" "file2"
62+
- ${args[file]} = file1 file2
6363
+ ./upcase file1 file2 file1
6464

6565
files:
@@ -71,4 +71,4 @@ files:
7171
upcase: CONTENT OF FILE2
7272

7373
args:
74-
- ${args[file]} = "file1" "file2"
74+
- ${args[file]} = file1 file2

spec/approvals/examples/repeatable-flag

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ two three
4747
Verbosity level: 3
4848

4949
args:
50-
- ${args[--data]} = "one" "two three"
50+
- ${args[--data]} = one two\ three
5151
- ${args[--path]} = file\ one file-two
5252
- ${args[--verbose]} = 3
5353
+ ./download -d one --path /bin --path /usr/lib --path /bin
@@ -57,5 +57,5 @@ one
5757
Verbosity level: 1
5858

5959
args:
60-
- ${args[--data]} = "one"
61-
- ${args[--path]} = "/bin" "/usr/lib"
60+
- ${args[--data]} = one
61+
- ${args[--path]} = /bin /usr/lib

spec/approvals/fixtures/repeatable-arg-validations

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ args: none
1111
# this file is located in 'src/root_command.sh'
1212
# you can edit it freely and regenerate (it will not be overwritten)
1313
args:
14-
- ${args[number]} = "1"
14+
- ${args[number]} = 1
1515
+ ./cli 1.1
1616
validation error in NUMBER:
1717
must be an integer
@@ -22,7 +22,7 @@ must be an integer
2222
# this file is located in 'src/root_command.sh'
2323
# you can edit it freely and regenerate (it will not be overwritten)
2424
args:
25-
- ${args[number]} = "1" "2"
25+
- ${args[number]} = 1 2
2626
+ ./cli 1.1 2
2727
validation error in NUMBER:
2828
must be an integer
@@ -32,3 +32,6 @@ must be an integer
3232
+ ./cli 1 a
3333
validation error in NUMBER:
3434
must be an integer
35+
+ ./cli 1 'bad"quote'
36+
validation error in NUMBER:
37+
must be an integer
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
+ bundle exec bashly generate
2+
creating user files in src
3+
skipped src/root_command.sh (exists)
4+
created ./cli
5+
run ./cli --help to test your bash script
6+
+ ./cli
7+
args: none
8+
9+
+ ./cli before 'x x' 'x x' after
10+
args:
11+
- ${args[term]} = before x\ x after
12+
[TERM] --> before
13+
[TERM] --> x x
14+
[TERM] --> after
15+
16+
+ ./cli before 'x "x x"' 'x "x x"' after
17+
args:
18+
- ${args[term]} = before x\ \"x\ x\" after
19+
[TERM] --> before
20+
[TERM] --> x "x x"
21+
[TERM] --> after
22+
23+
+ ./cli before 'x"x' 'x"x' after
24+
args:
25+
- ${args[term]} = before x\"x after
26+
[TERM] --> before
27+
[TERM] --> x"x
28+
[TERM] --> after
29+
30+
+ ./cli -s before -s 'x x' -s 'x x' -s after
31+
args:
32+
- ${args[--search]} = before x\ x after
33+
[--serach] --> before
34+
[--serach] --> x x
35+
[--serach] --> after
36+
37+
+ ./cli -s before -s 'x "x x"' -s 'x "x x"' -s after
38+
args:
39+
- ${args[--search]} = before x\ \"x\ x\" after
40+
[--serach] --> before
41+
[--serach] --> x "x x"
42+
[--serach] --> after
43+
44+
+ ./cli -s before -s 'x"x' -s 'x"x' -s after
45+
args:
46+
- ${args[--search]} = before x\"x after
47+
[--serach] --> before
48+
[--serach] --> x"x
49+
[--serach] --> after
50+
51+
+ ./cli once x once
52+
args:
53+
- ${args[term]} = once x
54+
[TERM] --> once
55+
[TERM] --> x
56+
57+
+ ./cli -s once -s x -s once
58+
args:
59+
- ${args[--search]} = once x
60+
[--serach] --> once
61+
[--serach] --> x
62+

spec/approvals/fixtures/repeatable-flag-validations

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ args: none
1111
# this file is located in 'src/root_command.sh'
1212
# you can edit it freely and regenerate (it will not be overwritten)
1313
args:
14-
- ${args[--number]} = "1"
14+
- ${args[--number]} = 1
1515
+ ./cli --number 1.1
1616
validation error in --number, -n NUMBER:
1717
must be an integer
@@ -22,7 +22,7 @@ must be an integer
2222
# this file is located in 'src/root_command.sh'
2323
# you can edit it freely and regenerate (it will not be overwritten)
2424
args:
25-
- ${args[--number]} = "1" "2"
25+
- ${args[--number]} = 1 2
2626
+ ./cli --number 1.1 --number 2
2727
validation error in --number, -n NUMBER:
2828
must be an integer
@@ -32,3 +32,6 @@ must be an integer
3232
+ ./cli --number 1 --number a
3333
validation error in --number, -n NUMBER:
3434
must be an integer
35+
+ ./cli --number 1 --number 'bad"quote'
36+
validation error in --number, -n NUMBER:
37+
must be an integer

spec/approvals/fixtures/repeatable-whitelist

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,17 @@ args:
1212
# this file is located in 'src/root_command.sh'
1313
# you can edit it freely and regenerate (it will not be overwritten)
1414
args:
15-
- ${args[--protocol]} = "ssh"
15+
- ${args[--protocol]} = ssh
1616
+ ./download -p ssh -p ftp
1717
# this file is located in 'src/root_command.sh'
1818
# you can edit it freely and regenerate (it will not be overwritten)
1919
args:
20-
- ${args[--protocol]} = "ssh" "ftp"
20+
- ${args[--protocol]} = ssh ftp
2121
+ ./download -p sftp -p https
2222
--protocol must be one of: ssh, ftp, sftp
2323
+ ./download -p http -p ftp
2424
--protocol must be one of: ssh, ftp, sftp
2525
+ ./download --protocol telnet
2626
--protocol must be one of: ssh, ftp, sftp
27+
+ ./download --protocol telnet --protocol 'bad"quote'
28+
--protocol must be one of: ssh, ftp, sftp

0 commit comments

Comments
 (0)