Skip to content

Commit 98ff692

Browse files
committed
Fixed wrapping of scripts with positional args
1 parent 4341882 commit 98ff692

File tree

14 files changed

+169
-24
lines changed

14 files changed

+169
-24
lines changed

ChangeLog

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
1-
1.3.0 (???)
1+
1.2.1 (???)
22
------------------
33

44
New features:
55

66
* TBD: Support for leftover args (kindof - not when upper bound of args is not
77
known)
88

9+
Bugfixes:
10+
11+
* Improved the wrapping of scripts to work with positional args
12+
913
1.2.0 (2016-07-08)
1014
------------------
1115

bin/argbash.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ for (( ii = 0; ii < ${#POSITIONALS[@]}; ii++))
8686
do
8787
eval "${POSITIONAL_NAMES[$ii]}=\"${POSITIONALS[$ii]}\"" || { echo "Error during argument parsing, possibly an Argbash bug." >&2; exit 1; }
8888
done
89+
8990
# OTHER STUFF GENERATED BY Argbash
9091
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
9192

resources/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ EXAMPLES = \
1515
examples/minimal.sh \
1616
examples/simple.sh \
1717
examples/simple-standalone.sh \
18+
examples/simple-wrapper.sh \
1819
$(NUL)
1920

2021
ROOT_DIR := $(dir $(realpath $(lastword $(MAKEFILE_LIST))))

resources/examples/minimal.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ for (( ii = 0; ii < ${#POSITIONALS[@]}; ii++))
6565
do
6666
eval "${POSITIONAL_NAMES[$ii]}=\"${POSITIONALS[$ii]}\"" || { echo "Error during argument parsing, possibly an Argbash bug." >&2; exit 1; }
6767
done
68+
6869
# OTHER STUFF GENERATED BY Argbash
6970

7071
### END OF CODE GENERATED BY Argbash (sortof) ### ])

resources/examples/simple-standalone.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ for (( ii = 0; ii < ${#POSITIONALS[@]}; ii++))
6464
do
6565
eval "${POSITIONAL_NAMES[$ii]}=\"${POSITIONALS[$ii]}\"" || { echo "Error during argument parsing, possibly an Argbash bug." >&2; exit 1; }
6666
done
67+
6768
# OTHER STUFF GENERATED BY Argbash
6869

6970
### END OF CODE GENERATED BY Argbash (sortof) ### ])

resources/examples/simple-wrapper.m4

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#!/bin/bash
2+
3+
# ARG_POSITIONAL_SINGLE([directory])
4+
# ARGBASH_WRAP([simple], [filename])
5+
# ARG_HELP([This program tells you size of files in a given directory in units you choose.])
6+
# ARGBASH_GO
7+
8+
# [ <-- needed because of Argbash
9+
10+
test -f simple.sh || { echo "Missing the wrapped script, execute me from the directory where 'simple.sh' is."; exit 1; }
11+
test -d "$_ARG_DIRECTORY" || { echo "We expected a directory, got '$_ARG_DIRECTORY'."; exit 1; }
12+
13+
for file in $_ARG_DIRECTORY/*
14+
do
15+
test -f "$file" && echo "$file: $(./simple.sh "${_ARGS_SIMPLE_OPT[@]}" "$file")"
16+
done
17+
18+
# ] <-- needed because of Argbash

resources/examples/simple-wrapper.sh

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
#!/bin/bash
2+
3+
# _ARG_POSITIONAL_SINGLE([directory])
4+
# ARGBASH_WRAP([simple],[filename])
5+
# ARG_HELP([This program tells you size of files in a given directory in units you choose.])
6+
# ARGBASH_GO()
7+
# needed because of Argbash --> m4_ignore([
8+
### START OF CODE GENERATED BY ARGBASH v1.2.0 one line above ###
9+
# Argbash is a bash code generator used to get arguments parsing right.
10+
# Argbash is FREE SOFTWARE, know your rights: https://github.com/matejak/argbash
11+
# THE DEFAULTS INITIALIZATION --- POSITIONALS
12+
# THE DEFAULTS INITIALIZATION --- OPTIONALS
13+
_ARG_UNIT="b"
14+
_ARG_VERBOSE=off
15+
16+
# THE PRINT HELP FUNCION
17+
function print_help
18+
{
19+
echo "This program tells you size of files in a given directory in units you choose."
20+
echo "Usage: $0 [--unit <arg>] [--(no-)verbose] [--help] <directory>"
21+
echo -e "\t<directory>: "
22+
echo -e "\t-u,--unit: What unit we accept (b for bytes, k for kibibytes, M for mebibytes) (default: '"b"')"
23+
echo -e "\t--verbose,--no-verbose: (default: 'off')"
24+
echo -e "\t-h,--help: Prints help"
25+
}
26+
27+
# THE PARSING ITSELF
28+
while test $# -gt 0
29+
do
30+
_key="$1"
31+
case "$_key" in
32+
-u|--unit)
33+
test $# -lt 2 && { echo "Missing value for the optional argument '$_key'." >&2; exit 1; }
34+
_ARG_UNIT="$2"
35+
_ARGS_SIMPLE_OPT+=("$1" "$2")
36+
shift
37+
;;
38+
--no-verbose|--verbose)
39+
_ARG_VERBOSE="on"
40+
_ARGS_SIMPLE_OPT+=("$1")
41+
test "${1:0:5}" = "--no-" && _ARG_VERBOSE="off"
42+
;;
43+
-h|--help)
44+
print_help
45+
exit 0
46+
;;
47+
*)
48+
POSITIONALS+=("$1")
49+
;;
50+
esac
51+
shift
52+
done
53+
54+
POSITIONAL_NAMES=('_ARG_DIRECTORY' )
55+
test ${#POSITIONALS[@]} -lt 1 && { ( echo "FATAL ERROR: Not enough positional arguments --- we require exactly 1, but got only ${#POSITIONALS[@]}."; print_help ) >&2; exit 1; }
56+
test ${#POSITIONALS[@]} -gt 1 && { ( echo "FATAL ERROR: There were spurious positional arguments --- we expect exactly 1, but got ${#POSITIONALS[@]} (the last one was: '${POSITIONALS[@]: -1}')."; print_help ) >&2; exit 1; }
57+
for (( ii = 0; ii < ${#POSITIONALS[@]}; ii++))
58+
do
59+
eval "${POSITIONAL_NAMES[$ii]}=\"${POSITIONALS[$ii]}\"" || { echo "Error during argument parsing, possibly an Argbash bug." >&2; exit 1; }
60+
done
61+
62+
# OTHER STUFF GENERATED BY Argbash
63+
_ARGS_SIMPLE=("${_ARGS_SIMPLE_OPT[@]}" "${_ARGS_SIMPLE_POS[@]}")
64+
65+
### END OF CODE GENERATED BY Argbash (sortof) ### ])
66+
# [ <-- needed because of Argbash
67+
68+
69+
test -f simple.sh || { echo "Missing the wrapped script, execute me from the directory where 'simple.sh' is."; exit 1; }
70+
test -d "$_ARG_DIRECTORY" || { echo "We expected a directory, got '$_ARG_DIRECTORY'."; exit 1; }
71+
72+
for file in $_ARG_DIRECTORY/*
73+
do
74+
test -f "$file" && echo "$file: $(./simple.sh "${_ARGS_SIMPLE_OPT[@]}" "$file")"
75+
done
76+
77+
# ] <-- needed because of Argbash

resources/examples/simple.m4

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
#!/bin/bash
22

33
# ARG_POSITIONAL_SINGLE([filename])
4-
# ARG_OPTIONAL_SINGLE([unit], u, [What unit we accept (b for bytes, k for kilobytes, M for megabytes)], b)
4+
# ARG_OPTIONAL_SINGLE([unit], u, [What unit we accept (b for bytes, k for kibibytes, M for mebibytes)], b)
55
# ARG_VERSION([echo $0 v0.1])
66
# ARG_OPTIONAL_BOOLEAN(verbose)
77
# ARG_HELP([This program tells you size of file that you pass to it in chosen units.])
88
# ARGBASH_GO
99

10-
# opening escape square bracket: [
10+
# [ <-- needed because of Argbash
1111

1212
# ARG_HELP <-- Unlike one above, his one does not disappear, it is behind the escape bracket.
1313

@@ -22,12 +22,12 @@ FILENAME="$_ARG_FILENAME"
2222
if [ $VERBOSE = on ]
2323
then
2424
_b="bytes (B)"
25-
_kb="kilobytes (kB)"
26-
_mb="megabytes (MB)"
25+
_kb="kibibytes (kiB)"
26+
_mb="mebibytes (MiB)"
2727
else
2828
_b="B"
29-
_kb="kB"
30-
_mb="MB"
29+
_kb="kiB"
30+
_mb="MiB"
3131
fi
3232

3333
SIZE_BYTES=$(wc -c "$FILENAME" | cut -f 1 -d ' ')
@@ -43,4 +43,4 @@ test "$UNIT" = M && echo $SIZE_MEGABYTES $_mb && exit 0
4343
test "$VERBOSE" = on && echo "The unit '$UNIT' is not supported!"
4444
exit 1
4545

46-
# closing escape square bracket: ]
46+
# ] <-- needed because of Argbash

resources/examples/simple.sh

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/bin/bash
22

33
# _ARG_POSITIONAL_SINGLE([filename])
4-
# ARG_OPTIONAL_SINGLE([unit],[u],[What unit we accept (b for bytes, k for kilobytes, M for megabytes)],[b])
4+
# ARG_OPTIONAL_SINGLE([unit],[u],[What unit we accept (b for bytes, k for kibibytes, M for mebibytes)],[b])
55
# ARG_VERSION([echo $0 v0.1])
66
# ARG_OPTIONAL_BOOLEAN([verbose])
77
# ARG_HELP([This program tells you size of file that you pass to it in chosen units.])
@@ -21,7 +21,7 @@ function print_help
2121
echo "This program tells you size of file that you pass to it in chosen units."
2222
echo "Usage: $0 [--unit <arg>] [--version] [--(no-)verbose] [--help] <filename>"
2323
echo -e "\t<filename>: "
24-
echo -e "\t-u,--unit: What unit we accept (b for bytes, k for kilobytes, M for megabytes) (default: '"b"')"
24+
echo -e "\t-u,--unit: What unit we accept (b for bytes, k for kibibytes, M for mebibytes) (default: '"b"')"
2525
echo -e "\t-v,--version: Prints version"
2626
echo -e "\t--verbose,--no-verbose: (default: 'off')"
2727
echo -e "\t-h,--help: Prints help"
@@ -65,12 +65,12 @@ for (( ii = 0; ii < ${#POSITIONALS[@]}; ii++))
6565
do
6666
eval "${POSITIONAL_NAMES[$ii]}=\"${POSITIONALS[$ii]}\"" || { echo "Error during argument parsing, possibly an Argbash bug." >&2; exit 1; }
6767
done
68+
6869
# OTHER STUFF GENERATED BY Argbash
6970

7071
### END OF CODE GENERATED BY Argbash (sortof) ### ])
7172
# [ <-- needed because of Argbash
7273

73-
# opening escape square bracket:
7474

7575
# ARG_HELP <-- Unlike one above, his one does not disappear, it is behind the escape bracket.
7676

@@ -85,12 +85,12 @@ FILENAME="$_ARG_FILENAME"
8585
if [ $VERBOSE = on ]
8686
then
8787
_b="bytes (B)"
88-
_kb="kilobytes (kB)"
89-
_mb="megabytes (MB)"
88+
_kb="kibibytes (kiB)"
89+
_mb="mebibytes (MiB)"
9090
else
9191
_b="B"
92-
_kb="kB"
93-
_mb="MB"
92+
_kb="kiB"
93+
_mb="MiB"
9494
fi
9595

9696
SIZE_BYTES=$(wc -c "$FILENAME" | cut -f 1 -d ' ')
@@ -106,5 +106,4 @@ test "$UNIT" = M && echo $SIZE_MEGABYTES $_mb && exit 0
106106
test "$VERBOSE" = on && echo "The unit '$UNIT' is not supported!"
107107
exit 1
108108

109-
# closing escape square bracket:
110109
# ] <-- needed because of Argbash

src/list.m4

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,13 @@ m4_define([m4_list_len], [m4_do(
3131
[m4_popdef([_LIST_NAME])],
3232
)])
3333

34+
dnl
35+
dnl Pefrorm an action if a given list is empty
36+
dnl $1: The list's ID
37+
dnl $2: The action to do if the list is empty or not even defined
38+
dnl $3: The action to do if the list is defined and non-empty
39+
m4_define([m4_list_ifempty], [m4_if(m4_list_len([$1]), 0, [$2], [$3])])
40+
3441
dnl
3542
dnl Given a list name, it expands to its contents, suitable to use e.g. in m4_foreach
3643
m4_define([m4_list_contents], [m4_do(

src/stuff.m4

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,10 @@ dnl $3: Help string
7474
dnl $4: Default, pass it through _sh_quote if needed beforehand (opt)
7575
dnl $5: Type
7676
m4_define([__some_opt], [m4_do(
77-
[m4_ifdef([WRAPPED], [m4_define([_COLLECT_]_varname([$1]), [_ARGS_]_translit(WRAPPED))])],
77+
[m4_ifdef([WRAPPED], [m4_do(
78+
[m4_set_add([_ARGS_GROUPS], m4_expand([[_ARGS_]_translit(WRAPPED)]))],
79+
[m4_define([_COLLECT_]_varname([$1]), [_ARGS_]_translit(WRAPPED)_OPT)],
80+
)])],
7881
[m4_list_add([_ARGS_LONG], [$1])],
7982
[dnl Check whether we didn't already use the arg, if not, add its tranliteration to the list of used ones
8083
],
@@ -146,6 +149,11 @@ m4_define([_ARG_POSITIONAL_SINGLE], [m4_do(
146149
[[$0($@)]],
147150
[IF_POSITIONALS_INF([m4_fatal([We already expect arbitrary number of arguments before '$1'. This is not supported])], [])],
148151
[IF_POSITIONALS_VARNUM([m4_fatal([The number of expected positional arguments before '$1' is unknown. This is not supported, define arguments that accept fixed number of values first.])], [])],
152+
[m4_ifdef([WRAPPED], [m4_do(
153+
[m4_set_add([_ARGS_GROUPS], m4_expand([[_ARGS_]_translit(WRAPPED)]))],
154+
[m4_set_add([_POS_VARNAMES], m4_expand([[_ARGS_]_translit(WRAPPED)_POS]))],
155+
[m4_list_add([_WRAPPED_ADD_SINGLE], m4_expand([[_ARGS_]_translit(WRAPPED)_POS+=@{:@"${_varname([$1])}"@:}@]))],
156+
)])],
149157
[dnl Number of possibly supplied positional arguments just went up
150158
],
151159
[m4_define([_POSITIONALS_MAX], m4_incr(_POSITIONALS_MAX))],
@@ -193,6 +201,11 @@ m4_define([_ARG_POSITIONAL_MULTI], [m4_do(
193201
[[$0($@)]],
194202
[IF_POSITIONALS_INF([m4_fatal([We already expect arbitrary number of arguments before '$1'. This is not supported])], [])],
195203
[IF_POSITIONALS_VARNUM([m4_fatal([The number of expected positional arguments before '$1' is unknown. This is not supported, define arguments that accept fixed number of values first.])], [])],
204+
[m4_ifdef([WRAPPED], [m4_do(
205+
[m4_set_add([_ARGS_GROUPS], m4_expand([[_ARGS_]_translit(WRAPPED)]))],
206+
[m4_set_add([_POS_VARNAMES], m4_expand([[_ARGS_]_translit(WRAPPED)_POS]))],
207+
[m4_list_add([_WRAPPED_ADD_SINGLE], m4_expand([[_ARGS_]_translit(WRAPPED)_POS+=@{:@${_varname([$1])@<:@@@:>@}@:}@]))]
208+
)])],
196209
[m4_define([_POSITIONALS_MAX], m4_if([$3], -1, -1, m4_eval(_POSITIONALS_MAX + [$3])))],
197210
[m4_list_add([_POSITIONALS_NAMES], [$1])],
198211
[m4_list_add([_POSITIONALS_TYPES], [more])],
@@ -452,7 +465,7 @@ m4_define([_MAKE_HELP], [m4_do(
452465
m4_define([_ADD_OPTS_VALS], [m4_do(
453466
[dnl If the arg comes from wrapped script/template, save it in an array
454467
],
455-
[m4_ifdef([_COLLECT_$1], [[_COLLECT_$1]+=("$[]1"m4_if($2, 2, ["$[]2"]))])],
468+
[m4_ifdef([_COLLECT_$1], [_COLLECT_$1+=("$[]1"m4_if($2, 2, [ "$[]2"]))])],
456469
)])
457470
458471
@@ -603,6 +616,12 @@ do
603616
eval "${POSITIONAL_NAMES[$ii]}=\"${POSITIONALS[$ii]}\"" || { echo "Error during argument parsing, possibly an Argbash bug." >&2; exit 1; }
604617
done]],
605618
[m4_popdef([_NARGS_SPEC])],
619+
[
620+
],
621+
[m4_list_ifempty([_WRAPPED_ADD_SINGLE], [], [m4_set_foreach([_POS_VARNAMES], [varname], [varname=@{:@@:}@
622+
])])],
623+
[m4_join([
624+
], m4_unquote(m4_list_contents([_WRAPPED_ADD_SINGLE])))],
606625
)])],
607626
)])
608627
@@ -660,6 +679,10 @@ m4_define([_MAKE_DEFAULTS], [m4_do(
660679
m4_define([_MAKE_OTHER], [m4_do(
661680
[[# OTHER STUFF GENERATED BY Argbash
662681
]],
682+
dnl Put the stuff below into some condition block
683+
, [m4_set_foreach([_ARGS_GROUPS], [agroup], [agroup=@{:@"${agroup[_OPT]@<:@@@:>@}" "${agroup[_POS]@<:@@@:>@}"@:}@
684+
])],
685+
[],
663686
[m4_list_declare([_OTHER])],
664687
[_OTHER_FOREACH([item
665688
])],
@@ -680,6 +703,7 @@ m4_define([ARGBASH_GO], [m4_do(
680703
[m4_ifndef([WRAPPED], [_ARGBASH_GO([$0()])])],
681704
)])
682705
706+
683707
dnl $1: The macro call (the caller is supposed to pass [$0($@)])
684708
m4_define([ARGBASH_GO_BASE], [m4_do(
685709
[[$1
@@ -725,11 +749,18 @@ m4_define([ARGBASH_WRAP], [m4_do(
725749
[m4_popdef([WRAPPED])],
726750
)])
727751
752+
728753
dnl If I am wrapped:
729754
dnl defns are applied, but not recorded
730755
dnl some are not even recorded
731756
dnl It may be that the wrapped script contains args that we already have.
732757
dnl In this case: Raise an error (with a good advice)
733758
dnl
734759
735-
dnl TODO: Add a repeated optional arg (s.a. -I in gcc)
760+
dnl Positional args wrapped:
761+
dnl - we keep a list POS_WRAPPED, where we store names of positional args that we want record.
762+
dnl - OR: When we encounter a wrapped positional arg, we store a code block <ARGS_ARRAY>+=pos_arg
763+
dnl - and at the end, we just expand this block after pos_arg vars are filled.
764+
dnl - after positional args are assigned, we go through this list and append to the array of passed wrapped args
765+
dnl
766+
dnl TODO: Implement leftover args

tests/regressiontests/Makefile

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ REVERSE = $(TESTDIR)/reverse
99
%.sh: %.m4 $(ARGBASH_BIN)
1010
$(word 2,$^) $< -o $@
1111

12+
# Let test-gen be last - those tests take the longest time to complete
1213
TESTS = \
1314
test-most \
1415
test-more \
@@ -19,12 +20,12 @@ TESTS = \
1920
test-onlyopt \
2021
test-onlypos \
2122
test-ddash \
22-
test-gen \
2323
test-simple \
2424
test-wrapping \
2525
test-wrapping-more \
2626
test-wrapping-excl \
2727
stability-wrapping \
28+
test-gen \
2829
$(NUL)
2930

3031
PHONIES += $(TESTS)
@@ -145,9 +146,10 @@ test-wrapping: $(TESTDIR)/test-wrapping.sh $(TESTDIR)/test-onlyopt.m4 $(TESTDIR)
145146
$< -h | grep -q pos-arg
146147
@# ! negates the return code
147148
! $< -h | grep -q boo_l
148-
$< LOOL | grep -q 'POS_S=LOOL,POS_OPT=pos-default'
149-
$< LOOL | grep -q 'POS_S=LOOL,POS_OPT=pos-default'
150-
$< LOOL --opt-arg lalala | grep -q OPT_S=lalala,
149+
$< XX LOOL | grep -q 'POS_S0=XX,POS_S=LOOL,POS_OPT=pos-default'
150+
$< XX LOOL | grep -q 'POS_S=LOOL,POS_OPT=pos-default'
151+
$< XX LOOL --opt-arg lalala | grep -q OPT_S=lalala,
152+
$< XX LOOL --opt-arg lalala | grep -q 'CMDLINE=--opt-arg lalala LOOL pos-default,'
151153

152154
test-wrapping-more: $(TESTDIR)/test-wrapping-more.sh $(TESTDIR)/test-onlyopt.m4
153155
$< -i -i -i | grep -q 'CMDLINE=-i -i -i,'

0 commit comments

Comments
 (0)