| 
				
			 | 
			
			
				@@ -33,10 +33,11 @@ cached() { 
			 | 
		
	
		
			
			| 
				33
			 | 
			
				33
			 | 
			
			
				     # Usage: 
			 | 
		
	
		
			
			| 
				34
			 | 
			
				34
			 | 
			
			
				     # 
			 | 
		
	
		
			
			| 
				35
			 | 
			
				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
			 | 
			
				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
			 | 
			
				42
			 | 
			
			
				     # Cache objects are identified by computing a MD5 hash from combination 
			 | 
		
	
		
			
			| 
				42
			 | 
			
				43
			 | 
			
			
				     # of several attributes.  By default, only CMD and ARGs are included; 
			 | 
		
	
	
		
			
			| 
				
			 | 
			
			
				@@ -62,6 +63,19 @@ cached() { 
			 | 
		
	
		
			
			| 
				62
			 | 
			
				63
			 | 
			
			
				     # All cache objects are queried or created under directory specified by 
			 | 
		
	
		
			
			| 
				63
			 | 
			
				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
			 | 
			
				79
			 | 
			
			
				     # NOTE: Caching of commands that process standard input is not supported. 
			 | 
		
	
		
			
			| 
				66
			 | 
			
				80
			 | 
			
			
				     # (I.e. cached() will close standard input immediately.) 
			 | 
		
	
		
			
			| 
				67
			 | 
			
				81
			 | 
			
			
				     # 
			 | 
		
	
	
		
			
			| 
				
			 | 
			
			
				@@ -73,9 +87,11 @@ cached() { 
			 | 
		
	
		
			
			| 
				73
			 | 
			
				87
			 | 
			
			
				     local ObjPath           # cache object path 
			 | 
		
	
		
			
			| 
				74
			 | 
			
				88
			 | 
			
			
				     local MatchWD=false     # does workdir matter? 
			 | 
		
	
		
			
			| 
				75
			 | 
			
				89
			 | 
			
			
				     local Attr              # custom attribute 
			 | 
		
	
		
			
			| 
				
			 | 
			
				90
			 | 
			
			
				+    local EsExpr=0          # allowed exit status 
			 | 
		
	
		
			
			| 
				76
			 | 
			
				91
			 | 
			
			
				     while true; do case $1 in 
			 | 
		
	
		
			
			| 
				77
			 | 
			
				92
			 | 
			
			
				         --)     shift; break ;; 
			 | 
		
	
		
			
			| 
				78
			 | 
			
				93
			 | 
			
			
				         -a)     Attr=$2; shift 2 || return 2 ;; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				94
			 | 
			
			
				+        -e)     EsExpr=$2; shift 2 || return 2 ;; 
			 | 
		
	
		
			
			| 
				79
			 | 
			
				95
			 | 
			
			
				         -w)     MatchWD=true; shift ;; 
			 | 
		
	
		
			
			| 
				80
			 | 
			
				96
			 | 
			
			
				         -m)     Miss=true; shift ;; 
			 | 
		
	
		
			
			| 
				81
			 | 
			
				97
			 | 
			
			
				         -*)     warn "bad argument: $1"; return 2 ;; 
			 | 
		
	
	
		
			
			| 
				
			 | 
			
			
				@@ -161,6 +177,20 @@ __cached__describe() { 
			 | 
		
	
		
			
			| 
				161
			 | 
			
				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
			 | 
			
				194
			 | 
			
			
				 __cached__hit() { 
			 | 
		
	
		
			
			| 
				165
			 | 
			
				195
			 | 
			
			
				     # 
			 | 
		
	
		
			
			| 
				166
			 | 
			
				196
			 | 
			
			
				     # True if $Command has cache hit 
			 | 
		
	
	
		
			
			| 
				
			 | 
			
			
				@@ -194,16 +224,28 @@ __cached__pull() { 
			 | 
		
	
		
			
			| 
				194
			 | 
			
				224
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				195
			 | 
			
				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
			 | 
			
				229
			 | 
			
			
				     local es        # command exit status 
			 | 
		
	
		
			
			| 
				200
			 | 
			
				230
			 | 
			
			
				     rm -rf "$ObjPath" 
			 | 
		
	
		
			
			| 
				201
			 | 
			
				231
			 | 
			
			
				     mkdir -p "$ObjPath" 
			 | 
		
	
		
			
			| 
				202
			 | 
			
				232
			 | 
			
			
				     __cached__describe >"$ObjPath/desc" 
			 | 
		
	
		
			
			| 
				203
			 | 
			
				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
			 | 
			
				249
			 | 
			
			
				     return $es 
			 | 
		
	
		
			
			| 
				208
			 | 
			
				250
			 | 
			
			
				 } 
			 | 
		
	
		
			
			| 
				209
			 | 
			
				251
			 | 
			
			
				  
			 |