56 Commits

Author SHA1 Message Date
  Alois Mahdal f872308193 Bump version to 0.10.27 4 years ago
  Alois Mahdal 411a359a0e Update TFKit to v0.0.18 4 years ago
  Alois Mahdal d0f12a2382 Mute ShellCheck warning about temp var 4 years ago
  Alois Mahdal a0fdf26b0f Enable Vornet Gladness pipeline 4 years ago
  Alois Mahdal 72bee24d1e Clarify list format for PRETTY_DEBUG_EXCLUDE 4 years ago
  Alois Mahdal ce4c42a9dc Update MKit to v0.0.40 4 years ago
  Alois Mahdal 04bbe6879e Bump version to 0.10.26 4 years ago
  Alois Mahdal dcdcd52728 Use leagacy mode for shellfu-sh-coerce also for RHEL-7 4 years ago
  Alois Mahdal 2d34f223af Bump version to 0.10.25 4 years ago
  Alois Mahdal 477cd50b82 Switch to less cynical branch naming convention 4 years ago
  Alois Mahdal f40b74432d Update MKit to v0.0.39 4 years ago
  Alois Mahdal 82a1c25930 Add -h to enable overriding definition of "hidden" 4 years ago
  Alois Mahdal 32bdba11b9 Add SFDOC_HIDE_REGEX to enable overriding definition of "hidden" 4 years ago
  Alois Mahdal 0922e6f4e6 Bump version 4 years ago
  Alois Mahdal e96616b77e Enable reloading modules 4 years ago
  Alois Mahdal cfb2e0f7cd Don't enforce debuging and verbosity modes on import 4 years ago
  Alois Mahdal 380eda671e Bump version 4 years ago
  Alois Mahdal aaa36c1b0a Fix bug when sfpi__key() would not ever return anything 4 years ago
  Alois Mahdal 5caf0cfba9 Bump version 4 years ago
  Alois Mahdal 93fa1abb5a Fix typo in usage error template 4 years ago
  Alois Mahdal fc20097925 Mention usage error templates in mkusage() docstring 4 years ago
  Alois Mahdal 83a4c9785d Bump version 4 years ago
  Alois Mahdal 171848a5fa Add extra shorthand arguments for common usage errors 4 years ago
  Alois Mahdal 42621995c2 Fortify command, file and pipe delimiters 4 years ago
  Alois Mahdal 089d0a76d0 Bump version 4 years ago
  Alois Mahdal d80a3cdc58 Add arr.sh, couple of utilities for array manipulation 4 years ago
  Alois Mahdal 47316ab8b7 Update TFKit to v0.0.17 4 years ago
  Alois Mahdal fb18926932 Bump version 4 years ago
  Alois Mahdal db7e27520b Add 'forcecolor' module 4 years ago
  Alois Mahdal 8e0cfadb13 Bump version 5 years ago
  Alois Mahdal 7eee5bb2fc Update MKit to v0.0.37 5 years ago
  Alois Mahdal 8875772d4d Bump version 5 years ago
  Alois Mahdal 4750ad76f3 Elaborate more in the docstring 5 years ago
  Alois Mahdal d7193295d0 Replace, don't remove control characters 5 years ago
  Alois Mahdal b1f3060143 Don't (mis)use tr/// to remove non-printables 5 years ago
  Alois Mahdal b00d06dfe4 Bump version 5 years ago
  Alois Mahdal 4112218fac Add legacy mode to avoid Term::ANSIColor dependency on RHEL-6 5 years ago
  Alois Mahdal e75c4b45d6 Bump version 5 years ago
  Alois Mahdal e5c2c211f9 Fix syntax error in debian/control 5 years ago
  Alois Mahdal fcd7da8d05 Bump version 5 years ago
  Alois Mahdal 76ccd1c093 Add missing file listings 5 years ago
  Alois Mahdal 7b7cc4b4a9 Add missing Perl dependencies 5 years ago
  Alois Mahdal 4e2cc49d13 Fix typo in .spec file 5 years ago
  Alois Mahdal 75dd46520b Bump version 5 years ago
  Alois Mahdal 0bec8ed937 Jump to first object mention in object mode 5 years ago
  Alois Mahdal e5f1740095 Add third import group for consistency with PEP8 5 years ago
  Alois Mahdal 13ac645e1e Remove leftover debug junk 5 years ago
  Alois Mahdal 508911f0b1 Fix typo 5 years ago
  Alois Mahdal e2214d4c0f Add coerce.sh for character set coercion 5 years ago
  Alois Mahdal 72a248a0c7 Bump version 5 years ago
  Alois Mahdal a11b72dea4 Improve an update tab completion for sfdoc 5 years ago
  Alois Mahdal ff4a9a4745 Stop stomping 'mname' global 5 years ago
  Alois Mahdal c788a63ddc Fix --which treated as if no value was needed 5 years ago
  Alois Mahdal 64964d7049 Avoid grep ambiguities 5 years ago
  Alois Mahdal ef4887123b Update MKit to v0.0.36 5 years ago
  Alois Mahdal 085aea4e87 Drop the 'draft' weasel-word 5 years ago

+ 5
- 0
.gitlab-ci.yml View File

@@ -0,0 +1,5 @@
1
+---
2
+include:
3
+  - project: 'vornet/infra/gladness'
4
+    ref: master
5
+    file: '/pipelines/shellfu.yaml'

+ 1
- 1
README.md View File

@@ -87,7 +87,7 @@ And that's also *all* this command does.
87 87
 Next, if you have also installed some modules, you can look around
88 88
 using `sfdoc`:
89 89
 
90
-    sfdoc --lsmods
90
+    sfdoc --lsmod
91 91
     sfdoc inigrep
92 92
 
93 93
 This is how you access documentation of modules available on the system.

+ 2
- 2
mkit.ini View File

@@ -1,5 +1,5 @@
1 1
 [project]
2
-    version     = 0.10.11
2
+    version     = 0.10.27
3 3
     codename    = FloatingPointError
4 4
     name        = Shellfu
5 5
     tagline     = Shell dot on steroids
@@ -7,7 +7,7 @@
7 7
     maintainer  = Alois Mahdal <netvor@vornet.cz>
8 8
     vcs_browser = https://pagure.io/shellfu
9 9
     relsrc      = master
10
-    reldst      = last
10
+    reldst      = latest
11 11
 
12 12
 [dist]
13 13
     tarball  = LICENSE.md

+ 2
- 1
notes/style.md View File

@@ -1,4 +1,4 @@
1
-Coding style - draft
1
+Coding style
2 2
 ============
3 3
 
4 4
 This is the official coding style for Shellfu project.
@@ -84,6 +84,7 @@ Imports should be grouped in this order:
84 84
 
85 85
  1. standard library modules,
86 86
  2. related third party modules,
87
+ 3. local application/library specific imports,
87 88
 
88 89
 with empty line between the groups, and each group being sorted
89 90
 alphabetically.

+ 38
- 1
packaging/debian/control View File

@@ -48,6 +48,23 @@ Description: Bash-specific base
48 48
  This sub-package contains Bash-specific parts of library infrastructure.
49 49
  Shellfu modules written for Bash should depend on this.
50 50
 
51
+Package: shellfu-bash-arr
52
+Architecture: all
53
+Depends: shellfu-bash, shellfu-bash-pretty, shellfu-sh-isa
54
+Description: Array utilities
55
+ Shellfu is an attempt to add modularity to your shell scripts.
56
+ .
57
+ With Shellfu you can develop your shell modules separately from your
58
+ scripts, and test, use, explore or study them without need to be aware
59
+ of details such as where the actual files are placed.
60
+ .
61
+ Shellfu is mostly intended for cases when there's need for non-trivial
62
+ amount of reliable body of shell scripts, and access to advanced modular
63
+ languages such as Python or Perl is limited.
64
+ .
65
+ This sub-package contains 'arr', Shellfu/Bash module with few utilities
66
+ for manipulating Bash arrays
67
+
51 68
 Package: shellfu-bash-inigrep
52 69
 Architecture: all
53 70
 Depends: shellfu-bash, shellfu-bash-pretty
@@ -172,6 +189,26 @@ Description: Shellfu/sh module for building interactive terminal menus
172 189
  This sub-package contains 'charmenu', a Shellfu/sh module for building
173 190
  interactive terminal menus
174 191
 
192
+Package: shellfu-sh-coerce
193
+Architecture: all
194
+Depends:
195
+ shellfu-sh,
196
+ perl,
197
+ perl-modules,
198
+Description: Shellfu/sh module with data coercion helpers
199
+ Shellfu is an attempt to add modularity to your shell scripts.
200
+ .
201
+ With Shellfu you can develop your shell modules separately from your
202
+ scripts, and test, use, explore or study them without need to be aware
203
+ of details such as where the actual files are placed.
204
+ .
205
+ Shellfu is mostly intended for cases when there's need for non-trivial
206
+ amount of reliable body of shell scripts, and access to advanced modular
207
+ languages such as Python or Perl is limited.
208
+ .
209
+ This sub-package contains 'coerce', Shellfu module containing few
210
+ data coercion helpers.
211
+
175 212
 Package: shellfu-sh-exit
176 213
 Architecture: all
177 214
 Depends: shellfu-sh
@@ -245,4 +282,4 @@ Description: Shellfu/sh module for terminal color names
245 282
  common ANSI color names.
246 283
 
247 284
 
248
-# control file built with MKit __MKIT_SELF_VERSION__
285
+# control file built with MKit __MKIT_MKIT_VERSION__

+ 1
- 0
packaging/debian/shellfu-bash-arr.install View File

@@ -0,0 +1 @@
1
+/usr/share/shellfu/include-bash/arr.sh

+ 1
- 0
packaging/debian/shellfu-bash-pretty.install View File

@@ -1,4 +1,5 @@
1 1
 /usr/share/shellfu/include-bash/_pretty_color.sh
2
+/usr/share/shellfu/include-bash/_pretty_forcecolor.sh
2 3
 /usr/share/shellfu/include-bash/_pretty_html.sh
3 4
 /usr/share/shellfu/include-bash/_pretty_journald.sh
4 5
 /usr/share/shellfu/include-bash/_pretty_notify.sh

+ 1
- 0
packaging/debian/shellfu-sh-coerce.install View File

@@ -0,0 +1 @@
1
+/usr/share/shellfu/include-sh/coerce.sh

+ 36
- 1
packaging/template.spec View File

@@ -4,6 +4,12 @@
4 4
 %global pspkg procps-ng
5 5
 %endif
6 6
 
