Browse Source

Do not always create cache

If exit status is not zero, do not create cache, but allow user to
override the default match.
Alois Mahdal 6 years ago
parent
commit
d1e64e537a
1 changed files with 48 additions and 6 deletions
  1. 48
    6
      src/cached.sh.skel

+ 48
- 6
src/cached.sh.skel View File

33
     # Usage:
33
     # Usage:
34
     #
34
     #
35
     #     CACHED__ROOT=$HOME/.cache/myapp
35
     #     CACHED__ROOT=$HOME/.cache/myapp
36
-    #     cached [-m] [-w] [-a ATTR] CMD [ARG]
36
+    #     cached [-m] [-w] [-a ATTR] [-e ES_EXPR] CMD [ARG]
37
     #
37
     #
38
     # Look up CMD with any ARGs in local cache and return result on hit.
38
     # Look up CMD with any ARGs in local cache and return result on hit.
39
-    # In case of miss, run command to create the cache first.
39
+    # In case of miss, run command and if exit status is zero (can be changed
40
+    # by -e argument; see below), create the cache and return it.
40
     #
41
     #
41
     # Cache objects are identified by computing a MD5 hash from combination
42
     # Cache objects are identified by computing a MD5 hash from combination
42
     # of several attributes.  By default, only CMD and ARGs are included;
43
     # of several attributes.  By default, only CMD and ARGs are included;
62
     # All cache objects are queried or created under directory specified by
63
     # All cache objects are queried or created under directory specified by
63
     # global variable $CACHED__ROOT, which must be specified beforehand.
64
     # global variable $CACHED__ROOT, which must be specified beforehand.
64
     #
65
     #
66
+    # Exit status has to match ES_EXPR in order to be matched.  ES_EXPR has
67
+    # form of comma-separated list of exit statuses or simple exit status
68
+    # ranges. Valid ranges are: `N` which matches exactly `N` or `M-N`,
69
+    # which matches any status from `M` to `N` inclusively.
70
+    #
71
+    # For example, following commands do or do not create cache (assuming
72
+    # no cache hit):
73
+    #
74
+    #     cached false              # no: by default ES_EXPR is only 0
75
+    #     cached -e 0,1 false       # yes: 1 matches `0,1`
76
+    #     cached -e 0-3,9 exit_4    # no: 4 does not match `0-3,9`
77
+    #     cached -e 0-3,9 exit_3    # yes: 3 matches `0-3,9`
78
+    #
65
     # NOTE: Caching of commands that process standard input is not supported.
79
     # NOTE: Caching of commands that process standard input is not supported.
66
     # (I.e. cached() will close standard input immediately.)
80
     # (I.e. cached() will close standard input immediately.)
67
     #
81
     #
73
     local ObjPath           # cache object path
87
     local ObjPath           # cache object path
74
     local MatchWD=false     # does workdir matter?
88
     local MatchWD=false     # does workdir matter?
75
     local Attr              # custom attribute
89
     local Attr              # custom attribute
90
+    local EsExpr=0          # allowed exit status
76
     while true; do case $1 in
91
     while true; do case $1 in
77
         --)     shift; break ;;
92
         --)     shift; break ;;
78
         -a)     Attr=$2; shift 2 || return 2 ;;
93
         -a)     Attr=$2; shift 2 || return 2 ;;
94
+        -e)     EsExpr=$2; shift 2 || return 2 ;;
79
         -w)     MatchWD=true; shift ;;
95
         -w)     MatchWD=true; shift ;;
80
         -m)     Miss=true; shift ;;
96
         -m)     Miss=true; shift ;;
81
         -*)     warn "bad argument: $1"; return 2 ;;
97
         -*)     warn "bad argument: $1"; return 2 ;;
161
     test -n "$Attr" && echo "Attr=$Attr"
177
     test -n "$Attr" && echo "Attr=$Attr"
162
 }
178
 }
163
 
179
 
180
+__cached__es_match() {
181
+    #
182
+    # True if exit status $1 matches expression $EsExpr
183
+    #
184
+    local es=$1
185
+    local part
186
+    for part in ${EsExpr//,/ }; do
187
+        test -n "$part" || continue
188
+        #FIXME: a rather funny implementation (works, though...)
189
+        eval "echo {${part/-/..}}" | grep -qwF "$es" && return 0
190
+    done
191
+    return 1
192
+}
193
+
164
 __cached__hit() {
194
 __cached__hit() {
165
     #
195
     #
166
     # True if $Command has cache hit
196
     # True if $Command has cache hit
194
 
224
 
195
 __cached__run() {
225
 __cached__run() {
196
     #
226
     #
197
-    # Run command, creating cache object
227
+    # Run command, creating cache object if exit status matches $EsExpr
198
     #
228
     #
199
     local es        # command exit status
229
     local es        # command exit status
200
     rm -rf "$ObjPath"
230
     rm -rf "$ObjPath"
201
     mkdir -p "$ObjPath"
231
     mkdir -p "$ObjPath"
202
     __cached__describe >"$ObjPath/desc"
232
     __cached__describe >"$ObjPath/desc"
203
     eval "$Command" \
233
     eval "$Command" \
204
-        >"$ObjPath/out"\
205
-        2>"$ObjPath/err"; es=$?
206
-    echo $es>"$ObjPath/es"
234
+        >"$ObjPath/out.tmp"\
235
+        2>"$ObjPath/err.tmp"; es=$?
236
+    echo $es>"$ObjPath/es.tmp"
237
+    if __cached__es_match $es; then
238
+        mv "$ObjPath/out.tmp" "$ObjPath/out"
239
+        mv "$ObjPath/err.tmp" "$ObjPath/err"
240
+        mv "$ObjPath/es.tmp" "$ObjPath/es"
241
+    else
242
+        warn "bad exit status; skipping cache creation: $es does not match $EsExpr"
243
+        cat "$ObjPath/out.tmp"
244
+        cat "$ObjPath/err.tmp" >&2
245
+        rm "$ObjPath/out.tmp"
246
+        rm "$ObjPath/err.tmp"
247
+        rm "$ObjPath/es.tmp"
248
+    fi
207
     return $es
249
     return $es
208
 }
250
 }
209
 
251