7
+%if ( 0%{?rhel} && 0%{?rhel} < 8 ) || ( 0%{?centos} && 0%{?centos} < 8 )
8
+%global legacy_coerce true
9
+%else
10
+%global legacy_coerce false
11
+%endif
12
+
7 13
 Name:           __MKIT_PROJ_PKGNAME__
8 14
 Version:        __MKIT_PROJ_VERSION__
9 15
 Release:        1%{?dist}
@@ -38,6 +44,15 @@ Requires: shellfu
38 44
 This sub-package contains Bash-specific parts of library infrastructure.
39 45
 Shellfu modules written for Bash should depend on this.
40 46
 
47
+%package bash-arr
48
+Summary: Array utilities
49
+Requires: shellfu-bash
50
+Requires: shellfu-bash-pretty
51
+Requires: shellfu-sh-isa
52
+%description bash-arr
53
+This sub-package contains 'arr', Shellfu/Bash module with few utilities
54
+for manipulating Bash arrays
55
+
41 56
 %package bash-inigrep
42 57
 Summary: INI grepping Shellfu/Bash module
43 58
 Requires: perl
@@ -97,6 +112,17 @@ Obsoletes: shellfu-bash-extras < 0.10
97 112
 This sub-package contains 'charmenu', a Shellfu/sh module for building
98 113
 interactive terminal menus
99 114
 
115
+%package sh-coerce
116
+Summary: Shellfu/sh module with data coercion helpers
117
+Requires: perl
118
+%if %{legacy_coerce} == "false"
119
+Requires: perl-Term-ANSIColor
120
+%endif
121
+Requires: shellfu-sh
122
+%description sh-coerce
123
+This sub-package contains 'coerce', Shellfu module containing few
124
+data coercion helpers.
125
+
100 126
 %package sh-exit
101 127
 Summary: Shellfu/sh module for standard exit statuses
102 128
 Requires: shellfu-sh
@@ -129,6 +155,8 @@ common ANSI color names.
129 155
 
130 156
 %prep
131 157
 %setup -q
158
+/bin/sed -i '/^__COERCE__LEGACY=/s/:-false/:-%{legacy_coerce}/' ./src/include-sh/coerce.sh
159
+
132 160
 
133 161
 %build
134 162
 make %{?_smp_mflags} PREFIX=/usr
@@ -155,11 +183,15 @@ make test \
155 183
 %files bash
156 184
 %dir %{_datadir}/%{name}/include-bash
157 185
 
186
+%files bash-arr
187
+%{_datadir}/%{name}/include-bash/arr.sh
188
+
158 189
 %files bash-inigrep
159 190
 %{_datadir}/%{name}/include-bash/inigrep.sh
160 191
 
161 192
 %files bash-pretty
162 193
 %{_datadir}/%{name}/include-bash/_pretty_color.sh
194
+%{_datadir}/%{name}/include-bash/_pretty_forcecolor.sh
163 195
 %{_datadir}/%{name}/include-bash/_pretty_html.sh
164 196
 %{_datadir}/%{name}/include-bash/_pretty_journald.sh
165 197
 %{_datadir}/%{name}/include-bash/_pretty_notify.sh
@@ -181,6 +213,9 @@ make test \
181 213
 %files sh-charmenu
182 214
 %{_datadir}/%{name}/include-sh/charmenu.sh
183 215
 
216
+%files sh-coerce
217
+%{_datadir}/%{name}/include-sh/coerce.sh
218
+
184 219
 %files sh-exit
185 220
 %{_datadir}/%{name}/include-sh/exit.sh
186 221
 
@@ -195,4 +230,4 @@ make test \
195 230
 
196 231
 %changelog
197 232
 
198
-# specfile built with MKit __MKIT_SELF_VERSION__
233
+# specfile built with MKit __MKIT_MKIT_VERSION__

+ 13
- 5
src/bin/sfdoc View File

@@ -12,7 +12,7 @@ usage() {
12 12
         "[options] MODULE"                                              \
13 13
         "[options] --ls [MODULE]"                                       \
14 14
         "[options] --ls{var|fun} MODULE"                                \
15
-        "[options] --which"                                             \
15
+        "[options] --which MODULE"                                      \
16 16
         "[options] --lsmod"                                             \
17 17
         "[options] -s|--src MODULE"                                     \
18 18
         "[options] --export FMT MODULE"                                 \
@@ -31,6 +31,8 @@ usage() {
31 31
             "-O, --object       Treat MODULE as function or variable"   \
32 32
             "                   name and find respective module first." \
33 33
             "-d, --debug        Turn on debugging"                      \
34
+            "-h, --hide REGEX   Use REGEX to determine what is hidden." \
35
+            "                   (See also -a and 'sfdoc sfdoc'.)"       \
34 36
             "-a, --all          Don't ignore hidden (starting with"     \
35 37
             "                   underscore) modules or objects"         \
36 38
             "--encoding ENC     Override encoding of the source text"   \
@@ -93,6 +95,7 @@ main() {
93 95
     local RealModuleName    # name to override eg. if accessing via filename
94 96
     local encoding          # encoding
95 97
     local mpath             # path to module file
98
+    local jump              # jump to first occurence of this
96 99
     action=man
97 100
     format=markdown
98 101
     encoding=utf8
@@ -102,6 +105,7 @@ main() {
102 105
         -O|--object)    spectype=obj;               shift ;;
103 106
         -d|--debug)     PRETTY_DEBUG=true;          shift ;;
104 107
         -a|--all)       SFDOC_SHOW_HIDDEN=true;     shift ;;
108
+        -h|--hide)      SFDOC_SHOW_HIDDEN=false; SFDOC_HIDE_REGEX="$2"; shift 2 || usage -w "no REGEX?" ;;
105 109
         -I|--include)   SHELLFU_PATH="$2:$SHELLFU_PATH"; shift 2 || usage -w "no PTH?" ;;
106 110
         -s|--src)       action=src;                 shift; break ;;
107 111
         -l|--ls)        action=lsx;                 shift; break ;;
@@ -120,12 +124,14 @@ main() {
120 124
     debug -v SHELLFU_INCLUDE SHELLFU_PATH SFDOC_SHOW_HIDDEN
121 125
     debug -v action format module RealModuleName
122 126
     case $action:$mspec in
123
-        lsx:*|lsm:*|wch:*) true ;;
127
+        lsx:*|lsm:*)    true ;;
124 128
         *:)             usage -w "no MODULE?" ;;
125 129
     esac
126 130
     case $spectype in
127 131
         obj) module=$(find_by "$mspec") \
128
-              || die "no module found with: $mspec" ;;
132
+              || die "no module found with: $mspec"
133
+             jump="$mspec"
134
+             ;;
129 135
         *)   module=$mspec ;;
130 136
     esac
131 137
     case $action in
@@ -134,7 +140,7 @@ main() {
134 140
     esac
135 141
     case $action in
136 142
         exp)    # --export
137
-            grep -qw "$format" <<<manpage,markdown,pod \
143
+            grep -qwe "$format" <<<manpage,markdown,pod \
138 144
              || die "unknown format: $format"
139 145
             sfdoc__export "$format" "${RealModuleName:-$module}" "$mpath" "$encoding"
140 146
             ;;
@@ -164,7 +170,9 @@ main() {
164 170
              || die "pod2man is missing; cannot use man page mode"
165 171
             manfile=$(mktemp -t "sfdoc.manfile.XXXXXXXX")
166 172
             sfdoc__export manpage "${RealModuleName:-$module}" "$mpath" "$encoding" >"$manfile"
167
-            man "$manfile"
173
+            manless="$LESS"
174
+            test -n "$jump" && manless+=" +/$jump"
175
+            LESS="$manless" man "$manfile"
168 176
             rm "$manfile"
169 177
             ;;
170 178
         src)

+ 69
- 6
src/complete.bash View File

@@ -1,25 +1,88 @@
1 1
 
2 2
 __sfpath() {
3
-    local cur prev opts
3
+    local cur       # current word
4
+    local prev      # previous word
5
+    local lopts     # long options
4 6
     COMPREPLY=()
5 7
     cur="${COMP_WORDS[COMP_CWORD]}"
6 8
     prev="${COMP_WORDS[COMP_CWORD-1]}"
7
-    opts="--version --version-semver"
9
+    lopts="--version --version-semver"
8 10
     COMPREPLY=(
9
-        $(compgen -W "$opts" -- ${cur})
11
+        $(compgen -W "$lopts" -- "$cur")
10 12
     )
11 13
 }
12 14
 
13 15
 __sfdoc() {
14
-    local cur prev opts
16
+    local cur       # current word
17
+    local prev      # previous word
18
+    local opts      # options
19
+    local rest      # rest of options
20
+    local cmds      # commands
21
+    local crtext    # text for COMPREPLY
15 22
     COMPREPLY=()
16 23
     cur="${COMP_WORDS[COMP_CWORD]}"
17 24
     prev="${COMP_WORDS[COMP_CWORD-1]}"
18
-    args="--help --debug --include --ls --lsmod --lsfun --lsvar --export --name"
25
+    opts="-d -O -a -I -o --debug --object --all --include --only-from --encoding --name"
26
+    cmds="-l -L -s -e --ls --lsvar --lsfun --which --lsmod --src --export"
27
+    rest="${opts/$prev/}"
28
+    crtext=$(
29
+        case $prev in
30
+            sfdoc)                  echo "$opts $cmds"; __sfdoc_compgen_M2 ;;
31
+            -d|--debug)             echo "$rest $cmds"; __sfdoc_compgen_M3 ;;
32
+            -O|--object)            echo "$rest $cmds"; __sfdoc_compgen_M3 ;;
33
+            -a|--all)               echo "$rest $cmds"; __sfdoc_compgen_M3 ;;
34
+            -I|--include)           compgen -o nospace -d -- "$cur" ;;
35
+            -o|--only-from)         compgen -o nospace -d -- "$cur" ;;
36
+            --encoding)             iconv -l | tr '[:upper:]' '[:lower:]' | sed s://$:: ;;
37
+            --name)                 echo "" ;;
38
+            -e|--export)            echo "markdown manpage pod" ;;
39
+            -s|--src)               __sfdoc_compgen_M3 ;;
40
+            -l|--ls)                __sfdoc_compgen_M2 ;;
41
+            --lsfun|--lsvar)        __sfdoc_compgen_M2 ;;
42
+            --which)                sfdoc --lsmod ;;
43
+            markdown|manpage|pod)   __sfdoc_cwhas "-e" "--export" \
44
+                                      && __sfdoc_compgen_M3  ;;
45
+        esac
46
+    )
19 47
     COMPREPLY=(
20
-        $(compgen -W "$args" -- ${cur})
48
+        $(compgen -W "$crtext" -- "$cur")
21 49
     )
22 50
 }
23 51
 
52
+__sfdoc_compgen_M2() {
53
+    #
54
+    # Produce list of possible MODULE values
55
+    #
56
+    case $cur in
57
+        */*)    compgen -f -o nospace -- "$cur" ;;
58
+        *)      sfdoc --lsmod ;;
59
+    esac
60
+}
61
+
62
+__sfdoc_cwhas() {
63
+    #
64
+    # True if COMP_WORDS already has word $1 or $2...
65
+    #
66
+    local word
67
+    local want
68
+    for want in "$@"; do
69
+        for word in "${COMP_WORDS[@]}"; do
70
+            test "$word" == "$want" && return 0
71
+        done
72
+    done
73
+    return 1
74
+}
75
+
76
+__sfdoc_compgen_M3() {
77
+    #
78
+    # Produce list of possible MODULE values
79
+    #
80
+    if __sfdoc_cwhas "-O" "--object"; then
81
+        sfdoc --ls | cut -d: -f2
82
+    else
83
+        __sfdoc_compgen_M2
84
+    fi
85
+}
86
+
24 87
 complete -F __sfpath sfpath
25 88
 complete -F __sfdoc sfdoc

+ 62
- 0
src/include-bash/_pretty_forcecolor.sh View File

@@ -0,0 +1,62 @@
1
+#!/bin/bash
2
+
3
+shellfu import termcolors
4
+
5
+
6
+_PRETTY_FORCECOLOR_DEBUG="${TERMCOLORS_LBLUE}"
7
+_PRETTY_FORCECOLOR_DIE="${TERMCOLORS_LRED}"
8
+_PRETTY_FORCECOLOR_USAGE_IS="${TERMCOLORS_YELLOW}"
9
+_PRETTY_FORCECOLOR_THINK="${TERMCOLORS_LBLACK}"
10
+_PRETTY_FORCECOLOR_WARN="${TERMCOLORS_LRED}"
11
+_PRETTY_FORCECOLOR_OFF="${TERMCOLORS_NONE}"
12
+
13
+
14
+_pretty__debug() {
15
+    local decor="()"
16
+    local caller_is_main=${caller_is_main:-false}
17
+    local caller=${caller:-UNKNOWN}
18
+    $caller_is_main && decor=
19
+    while IFS= read -r line;
20
+    do echo -ne "${_PRETTY_FORCECOLOR_DEBUG}debug:$caller$decor:$_PRETTY_FORCECOLOR_OFF"
21
+       echo "$line"; done
22
+}
23
+
24
+
25
+_pretty__die() {
26
+    echo -ne "$_PRETTY_FORCECOLOR_DIE"
27
+    while IFS= read -r line;
28
+    do echo "$line"; done
29
+    echo -ne "$_PRETTY_FORCECOLOR_OFF"
30
+}
31
+
32
+
33
+_pretty__mkhelp() {
34
+    echo -ne "$_PRETTY_FORCECOLOR_USAGE_IS"
35
+    while IFS= read -r line;
36
+    do echo -e "$line"; done
37
+    echo -ne "$_PRETTY_FORCECOLOR_OFF"
38
+}
39
+
40
+
41
+_pretty__mkusage() {
42
+    echo -ne "$_PRETTY_FORCECOLOR_USAGE_IS"
43
+    while IFS= read -r line;
44
+    do echo -e "$line"; done
45
+    echo -ne "$_PRETTY_FORCECOLOR_OFF"
46
+}
47
+
48
+
49
+_pretty__think() {
50
+    echo -ne "$_PRETTY_FORCECOLOR_THINK"
51
+    while IFS= read -r line;
52
+    do echo "$line"; done
53
+    echo -ne "$_PRETTY_FORCECOLOR_OFF"
54
+}
55
+
56
+
57
+_pretty__warn() {
58
+    echo -ne "$_PRETTY_FORCECOLOR_WARN"
59
+    while IFS= read -r line;
60
+    do echo "$line"; done
61
+    echo -ne "$_PRETTY_FORCECOLOR_OFF"
62
+}

+ 98
- 0
src/include-bash/arr.sh View File

@@ -0,0 +1,98 @@
1
+#!/bin/bash
2
+
3
+shellfu import isa
4
+shellfu import pretty
5
+
6
+#
7
+# Array utilities
8
+#
9
+# Several utilities for loading and printing Bash arrays.
10
+#
11
+
12
+arr__fromcmd() {
13
+    #
14
+    # Save output lines from command $2.. to array named $1
15
+    #
16
+    # Usage:
17
+    #     arr__fromcmd ARRAY CMD [ARG]..
18
+    #
19
+    # Unlike `mapfile -t <<<"$(command)", this produces zero
20
+    # items if command output was empty.
21
+    #
22
+    local __arr__fromcmd__oarr=$1; shift
23
+    local __arr__fromcmd__cmd=("$@")
24
+    local __arr__fromcmd__tmp
25
+    local es
26
+    __arr__val_oarr "$__arr__fromcmd__oarr" || return 2
27
+    __arr__fromcmd__tmp=$(mktemp arr__fromcmd.__arr__fromcmd__tmp.XXXXX)
28
+    "${__arr__fromcmd__cmd[@]}" > "$__arr__fromcmd__tmp"; es=$?
29
+    mapfile -t "$__arr__fromcmd__oarr" <"$__arr__fromcmd__tmp"
30
+    rm "$__arr__fromcmd__tmp"
31
+    return $es
32
+}
33
+
34
+arr__has() {
35
+    #
36
+    # True if value $1 is in array $2
37
+    #
38
+    # Usage:
39
+    #     arr__has VALUE ARRAY
40
+    #
41
+    local want=$1
42
+    local iarr=$2
43
+    local copy
44
+    local value
45
+    local code
46
+    __arr__val_iarr "$iarr" || return 2
47
+    code=$(declare -p "$iarr"); code=${code/ $iarr=/ copy=}
48
+    eval "$code"
49
+    for value in "${copy[@]}"; do
50
+        test "$value" == "$want" && return 0
51
+    done
52
+    return 1
53
+}
54
+
55
+arr__join() {
56
+    #
57
+    # Join items in array $2 by string $1
58
+    #
59
+    # Usage:
60
+    #     arr__join DELIM ARRAY
61
+    #
62
+    # Example:
63
+    #
64
+    #     names=( Alice Bob )
65
+    #     arr__join , names
66
+    #     # prints 'Alice,Bob'
67
+    #
68
+    local delim=$1
69
+    local iarr=$2
70
+    local first=true
71
+    local item
72
+    local copy
73
+    local code
74
+    __arr__val_iarr "$iarr" || return 2
75
+    code=$(declare -p "$iarr"); code=${code/ $iarr=/ copy=}
76
+    eval "$code"
77
+    for item in "${copy[@]}"; do
78
+        $first || echo -n "$delim"
79
+        first=false
80
+        echo -n "$item"
81
+    done
82
+}
83
+
84
+__arr__val_iarr() {
85
+    #
86
+    # Validate input array named $1
87
+    #
88
+    local name=$1
89
+    set | grep -q "^$name=" || { warn "no such array: $name"; return 2; }
90
+}
91
+
92
+__arr__val_oarr() {
93
+    #
94
+    # Validate output array named $1
95
+    #
96
+    local name=$1
97
+    isa__name "$name" || { warn "invalid array name: $name"; return 2; }
98
+}

+ 26
- 13
src/include-bash/pretty.sh View File

@@ -5,10 +5,10 @@ shellfu import exit
5 5
 #
6 6
 # Application debug mode
7 7
 #
8
-PRETTY_DEBUG=${PRETTY_DEBUG:-false}
8
+PRETTY_DEBUG=${PRETTY_DEBUG:-}
9 9
 
10 10
 #
11
-# List of module/function names to exclude from debuging
11
+# Comma-separated list of module/function names to exclude from debuging
12 12
 #
13 13
 # For the sake of readability of your debug dumps, you can set this
14 14
 # variable to comma-separated list of module or function names that
@@ -24,7 +24,7 @@ PRETTY_DEBUG_EXCLUDE=${PRETTY_DEBUG_EXCLUDE:-}
24 24
 #
25 25
 # Application verbosity mode
26 26
 #
27
-PRETTY_VERBOSE=${PRETTY_VERBOSE:-false}
27
+PRETTY_VERBOSE=${PRETTY_VERBOSE:-}
28 28
 
29 29
 #
30 30
 # Name of pretty-printer module
@@ -76,7 +76,7 @@ debug() {
76 76
     #     debug "var1=$var1" "var2=$var2" "result=$result"
77 77
     #     debug -v var1 var2 result
78 78
     #
79
-    $PRETTY_DEBUG || return 0
79
+    test "$PRETTY_DEBUG" == true || return 0
80 80
     _pretty__echo "$@"
81 81
 }
82 82
 
@@ -135,7 +135,14 @@ mkusage() {
135 135
     #
136 136
     # Optionally, you can add -w MSG to add clarifying message
137 137
     # (presented as warning) to help user understand what is
138
-    # wrong with arguments they have passed.
138
+    # wrong with arguments they have passed.  Alternatively,
139
+    # -m SUBJ, -M SUBJ, -u SUBJ, and -U SUBJ are shorthands for
140
+    # error messages describing missing positional argument (-m),
141
+    # missing value to a parametrized argument (-M), unknown
142
+    # argument (-u) or unknown command (-U).  Using these
143
+    # shorthands you don't need  to provide whole message, but
144
+    # only subject in question; rest of the message is provided
145
+    # by pretty.sh.
139 146
     #
140 147
     # Use "--" to delimit end of arguments processed by mkusage.
141 148
     #
@@ -154,6 +161,10 @@ mkusage() {
154 161
         -E) doexit=false;   shift ;;
155 162
         -k) es=$EXIT_OK;    shift ;;
156 163
         -w) cmsg="$2";      shift 2 || return 2 ;;
164
+        -m) cmsg="no $2?";  shift 2 || return 2 ;;
165
+        -M) cmsg="missing value for: $2";    shift 2 || return 2 ;;
166
+        -u) cmsg="unknown argument: $2";     shift 2 || return 2 ;;
167
+        -U) cmsg="unknown command: $2";      shift 2 || return 2 ;;
157 168
         --)                 shift; break ;;
158 169
         *)                  break ;;
159 170
     esac done
@@ -203,7 +214,7 @@ think() {
203 214
     # Use "-l" to split every parameter to separate line, (useful
204 215
     # or longer warnings)
205 216
     #
206
-    $PRETTY_VERBOSE || return 0
217
+    test "$PRETTY_VERBOSE" == true || return 0
207 218
     _pretty__echo "$@"
208 219
 }
209 220
 
@@ -378,11 +389,10 @@ _pretty__echo_cmd() {
378 389
     #
379 390
     # Print command line, launch it and report exit status
380 391
     #
381
-    local c=\$
382
-    test "$(id -u)" -eq 0 && c="#"
383
-    echo "$c $*"
384
-    "$@"
385
-    echo "^ exit status: $?"
392
+    local es
393
+    echo "-- begin command $* --"
394
+    "$@"; es=$?
395
+    echo "-- end command ($es) $* --"
386 396
 }
387 397
 
388 398
 
@@ -393,10 +403,13 @@ _pretty__echo_files() {
393 403
     local fp
394 404
     for fp in "$@"; do
395 405
         if test "$fp" = "-"; then
406
+            echo "-- begin pipe --"
396 407
             cat
408
+            echo "-- end pipe --"
397 409
         elif test -s "$fp" || test "$fp" = "/dev/stdin"; then
398
-            echo "-- $fp --"
410
+            echo "-- begin file $fp --"
399 411
             cat "$fp"
412
+            echo "-- end file $fp --"
400 413
         fi
401 414
     done
402 415
 }
@@ -415,7 +428,7 @@ _pretty__echo_trace() {
415 428
     #
416 429
     # Print "decorated" call trace (only in debug mode)
417 430
     #
418
-    $PRETTY_DEBUG || return 0
431
+    test "$PRETTY_DEBUG" == true || return 0
419 432
     local depth
420 433
     echo "== trace =="
421 434
     for depth in $(seq 0 ${#FUNCNAME}); do

+ 18
- 3
src/include-bash/sfdoc.sh View File

@@ -23,8 +23,22 @@ shellfu import pretty
23 23
 # with `_` (underscore).  These are ignored by default.  Set this to 'true' to show
24 24
 # them.
25 25
 #
26
+# See also $SFDOC_HIDE_REGEX.
27
+#
26 28
 SFDOC_SHOW_HIDDEN=${SFDOC_SHOW_HIDDEN:-false}
27 29
 
30
+#
31
+# Regex to override what is hidden
32
+#
33
+# Override definition of which objects are considered "private", thus hidden
34
+# by default.  Regular expression is used as Extended Regular Expressions,
35
+# is anchored on both sides and case-sensitive, e setting 'foo|bAr' matches
36
+# only objects whose entire name is either 'foo' or 'bAr'.
37
+#
38
+# See also $SFDOC_SHOW_HIDDEN.
39
+#
40
+SFDOC_HIDE_REGEX=${SFDOC_HIDE_REGEX:-_.*}
41
+
28 42
 sfdoc__export() {
29 43
     #
30 44
     # Export docs of module $2 from file $3 as format $3
@@ -345,10 +359,11 @@ __sfdoc__filter_hidden() {
345 359
     #
346 360
     local what=$1
347 361
     $SFDOC_SHOW_HIDDEN && cat && return
362
+    debug -v SFDOC_HIDE_REGEX
348 363
     case $what in
349
-        m)  grep -v ^_ ;;
350
-        v)  grep -v :_ ;;
351
-        f)  grep -v :_ ;;
364
+        m)  grep -vE "^$SFDOC_HIDE_REGEX$" ;;
365
+        v)  grep -vE ":$SFDOC_HIDE_REGEX$" ;;
366
+        f)  grep -vE ":$SFDOC_HIDE_REGEX$" ;;
352 367
         *)  warn "bug: invalid object type: $otype" ;;
353 368
     esac
354 369
 }

+ 11
- 8
src/include-bash/sfpi.sh View File

@@ -226,14 +226,17 @@ sfpi__key() {
226 226
     local key=$2    # meta-data key
227 227
     local value     # ^^ value
228 228
     local fun="${SFPI__PREFIX}_${plg}__sfpimeta" # plg getter function name
229
-    if type -t "$fun" >/dev/null; then
230
-        value=$("$fun" "$key")
231
-        debug -v fun key value
232
-        test -n "$value" || value="(none)"
233
-    else
234
-        value='(undefined)'
235
-    fi
236
-    echo "$value"
229
+    (
230
+        sfpi__import "$plg"
231
+        if type -t "$fun" >/dev/null; then
232
+            value=$("$fun" "$key")
233
+            debug -v fun key value
234
+            test -n "$value" || value="(none)"
235
+        else
236
+            value='(undefined)'
237
+        fi
238
+        echo "$value"
239
+    )
237 240
 }
238 241
 
239 242
 sfpi__ls_all() {

+ 95
- 0
src/include-sh/coerce.sh View File

@@ -0,0 +1,95 @@
1
+#!/bin/sh
2
+
3
+#
4
+# Data coercion helpers
5
+#
6
+# This module provides several simple functions to help transform
7
+# data to fit certain constraints.
8
+#
9
+
10
+#
11
+# Replacement character
12
+#
13
+COERCE__REPCHAR=${COERCE__REPCHAR:-�}
14
+
15
+coerce__nocolor() {
16
+    #
17
+    # Remove ANSI color codes
18
+    #
19
+    if $__COERCE__LEGACY; then
20
+        sed 's/\x1b\[[0-9;]*m//g'
21
+    else
22
+        perl -CS -Mutf8 -MTerm::ANSIColor=colorstrip -ne 'print colorstrip $_;'
23
+    fi
24
+}
25
+
26
+coerce__noctl() {
27
+    #
28
+    # Replace non-printable characters with $COERCE__REPCHAR
29
+    #
30
+    # Keep only characters that have grapgical representation ([:graph:] POSIX
31
+    # class), newline, tab and space.  Replace rest with $COERCE__REPCHAR.
32
+    #
33
+    perl -CS -Mutf8 -pe "s|[^[:graph:] \t\n]|$COERCE__REPCHAR|g"
34
+}
35
+
36
+coerce__nofdraw() {
37
+    #
38
+    # Replace frame-drawing characters with ASCII
39
+    #
40
+    # Replace frame-drawing characters according
41
+    # to following mapping:
42
+    #
43
+    #     ┌ ┬ ┐ └ ┴ ┘ ├ ┤ │ ┼ ─
44
+    #
45
+    #     ' ' ' . . . | | | | -
46
+    #
47
+    # This converts frame-drawing to ASCII, making it
48
+    # safer when fonts on terminals are not rendering
49
+    # properly.
50
+    #
51
+    perl -CS -Mutf8 -pe "
52
+        tr{┌┬┐}{.};
53
+        tr{└┴┘}{'};
54
+        tr{├┼┤│}{|};
55
+        tr{─}{-};
56
+    "
57
+}
58
+
59
+coerce__for_yaml() {
60
+    #
61
+    # Replace yaml-invalid characters
62
+    #
63
+    # Yaml won't allow all characters:
64
+    #
65
+    # > [...] The allowed character range explicitly excludes the C0 control
66
+    # > block #x0-#x1F (except for TAB #x9, LF #xA, and CR #xD which are
67
+    # > allowed), DEL #x7F, the C1 control block #x80-#x9F (except for NEL
68
+    # > #x85 which is allowed), the surrogate block #xD800-#xDFFF, #xFFFE,
69
+    # > and #xFFFF.
70
+    #
71
+    # so take stdin and replace all unacceptable characters with '�'.
72
+    #
73
+    perl -CS -Mutf8 -pe "tr/$(__coerce__for_yaml_bad)/$COERCE__REPCHAR/"
74
+}
75
+
76
+#
77
+# Legacy mode
78
+#
79
+# If 'true', avoids using Term::ANSIColor in favor of a local hacky
80
+# sed expression yanked from stackoverflow.  Use if Term::ANSIColor
81
+# is not available (as is case of eg. RHEL-6).
82
+#
83
+__COERCE__LEGACY=${__COERCE__LEGACY:-false}
84
+
85
+__coerce__for_yaml_bad() {
86
+    #
87
+    # Print all YAML-bad chars
88
+    #
89
+    printf '\N{U+0}-\N{U+8}\N{U+B}\N{U+C}\N{U+E}-\N{U+1F}'    # C0 with some gaps
90
+    printf '\N{U+7F}'                                         # DEL alone
91
+    printf '\N{U+80}-\N{U+84}\N{U+86}-\N{U+9F}'               # C1 with NEL gap
92
+    # printf -n '\N{U+D800}-\N{U+DFFF}'                        # surrogates
93
+    # printf -n '\N{U+FFFE}-\N{U+FFFF}'                        # 0xFFFE and 0xFFFF
94
+    #FIXME: for some reasons perl complains about these ^^
95
+}

+ 1
- 0
src/include-sh/mdfmt.sh View File

@@ -78,6 +78,7 @@ _mdfmt__indent() {
78 78
     test "$Elem" == h2 && { cat; return; }
79 79
     test "$Elem" == h3 && { cat; return; }
80 80
     pfx=$(
81
+        #shellcheck disable=SC2034
81 82
         for n in $(seq 1 "$Nest"); do
82 83
             printf '    '
83 84
         done

+ 15
- 1
src/shellfu.sh.skel View File

@@ -173,6 +173,19 @@ shellfu() {
173 173
                 shellfu __die "cannot import module: $mname"
174 174
             fi
175 175
             ;;
176
+        reload)
177
+            #
178
+            # Reload module named $1 (unsafe!)
179
+            #
180
+            local mname=$1
181
+            shellfu _is_imported "$mname" || {
182
+                shellfu __warn "cannot reload; not imported yet: $mname"
183
+                return 2
184
+            }
185
+            if ! shellfu _do_import "$mname"; then
186
+                shellfu __die "cannot reload module: $mname"
187
+            fi
188
+            ;;
176 189
         try_import)
177 190
             #
178 191
             # Try if module $1 could be imported
@@ -185,6 +198,7 @@ shellfu() {
185 198
             # Show version of module named $1
186 199
             #
187 200
             local mname=$1
201
+            local mpath
188 202
             mpath=$(shellfu _select_mfile "$mname") || {
189 203
                 shellfu __warn "cannot find module: $mname"
190 204
                 return 3
@@ -230,7 +244,7 @@ shellfu() {
230 244
             # True if module $1 is already imported
231 245
             #
232 246
             local mname=$1
233
-            echo "$__SHELLFU_IMPORTED" | tr : \\n | grep -qx "$mname"
247
+            echo "$__SHELLFU_IMPORTED" | tr : \\n | grep -qxe "$mname"
234 248
             ;;
235 249
 
236 250
         _list_mfiles)

+ 229
- 0
tests/arr/TF_RUN View File

@@ -0,0 +1,229 @@
1
+#!/bin/bash
2
+#shellcheck disable=SC1090
3
+
4
+. "$TF_DIR/include/subtest.sh"
5
+. "$TF_DIR/include/tools.sh"
6
+
7
+. "$(sfpath)" || tf_exit_error "failed to init shellfu"
8
+export PRETTY=plain
9
+shellfu import arr    || tf_exit_error "failed to import arr"
10
+
11
+
12
+tf_enum_subtests() {
13
+    echo arr__fromcmd,inval
14
+    echo arr__fromcmd,c_null
15
+    echo arr__fromcmd,c_zlz
16
+    echo arr__fromcmd,c_lzl
17
+    echo arr__fromcmd,c_lz
18
+    echo arr__fromcmd,c_zl
19
+    echo arr__fromcmd,c_zz
20
+    echo arr__fromcmd,c_zzz
21
+    echo arr__fromcmd,c_l
22
+    echo arr__fromcmd,c_ll
23
+    echo arr__fromcmd,c_lll
24
+    echo arr__has,nsuch
25
+    echo arr__has,c_null
26
+    echo arr__has,w_null_yes
27
+    echo arr__has,w_null_not
28
+    echo arr__has,m_not
29
+    echo arr__has,m_mid
30
+    echo arr__has,m_a
31
+    echo arr__has,m_z
32
+    echo arr__join,nsuch
33
+    echo arr__join,d_null
34
+    echo arr__join,c_null
35
+    echo arr__join,d_mult
36
+    echo arr__join,c_zz
37
+    echo arr__join,c_lll
38
+    echo arr__join,c_z
39
+    echo arr__join,c_l
40
+}
41
+
42
+bashfix() {
43
+    local x=${BASH_VERSION%%.*}
44
+    local yz=${BASH_VERSION#$x.}
45
+    local y=${yz%%.**}
46
+    if test "$x" -eq 4 && test "$y" -lt 4; then
47
+        tr -d "'"
48
+    else
49
+        cat
50
+    fi
51
+}
52
+
53
+cmd_printing() {
54
+    local what=$1
55
+    case $1 in
56
+        c_null)   : ;;
57
+        c_z)      echo ;;
58
+        c_zz)     echo; echo ;;
59
+        c_zzz)    echo; echo; echo ;;
60
+        c_l)      echo all ;;
61
+        c_ll)     echo first; echo last ;;
62
+        c_lll)    echo first; echo mid; echo last ;;
63
+        c_zlz)    echo; echo mid; echo ;;
64
+        c_lzl)    echo first; echo; echo last ;;
65
+        c_lz)     echo left; echo  ;;
66
+        c_zl)     echo; echo right  ;;
67
+    esac
68
+}
69
+
70
+mkadecl() {
71
+    local name=$1
72
+    local shape=$2
73
+    echo -n "declare -a $name="
74
+    case $shape in
75
+        inval)    echo '()' ;;
76
+        c_null)   echo '()' ;;
77
+        c_z)      echo '([0]="")' ;;
78
+        c_zz)     echo '([0]="" [1]="")' ;;
79
+        c_zzz)    echo '([0]="" [1]="" [2]="")' ;;
80
+        c_l)      echo '([0]="all")' ;;
81
+        c_ll)     echo '([0]="first" [1]="last")' ;;
82
+        c_lll)    echo '([0]="first" [1]="mid" [2]="last")' ;;
83
+        c_zlz)    echo '([0]="" [1]="mid" [2]="")' ;;
84
+        c_lzl)    echo '([0]="first" [1]="" [2]="last")' ;;
85
+        c_lz)     echo '([0]="left" [1]="")' ;;
86
+        c_zl)     echo '([0]="" [1]="right")' ;;
87
+    esac
88
+}
89
+
90
+getprop() {
91
+    #
92
+    # Make artifact or oracle $what for $TestName
93
+    #
94
+    local what=$1
95
+    case $TestName:$what in
96
+
97
+        # arr__fromcmd
98
+
99
+        arr__fromcmd,inval:args)    echo bad=array=name; echo echo; echo hello ;;
100
+        arr__fromcmd,c_*:args)      echo cout; echo cmd_printing; echo "${TestName#*,}" ;;
101
+
102
+        arr__fromcmd,*:o_decl)      mkadecl cout "${TestName#*,}" ;;
103
+
104
+        arr__fromcmd,inval:o_es)    echo 2 ;;
105
+        arr__fromcmd,*:o_es)        echo 0 ;;
106
+
107
+        # arr__has
108
+
109
+        arr__has,w_null_yes:a_decl) mkadecl cin c_lzl ;;
110
+        arr__has,w_null_not:a_decl) mkadecl cin c_lll ;;
111
+        arr__has,c_null:a_decl)     mkadecl cin c_null ;;
112
+        arr__has,m_not:a_decl)      mkadecl cin c_lll ;;
113
+        arr__has,m_mid:a_decl)      mkadecl cin c_lll ;;
114
+        arr__has,m_a:a_decl)        mkadecl cin c_lll ;;
115
+        arr__has,m_z:a_decl)        mkadecl cin c_lll ;;
116
+
117
+        arr__has,nsuch:args)        echo foo; echo nonesuch ;;
118
+        arr__has,c_null:args)       echo foo;   echo cin ;;
119
+        arr__has,w_null*:args)      echo "";    echo cin ;;
120
+        arr__has,m_not:args)        echo bar;   echo cin ;;
121
+        arr__has,m_mid:args)        echo mid;   echo cin ;;
122
+        arr__has,m_a:args)          echo first; echo cin ;;
123
+        arr__has,m_z:args)          echo last;  echo cin ;;
124
+
125
+        arr__has,nsuch:o_es)        echo 2 ;;
126
+        arr__has,m_not:o_es)        echo 1 ;;
127
+        arr__has,c_null:o_es)       echo 1 ;;
128
+        arr__has,w_null_not:o_es)   echo 1 ;;
129
+        arr__has,*:o_es)            echo 0 ;;
130
+
131
+        # arr__join
132
+
133
+        arr__join,nsuch:a_decl)     mkadecl cin c_lll ;;
134
+        arr__join,d_null:a_decl)    mkadecl cin c_lll ;;
135
+        arr__join,d_mult:a_decl)    mkadecl cin c_lll ;;
136
+        arr__join,c_null:a_decl)    mkadecl cin c_null ;;
137
+        arr__join,c_zz:a_decl)      mkadecl cin c_zz ;;
138
+        arr__join,c_zzz:a_decl)     mkadecl cin c_zzz ;;
139
+        arr__join,c_lll:a_decl)     mkadecl cin c_lll ;;
140
+        arr__join,c_z:a_decl)       mkadecl cin c_z ;;
141
+        arr__join,c_l:a_decl)       mkadecl cin c_l ;;
142
+
143
+        arr__join,nsuch:args)       echo oxo;  echo nonesuch ;;
144
+        arr__join,d_null:args)      echo "";   echo cin ;;
145
+        arr__join,d_mult:args)      echo oxo;  echo cin ;;
146
+        arr__join,c_null:args)      echo .;    echo cin ;;
147
+        arr__join,c_zz:args)        echo .;    echo cin ;;
148
+        arr__join,c_zzz:args)       echo .;    echo cin ;;
149
+        arr__join,c_lll:args)       echo .;    echo cin ;;
150
+        arr__join,c_z:args)         echo .;    echo cin ;;
151
+        arr__join,c_l:args)         echo .;    echo cin ;;
152
+
153
+        arr__join,nsuch:o_out)      echo -n ;;
154
+        arr__join,d_null:o_out)     echo -n firstmidlast ;;
155
+        arr__join,d_mult:o_out)     echo -n firstoxomidoxolast ;;
156
+        arr__join,c_null:o_out)     echo -n '' ;;
157
+        arr__join,c_zz:o_out)       echo -n . ;;
158
+        arr__join,c_zzz:o_out)      echo -n .. ;;
159
+        arr__join,c_lll:o_out)      echo -n first.mid.last ;;
160
+        arr__join,c_z:o_out)        echo -n ;;
161
+        arr__join,c_l:o_out)        echo -n all ;;
162
+
163
+        arr__join,nsuch:o_es)       echo 2 ;;
164
+        arr__join,*:o_es)           echo 0 ;;
165
+
166
+    esac
167
+}
168
+
169
+mkresult() {
170
+    local sut
171
+    local ttype
172
+    local args=()
173
+    local cout=()
174
+    local cin=()
175
+    local r_es
176
+    ttype=${TestName##*,}
177
+    sut=${TestName%,$ttype}
178
+    type -t "$sut" >/dev/null || {
179
+        tf_exit_error "no such function: $sut"
180
+    }
181
+    readarray -t args <<<"$(getprop args)"
182
+    tf_debugv args
183
+    case $sut in
184
+        arr__fromcmd)
185
+            cout=()
186
+            "$sut" "${args[@]}"; r_es=$?
187
+            declare -p cout | bashfix
188
+            ;;
189
+        *)
190
+            eval "$(getprop a_decl)"
191
+            "$sut" "${args[@]}"; r_es=$?
192
+            ;;
193
+    esac
194
+    return "$r_es"
195
+}
196
+
197
+mkoracle() {
198
+    case $TestName in
199
+        *,nsuch)
200
+            echo 'no such array: nonesuch' >&2
201
+            ;;
202
+        arr__fromcmd,inval)
203
+            getprop o_decl
204
+            echo 'invalid array name: bad=array=name' >&2
205
+            ;;
206
+        arr__fromcmd,*)
207
+            getprop o_decl
208
+            ;;
209
+        arr__join,*)
210
+            getprop o_out
211
+            ;;
212
+    esac >"oracle/$TestName.out" 2>"oracle/$TestName.err"
213
+}
214
+
215
+tf_do_subtest() {
216
+    local TestName=$1
217
+    local o_es
218
+    mkdir -p oracle result
219
+    o_es=$(getprop o_es)
220
+    mkoracle
221
+    tf_testflt \
222
+        -n "$TestName" \
223
+        -O "oracle/$TestName.out" \
224
+        -E "oracle/$TestName.err" \
225
+        -S "$o_es" \
226
+        "mkresult"
227
+}
228
+
229
+tf_do_subtests

+ 2
- 0
tests/shellfu_api/TF_RUN View File

@@ -12,6 +12,7 @@ flt_ours() {
12 12
         -e _pretty_journald \
13 13
         -e _pretty_html \
14 14
         -e sync \
15
+        -e _pretty_forcecolor \
15 16
         -e _pretty_color \
16 17
         -e inigrep \
17 18
         -e _pretty_notify \
@@ -22,6 +23,7 @@ flt_ours() {
22 23
         -e sfdoc \
23 24
         -e sfpi \
24 25
         -e mdfmt \
26
+        -e arr \
25 27
     #FIXME: remove the filter when TFKit learns to test in sandbox
26 28
 }
27 29
 

+ 11
- 0
tests/shellfu_api/oracle/functions.stdout View File

@@ -5,6 +5,12 @@ _pretty_color:_pretty__mkhelp
5 5
 _pretty_color:_pretty__mkusage
6 6
 _pretty_color:_pretty__think
7 7
 _pretty_color:_pretty__warn
8
+_pretty_forcecolor:_pretty__debug
9
+_pretty_forcecolor:_pretty__die
10
+_pretty_forcecolor:_pretty__mkhelp
11
+_pretty_forcecolor:_pretty__mkusage
12
+_pretty_forcecolor:_pretty__think
13
+_pretty_forcecolor:_pretty__warn
8 14
 _pretty_html:_pretty__debug
9 15
 _pretty_html:_pretty__die
10 16
 _pretty_html:_pretty__mkhelp
@@ -29,6 +35,11 @@ _pretty_plain:_pretty__mkhelp
29 35
 _pretty_plain:_pretty__mkusage
30 36
 _pretty_plain:_pretty__think
31 37
 _pretty_plain:_pretty__warn
38
+arr:__arr__val_iarr
39
+arr:__arr__val_oarr
40
+arr:arr__fromcmd
41
+arr:arr__has
42
+arr:arr__join
32 43
 charmenu:charmenu
33 44
 exit:exit_error
34 45
 exit:exit_no

+ 2
- 0
tests/shellfu_api/oracle/modules.stdout View File

@@ -1,8 +1,10 @@
1 1
 _pretty_color
2
+_pretty_forcecolor
2 3
 _pretty_html
3 4
 _pretty_journald
4 5
 _pretty_notify
5 6
 _pretty_plain
7
+arr
6 8
 charmenu
7 9
 exit
8 10
 inigrep

+ 7
- 0
tests/shellfu_api/oracle/variables.stdout View File

@@ -4,6 +4,12 @@ _pretty_color:_PRETTY_COLOR_OFF
4 4
 _pretty_color:_PRETTY_COLOR_THINK
5 5
 _pretty_color:_PRETTY_COLOR_USAGE_IS
6 6
 _pretty_color:_PRETTY_COLOR_WARN
7
+_pretty_forcecolor:_PRETTY_FORCECOLOR_DEBUG
8
+_pretty_forcecolor:_PRETTY_FORCECOLOR_DIE
9
+_pretty_forcecolor:_PRETTY_FORCECOLOR_OFF
10
+_pretty_forcecolor:_PRETTY_FORCECOLOR_THINK
11
+_pretty_forcecolor:_PRETTY_FORCECOLOR_USAGE_IS
12
+_pretty_forcecolor:_PRETTY_FORCECOLOR_WARN
7 13
 charmenu:CHARMENU_FILE
8 14
 exit:EXIT_ERROR
9 15
 exit:EXIT_NO
@@ -16,6 +22,7 @@ pretty:PRETTY_DEBUG
16 22
 pretty:PRETTY_DEBUG_EXCLUDE
17 23
 pretty:PRETTY_USAGE
18 24
 pretty:PRETTY_VERBOSE
25
+sfdoc:SFDOC_HIDE_REGEX
19 26
 sfdoc:SFDOC_SHOW_HIDDEN
20 27
 sfpi:SFPI__PREFIX
21 28
 termcolors:TERMCOLORS_BLACK

+ 30
- 9
utils/mkit/include/build.sh View File

@@ -71,6 +71,7 @@ __expand_macros() {
71 71
     local line          # each line on stdin
72 72
     local mname         # each macro name
73 73
     local -A MacroMap   # macro value map
74
+    MacroMap[__MKIT_MKIT_VERSION__]=$MKIT_VERSION
74 75
     MacroMap[__MKIT_PROJ_NAME__]=$(ini 1value project:name)
75 76
     MacroMap[__MKIT_PROJ_CODENAME__]=$(ini 1value project:codename)
76 77
     MacroMap[__MKIT_PROJ_LICENSE__]=$(ini 1value project:license)
@@ -79,8 +80,8 @@ __expand_macros() {
79 80
     MacroMap[__MKIT_PROJ_MAINTAINER__]=$(ini 1value project:maintainer)
80 81
     MacroMap[__MKIT_PROJ_VCS_BROWSER__]=$(ini 1value project:vcs_browser)
81 82
     MacroMap[__MKIT_PROJ_GIT_LASTHASH__]=$(__cached git_lasthash)
83
+    MacroMap[__MKIT_PROJ_GIT_LASTSUMMARY__]=$(__cached git_lastsummary)
82 84
     MacroMap[__MKIT_PROJ_VERSION__]=$(__cached semver)
83
-    MacroMap[__MKIT_SELF_VERSION__]=$MKIT_VERSION
84 85
     for section in "$@"; do
85 86
         for mname in $(ini lskeys "$section"); do
86 87
             MacroMap[$mname]=$(ini values "$section:$mname")
@@ -161,7 +162,7 @@ __rec_built() {
161 162
     #
162 163
     local file=$1
163 164
     mkdir -p "$MKIT_LOCAL"
164
-    echo "$file" >> "$MKIT_LOCAL/built.lst"
165
+    echo "1:$file" >> "$MKIT_LOCAL/built.lst"
165 166
 }
166 167
 
167 168
 _mkit_data() {
@@ -176,6 +177,7 @@ _mkit_data() {
176 177
     sections+=( $(ini lssect | grep ':macros$') )
177 178
     {
178 179
         echo "(builtin):"
180
+        echo "  x_MKIT_MKIT_VERSION__ => '__MKIT_MKIT_VERSION__'"
179 181
         echo "  x_MKIT_PROJ_NAME__ => '__MKIT_PROJ_NAME__'"
180 182
         echo "  x_MKIT_PROJ_CODENAME__ => '__MKIT_PROJ_CODENAME__'"
181 183
         echo "  x_MKIT_PROJ_LICENSE__ => '__MKIT_PROJ_LICENSE__'"
@@ -184,8 +186,8 @@ _mkit_data() {
184 186
         echo "  x_MKIT_PROJ_MAINTAINER__ => '__MKIT_PROJ_MAINTAINER__'"
185 187
         echo "  x_MKIT_PROJ_VCS_BROWSER__ => '__MKIT_PROJ_VCS_BROWSER__'"
186 188
         echo "  x_MKIT_PROJ_GIT_LASTHASH__ => '__MKIT_PROJ_GIT_LASTHASH__'"
189
+        echo "  x_MKIT_PROJ_GIT_LASTSUMMARY__ => '__MKIT_PROJ_GIT_LASTSUMMARY__'"
187 190
         echo "  x_MKIT_PROJ_VERSION__ => '__MKIT_PROJ_VERSION__'"
188
-        echo "  x_MKIT_SELF_VERSION__ => '__MKIT_SELF_VERSION__'"
189 191
         for section in "${sections[@]}"; do
190 192
             echo "$section:"
191 193
             for macro in $(ini lskeys "$section"); do
@@ -212,12 +214,31 @@ clean() {
212 214
     #
213 215
     # Clean up tree after building
214 216
     #
215
-    test -f "$MKIT_LOCAL/built.lst" && {
216
-        <"$MKIT_LOCAL/built.lst" grep -v -e '\.\.' -e ^/ \
217
-          | xargs -r rm -rf
218
-        rm -f "$MKIT_LOCAL/built.lst"
219
-        rmdir --ignore-fail-on-non-empty "$MKIT_LOCAL"
220
-    }
217
+    local path
218
+    local line
219
+    local depth
220
+    test -f "$MKIT_LOCAL/built.lst" || return 0
221
+    {
222
+        cat "$MKIT_LOCAL/built.lst"
223
+        echo "1:$MKIT_LOCAL/built.lst"
224
+        echo "1:$MKIT_LOCAL"
225
+    } \
226
+      | grep -v -e '\.\.' -e ^/ -e '^~' \
227
+      | while IFS=: read -r depth path; do
228
+            test -e "$path" || continue
229
+            case $depth in
230
+                1)  warn "removing: $path"
231
+                    test -d "$path" \
232
+                     && rmdir -p --ignore-fail-on-non-empty "$path"
233
+                    test -f "$path" && rm "$path"
234
+                    ;;
235
+                r)  warn "removing recursively: $path"
236
+                    rm -r "$path"
237
+                    ;;
238
+                *)  warn "invalid built.lst format!"
239
+                    ;;
240
+            esac
241
+        done
221 242
     true
222 243
 }
223 244
 

+ 1
- 1
utils/mkit/include/deploy.sh View File

@@ -35,7 +35,7 @@ __deploy_item() {
35 35
         find "$src" -type f \
36 36
           | while read -r item; do
37 37
                 [[ $item =~ .skel$ ]] \
38
-                 && grep -q "${item%.skel}" "$MKIT_LOCAL/built.lst" \
38
+                 && grep -qe "${item%.skel}" "$MKIT_LOCAL/built.lst" \
39 39
                  && continue
40 40
                 __deploy_item "$item" "$dst${item#$src}" "$mode"
41 41
             done

+ 42
- 17
utils/mkit/include/facts.sh View File

@@ -103,6 +103,27 @@ git_lasthash() {
103 103
     git_bool dirty && echo -n ".dirty"
104 104
 }
105 105
 
106
+git_lastsummary() {
107
+    #
108
+    # Show last commit summary
109
+    #
110
+    # We can't do it outside git repo (or without git) but we should
111
+    # not be asked to; targets that don't require git should make use
112
+    # of cache built by dist target.
113
+    #
114
+    git_present || {
115
+        echo UNKNOWN_SUMMARY
116
+        warn "no git present; could not determine last summary"
117
+        return 3
118
+    }
119
+    git_bool dirty && {
120
+        echo "(index is dirty)"
121
+        return
122
+    }
123
+    git log -1 --format=oneline HEAD \
124
+      | cut -d' ' -f2-
125
+}
126
+
106 127
 semver() {
107 128
     #
108 129
     # Build proper SemVer version string
@@ -141,15 +162,17 @@ semver() {
141 162
     local xyz           # base version string
142 163
     local prerl         # pre-release keyword (from mkit.ini, eg. 'beta')
143 164
     local latest_tag    # latest git tag
144
-    local commit        # commit indicator (CURRENT_BRANCH.gHASH)
145
-    local dirty=F       # F if dirty, T if clean
146
-    local btime         # timestamp or nothing (see $MKIT_TTAG)
165
+    local brname        # current branch name
166
+    local ghash         # current commit short hash
167
+    local is_tagged=T   # T if tagged (clean, no metadata), F if devel
168
+    local is_dirty=F    # F if dirty, T if clean
169
+    local stamp         # timestamp or nothing (see $MKIT_TSTAMP)
147 170
     local suffix        # version suffix
148 171
     prerl=$(ini 1value project:prerl)
149
-    case $MKIT_TTAG in
150
-        none)   btime= ;;
151
-        btime)  btime=$(date -u +%Y%m%d%H%M%S) ;;
152
-        ctime)  btime=$(date -d @"$(git_fact latest_cdate)" -u +%Y%m%d%H%M%S) ;;
172
+    case $MKIT_TSTAMP in
173
+        none)   stamp= ;;
174
+        btime)  stamp=$(date -u +%Y%m%d%H%M%S) ;;
175
+        ctime)  stamp=$(date -d @"$(git_fact latest_cdate)" -u +%Y%m%d%H%M%S) ;;
153 176
     esac
154 177
     grep ":" <<<"$prerl" \
155 178
      && warn "colon in project:prerl may corrupt version data: $prerl"
@@ -168,17 +191,19 @@ semver() {
168 191
     esac
169 192
     if ! git describe --tags --exact-match HEAD >&/dev/null;
170 193
     then    # we are at a later commit than the last tag
171
-        commit="$(git_fact current_branch).g$(git_fact latest_sha)"
194
+        is_tagged=F
195
+        brname=$(git_fact current_branch | sed 's/[^[:alnum:]]/_/g')
196
+        ghash=$(git_fact latest_sha)
172 197
     fi
173
-    git_bool dirty && dirty=T
174
-    case "$dirty:$btime:$commit" in
175
-        F:*:)   suffix=""                       ;;
176
-        T::)    suffix="+dirty"                 ;;
177
-        T:*:)   suffix="+t$btime.dirty"           ;;
178
-        F::*)   suffix="+$commit"               ;;
179
-        F:*:*)  suffix="+t$btime.$commit"         ;;
180
-        T::*)   suffix="+$commit.dirty"         ;;
181
-        T:*:*)  suffix="+t$btime.$commit.dirty"   ;;
198
+    git_bool dirty && is_dirty=T
199
+    case "$is_dirty:$is_tagged:$stamp" in
200
+        F:T:*)  suffix=""                                 ;;
201
+        T:T:)   suffix="+dirty"                           ;;
202
+        T:T:*)  suffix="+t$stamp.dirty"                   ;;
203
+        F:F:)   suffix="+$brname.g$ghash"                 ;;
204
+        F:F:*)  suffix="+t$stamp.$brname.g$ghash"         ;;
205
+        T:F:)   suffix="+$brname.g$ghash.dirty"           ;;
206
+        T:F:*)  suffix="+t$stamp.$brname.g$ghash.dirty"   ;;
182 207
         *)      suffix=MKIT_BUG
183 208
                 warn "MKIT_BUG: bad dirt/commit detection" ;;
184 209
     esac

+ 53
- 15
utils/mkit/include/ini.sh View File

@@ -8,7 +8,7 @@ __ini_cat() {
8 8
     #
9 9
     local line      # each line
10 10
     while read -r line; do
11
-        printf -- "%s\n" "$line"
11
+        printf -- '%s\n' "$line"
12 12
     done
13 13
 }
14 14
 
@@ -17,19 +17,58 @@ __ini_expand() {
17 17
     # Expand reference value (prefix only)
18 18
     #
19 19
     local line      # each input line
20
-    local suffix    # tail of the line
21
-    local ref       # reference
22
-    local value     # value if reference
23 20
     while read -r line; do                  # [foo:bar]/path
24
-        suffix="${line#\[*\]}"              # /path
25
-        ref="${line%$suffix}"               # [foo:bar]
26
-        ref="${ref%\]}"                     # [foo:bar
27
-        ref="${ref#\[}"                     # foo:bar
28
-        value="$(ini 1value "$ref")"        # foo_bar_value
29
-        printf -- "%s\n" "$value$suffix"    # foo_bar_value/path
21
+        __ini_expandln "$line"
30 22
     done
31 23
 }
32 24
 
25
+__ini_expandln() {
26
+    #
27
+    # Fully expand references in line $1
28
+    #
29
+    local line_orig=$1          # original line
30
+    local line_todo=$line_orig  # current state
31
+    local line_done             # next state
32
+    local Depth=0               # current depth
33
+    local MaxDepth=10           # maximum depth
34
+    while true; do
35
+        ((Depth++))
36
+        debug_var line_todo
37
+        test "$Depth" -le "$MaxDepth" || {
38
+            warn "expansion error: reached maximum depth: $Depth > $MaxDepth"
39
+            warn "    original line: $line_orig"
40
+            warn "    expanded line: $line_todo"
41
+            return 3
42
+        }
43
+        line_done=$(__ini_expandln_once "$line_todo")
44
+        debug_var line_done
45
+        test "$line_done" == "$line_todo" && break
46
+        line_todo=$line_done
47
+    done
48
+    echo "$line_done"
49
+}
50
+
51
+__ini_expandln_once() {
52
+    #
53
+    # Run through line $1 once and replace all references
54
+    #
55
+    local line=$1   # line to expand
56
+    local ref       # full reference (incl. brackets)
57
+    local ipath     # just ini path from ^^ (stripped brackets)
58
+    local value     # value of reference
59
+    local refs=()   # all references found in line
60
+    mapfile -t refs <<<"$(grep -Eo '[[][^]]+[]]' <<< "$line_todo")"
61
+    debug_var refs
62
+    for ref in "${refs[@]}"; do
63
+        test -n "$ref" || continue
64
+        ipath=${ref#[}; ipath=${ipath%]}
65
+        value=$(ini 1value "$ipath")
66
+        debug_var line ref ipath value
67
+        line=$(sed "s|\\[$ipath\\]|$value|" <<<"$line")
68
+    done
69
+    echo "$line"
70
+}
71
+
33 72
 __ini_grepcmt() {
34 73
     #
35 74
     # Remove comments from INI file on stdin
@@ -85,7 +124,7 @@ __ini_grepsec() {
85 124
                 \[*\])    ok=false; continue ;;
86 125
             esac
87 126
             $ok || continue
88
-            printf -- "%s\n" "$line"
127
+            printf -- '%s\n' "$line"
89 128
         done \
90 129
       | sed -e 's/ *= */=/; s/ +$//; s/^//;'
91 130
 }
@@ -102,7 +141,6 @@ __ini_lssect() {
102 141
     #
103 142
     # List all section names
104 143
     #
105
-    local arg=$1    # unused argument
106 144
     grep -x '\[.*\]' | sed 's/^.//; s/.$//'
107 145
 }
108 146
 
@@ -126,10 +164,10 @@ __ini_body() {
126 164
     local inc                       # file to include
127 165
     local incre='\[INCLUDE:.*\]'    # include directive regex
128 166
     local iline                     # include directive line
129
-    if iline=$(grep -m1 -x "$incre" "$MKIT_INI"); then
167
+    if iline=$(grep -m1 -xe "$incre" "$MKIT_INI"); then
130 168
         inc=${iline#*:}; inc=${inc%]}
131
-        grep -vx "$incre" "$inc"
132
-        grep -vx "$incre" "$MKIT_INI"
169
+        grep -vxe "$incre" "$inc"
170
+        grep -vxe "$incre" "$MKIT_INI"
133 171
     else
134 172
         cat "$MKIT_INI"
135 173
     fi | __ini_grepcmt

+ 5
- 4
utils/mkit/include/release.sh View File

@@ -44,7 +44,7 @@ __relck() {
44 44
         at_relsrc)
45 45
             oracle=$(ini 1value project:relsrc)
46 46
             git_fact current_branch \
47
-              | grep -qFx "$oracle" \
47
+              | grep -qFxe "$oracle" \
48 48
              || die "you are not on release source branch: $oracle"
49 49
             ;;
50 50
         not_dirty)
@@ -70,7 +70,7 @@ __relck() {
70 70
         ini_version)
71 71
             oracle=$(git_fact latest_version | __bump_version "$rlevel")
72 72
             ini 1value project:version  \
73
-              | grep -qFx "$oracle" \
73
+              | grep -qFxe "$oracle" \
74 74
              || die "new version not in mkit.ini: $oracle"
75 75
             ;;
76 76
         *)
@@ -154,7 +154,7 @@ __vbump() {
154 154
     git add mkit.ini \
155 155
       || die "failed to add mkit.ini to the index"
156 156
     cache=$(mktemp -t "mkit._vbump_gitmsg.XXXXXXXX")
157
-    _vbump_gitmsg > "$cache"
157
+    _vbump_gitmsg "$nextver" > "$cache"
158 158
     git commit -e -F "$cache"   # note: reading from stdin will break vim
159 159
     rm "$cache"
160 160
 }
@@ -163,7 +163,8 @@ _vbump_gitmsg() {
163 163
     #
164 164
     # Compose git message template for 'Bump version' commit
165 165
     #
166
-    echo "Bump version"
166
+    local nextver=$1
167
+    echo "Bump version to $nextver"
167 168
     echo ""
168 169
     echo "Overview of changes:"
169 170
     echo ""

+ 3
- 3
utils/mkit/include/vars.sh View File

@@ -71,7 +71,7 @@ MKIT_PROJ_PKGNAME=""
71 71
 # For example, old yum version (as of RHEL-6) will not let you install
72 72
 # version that it deems older than is installed, making it hard to
73 73
 # continually upgrade during active development.  While packaging
74
-# systems have their own rukes (and SemVer says both versions should be
74
+# systems have their own rules (and SemVer says both versions should be
75 75
 # considered same) this tag will make it more likely to "win" the build
76 76
 # you made later.
77 77
 #
@@ -81,9 +81,9 @@ MKIT_PROJ_PKGNAME=""
81 81
 # Also note that 'btime' makes the version non-deterministic: merely
82 82
 # initiating the build a second later will result in different version.
83 83
 #
84
-MKIT_TTAG=${MKIT_TTAG:-ctime}
84
+MKIT_TSTAMP=${MKIT_TSTAMP:-ctime}
85 85
 
86 86
 #
87 87
 # This MKit version
88 88
 #
89
-MKIT_VERSION=0.0.35
89
+MKIT_VERSION=0.0.40

+ 3
- 3
utils/mkit/stub View File

@@ -162,7 +162,7 @@ deploy() {
162 162
             echo ''
163 163
             echo '%changelog'
164 164
             echo ''
165
-            echo '# specfile built with MKit __MKIT_SELF_VERSION__'
165
+            echo '# specfile built with MKit __MKIT_MKIT_VERSION__'
166 166
             ;;
167 167
 
168 168
         packaging/debian/copyright)
@@ -185,7 +185,7 @@ deploy() {
185 185
             echo 'Description: __MKIT_PROJ_NAME__ - __MKIT_PROJ_TAGLINE__'
186 186
             echo ' MKIT_STUB_DESCRIPTION'
187 187
             echo ''
188
-            echo '# control file built with MKit __MKIT_SELF_VERSION__'
188
+            echo '# control file built with MKit __MKIT_MKIT_VERSION__'
189 189
             ;;
190 190
 
191 191
         packaging/debian/changelog)
@@ -686,7 +686,7 @@ main() {
686 686
     esac
687 687
     updating && init_from_existing
688 688
     if test -n "$License"; then
689
-        known_licenses | grep -qxF "$License" \
689
+        known_licenses | grep -qxFe "$License" \
690 690
          || die "unknown license (use -L to get list): $License"
691 691
         MkLicense=true
692 692
     fi

+ 4
- 1
utils/tfkit/include/common.sh View File

@@ -1,3 +1,6 @@
1
+#!/bin/bash
2
+#shellcheck disable=SC2034,SC1117
3
+
1 4
 #
2 5
 # Variables to hold exit status semantic
3 6
 #
@@ -123,7 +126,7 @@ tf_think() {
123 126
     for msg in "$@";
124 127
     do
125 128
         $TF_COLOR && echo -ne "$TF_COLOR_LBLACK" >&2
126
-        echo "$pfx$msg$sfx" >&2;
129
+        echo "$msg" >&2;
127 130
         $TF_COLOR && echo -ne "$TF_COLOR_NONE" >&2
128 131
     done
129 132
 }

+ 4
- 2
utils/tfkit/include/harness.sh View File

@@ -1,7 +1,9 @@
1 1
 #!/bin/bash
2
+#shellcheck disable=SC1090
2 3
 # tfkit - Shellfu's movable test framework
3 4
 # See LICENSE file for copyright and license details.
4 5
 
6
+#shellcheck disable=SC2153
5 7
 . "$TF_DIR/include/common.sh"
6 8
 
7 9
 
@@ -104,7 +106,7 @@ tf_run_tests() {
104 106
         tmpdir=$(mktemp -d)
105 107
         stamp=$(date "+relics-$tname-%Y%m%d-%H%M%S")
106 108
         cp -r "$TF_SUITE/$tname/"* "$tmpdir"
107
-        pushd "$tmpdir" >/dev/null
109
+        pushd "$tmpdir" >/dev/null || tf_exit_panic "could not chdir to: $tmpdir"
108 110
             TF_DEBUG=$TF_DEBUG TF_VERBOSE=$TF_VERBOSE \
109 111
             TF_DIR="$tf_dir" TF_TEST="$tname" \
110 112
             TF_FILTER_SUBTEST=$TF_FILTER_SUBTEST \
@@ -112,7 +114,7 @@ tf_run_tests() {
112 114
             tes=$?
113 115
             __tf_collect_if_needed $tes
114 116
             test $tes -gt $es && es=$tes
115
-        popd >/dev/null
117
+        popd >/dev/null || tf_exit_panic "could not chdir from: $tmpdir to $OLDPWD"
116 118
         rm -rf "$tmpdir"
117 119
         if test $tes -eq 0;
118 120
         then

+ 1
- 0
utils/tfkit/include/subtest.sh View File

@@ -1,4 +1,5 @@
1 1
 #!/bin/bash
2
+#shellcheck disable=SC1090
2 3
 
3 4
 . "$TF_DIR/include/common.sh"
4 5
 

+ 19
- 18
utils/tfkit/include/tools.sh View File

@@ -1,4 +1,5 @@
1 1
 #!/bin/bash
2
+#shellcheck disable=SC1090
2 3
 
3 4
 . "$TF_DIR/include/common.sh"
4 5
 
@@ -10,10 +11,10 @@ tf_testflt() {
10 11
     # Run a simple test for a unix filter
11 12
     #
12 13
     #     tf_testflt -n foo [-i foo.stdin] \
13
-    #                [-O foo.stdout] [-E foo.stderr] [-S 3] \
14
+    #                [-O foo.out] [-E foo.err] [-S 3] \
14 15
     #                cmd arg...
15 16
     #
16
-    # Will drop *result/NAME.stdout* and *result/NAME.stderr* (intentionally
17
+    # Will drop *result/NAME.out* and *result/NAME.err* (intentionally
17 18
     # not cleaning up).
18 19
     #
19 20
 
@@ -44,10 +45,10 @@ tf_testflt() {
44 45
         -S) o_es="$2";          shift 2 || { arg_err=true; break; } ;;
45 46
         --)                     shift; break ;;
46 47
         "")                            break ;;
47
-        -*) tf_warn "wrong testcli arg: $1"; return $TF_ES_BAILOUT ;;
48
+        -*) tf_warn "wrong testcli arg: $1"; return "$TF_ES_BAILOUT" ;;
48 49
         *)                             break ;;
49 50
     esac done
50
-    $arg_err && { tf_warn "error parsing arguments: $orig_args"; return $TF_ES_BAILOUT; }
51
+    $arg_err && { tf_warn "error parsing arguments: $orig_args"; return "$TF_ES_BAILOUT"; }
51 52
     tf_debug "t_in='$t_in'"
52 53
     tf_debug "t_name='$t_name'"
53 54
     tf_debug "o_out='$o_out'"
@@ -55,22 +56,22 @@ tf_testflt() {
55 56
     tf_debug "o_es='$o_es'"
56 57
     tf_debug "test command: $*"
57 58
     test "$t_in" = "-" && t_in=/dev/stdin   # works better for check below
58
-    test -z "$t_name"  && { tf_warn "missing test name"             ; return $TF_ES_BAILOUT; }
59
-    test -z "$1"       && { tf_warn "missing test command"          ; return $TF_ES_BAILOUT; }
60
-    test -r "$t_in"    || { tf_warn "missing input file: $t_in"     ; return $TF_ES_BAILOUT; }
61
-    test -e "$o_out"   || { tf_warn "missing oracle stdout: $o_out" ; return $TF_ES_BAILOUT; }
62
-    test -e "$o_err"   || { tf_warn "missing oracle stderr: $o_err" ; return $TF_ES_BAILOUT; }
63
-    test "$o_es" -ge 0 || { tf_warn "invalid oracle status: $o_es"  ; return $TF_ES_BAILOUT; }
59
+    test -z "$t_name"  && { tf_warn "missing test name"             ; return "$TF_ES_BAILOUT"; }
60
+    test -z "$1"       && { tf_warn "missing test command"          ; return "$TF_ES_BAILOUT"; }
61
+    test -r "$t_in"    || { tf_warn "missing input file: $t_in"     ; return "$TF_ES_BAILOUT"; }
62
+    test -e "$o_out"   || { tf_warn "missing oracle stdout: $o_out" ; return "$TF_ES_BAILOUT"; }
63
+    test -e "$o_err"   || { tf_warn "missing oracle stderr: $o_err" ; return "$TF_ES_BAILOUT"; }
64
+    test "$o_es" -ge 0 || { tf_warn "invalid oracle status: $o_es"  ; return "$TF_ES_BAILOUT"; }
64 65
 
65 66
     # prepare
66 67
     #
67 68
     mkdir -p result
68
-    r_out="result/$t_name.stdout"
69
-    r_err="result/$t_name.stderr"
69
+    r_out="result/$t_name.out"
70
+    r_err="result/$t_name.err"
70 71
     tf_debug "r_out='$r_out'"
71 72
     tf_debug "r_err='$r_err'"
72
-    touch "$r_out" || { tf_warn "cannot create tmp file: $r_out" ; return $TF_ES_BAILOUT; }
73
-    touch "$r_err" || { tf_warn "cannot create tmp file: $r_err" ; return $TF_ES_PANIC; }
73
+    touch "$r_out" || { tf_warn "cannot create tmp file: $r_out" ; return "$TF_ES_BAILOUT"; }
74
+    touch "$r_err" || { tf_warn "cannot create tmp file: $r_err" ; return "$TF_ES_PANIC"; }
74 75
 
75 76
     # run
76 77
     #
@@ -79,8 +80,8 @@ tf_testflt() {
79 80
 
80 81
     # eval/report/exit
81 82
     #
82
-    test $r_es = $o_es || { tf_warn "bad exit status: $r_es (need $o_es)" ; t_es=$TF_ES_FAIL; }
83
-    $diff -u "$o_err" "$r_err" || t_es=$TF_ES_FAIL
84
-    $diff -u "$o_out" "$r_out" || t_es=$TF_ES_FAIL
85
-    return $t_es
83
+    test "$r_es" = "$o_es" || { tf_warn "bad exit status: $r_es (need $o_es)" ; t_es=$TF_ES_FAIL; }
84
+    $diff -u "$r_err" "$o_err" || t_es=$TF_ES_FAIL
85
+    $diff -u "$r_out" "$o_out" || t_es=$TF_ES_FAIL
86
+    return "$t_es"
86 87
 }

+ 4
- 3
utils/tfkit/runtests View File

@@ -1,8 +1,9 @@
1 1
 #!/bin/bash
2
+#shellcheck disable=SC1090
2 3
 # tfkit - Shellfu's movable test framework
3 4
 # See LICENSE file for copyright and license details.
4 5
 
5
-TF_VERSION="0.0.16"
6
+TF_VERSION="0.0.18"
6 7
 
7 8
 die() {
8 9
     echo "$@" && exit 9
@@ -75,8 +76,8 @@ main() {
75 76
         -c|--collect)           TF_COLLECT=always;          shift ;;
76 77
         -C|--no-collect)        TF_COLLECT=never;           shift ;;
77 78
         -d|--debug)             TF_DEBUG=true;              shift ;;
78
-        -p|--prefix)            export PATH="$(readlink -f "$2")/bin:$PATH"
79
-                                                            shift 2 || usage ;;
79
+        -p|--prefix)            PATH="$(readlink -f "$2")/bin:$PATH"
80
+                                export PATH;                shift 2 || usage ;;
80 81
         -s|--filter-subtest)    TF_FILTER_SUBTEST="$2";     shift 2 || usage ;;
81 82
         -t|--filter-test)       TF_FILTER_TEST="$2";        shift 2 || usage ;;
82 83
         -v|--verbose)           TF_VERBOSE=true;            shift ;;