1#!/bin/sh
2
3QUIET="${OK_QUIET:-false}"
4NORUN="${OK_NORUN:-false}"
5FORCE="${OK_FORCE:-false}"
6NODIE="${OK_NODIE:-false}"
7
8OKFILE="${OK_OKFILE:-./ok}"
9FRFILE="${OK_FRFILE:-./.fr}"
10
11DOARGS=true
12
13usage() {
14 cat >&2 <<EOF
15Usage: ok [OPTION...] [TARGET...]
16Options:
17 -h Show this help and exit
18 -q Run quietly
19 -n Only print what would happen
20 -k Keep going after failure
21 -x Run with trace
22 -B Run all targets as if they were "new"
23 -f FILE
24 Use FILE as the okfile (default: $OKFILE)
25 -C DIRECTORY
26 Change to DIRECTORY before doing anything
27EOF
28}
29
30### API
31
32ok() {
33 $QUIET || echo >&2 "* $@"
34 if ! $NORUN
35 then
36 "$@"; ec="$?"
37 if ! test $ec -eq 0
38 then
39 echo >&2 "* not ok : $@"
40 $NODIE || exit $((100 + $?))
41 fi
42 fi
43}
44
45fr() (
46 exec > "$FRFILE"
47 while read -r target job deps
48 do printf '%s\tok %s\t%s\n' "$target" "$job" "$deps"
49 done
50)
51
52dep() {
53 if ! DOARGS=false go "$@"
54 then
55 echo >&2 dep not ok
56 exit $((200 + $?))
57 fi
58}
59
60all() {
61 while read -r target job deps
62 do
63 if split "$line" | buildp "$target"
64 then TARGET="$target" eval "$job" "$deps"
65 fi
66 done < "$FRFILE"
67}
68
69### Backend
70
71buildp() {
72 $FORCE && return 0
73 target="$1"; shift
74 test -e "$target" || return 0
75 while read -r dep
76 do
77 if test "$dep" -nt "$target"
78 then
79 echo >&2 "$dep newer than $target"
80 return 0
81 fi
82 done
83 return 1
84}
85
86### Entry point
87
88args() {
89 $DOARGS || return 1
90 while getopts hqnBkxf:C: OPT
91 do
92 case "$OPT" in
93 (h) usage; exit ;;
94 (q) QUIET=true ;;
95 (n) NORUN=true ;;
96 (B) FORCE=true ;;
97 (k) NODIE=true ;;
98 (x) set -x ;;
99 (f)
100 if test -f "$OPTARG"
101 then OKFILE="$OPTARG"
102 else
103 echo >&2 No okfile given.
104 exit 2
105 fi
106 ;;
107 (C) if ! cd "$OPTARG"
108 then
109 echo >&2 Directory does not exist.
110 exit 2
111 fi
112 ;;
113 (*) usage; exit 1 ;;
114 esac
115 done
116}
117
118go() {
119 args "$@" && shift $((OPTIND - 1))
120
121 case "$OKFILE" in
122 (*/*) ;;
123 (*) OKFILE="./$OKFILE" ;;
124 esac
125
126 if ! test -f "$OKFILE"
127 then
128 echo >&2 Cannot find okfile "$OKFILE"
129 exit 3
130 fi
131
132 DEFAULT="$(sed -n 's/\([a-z][a-z]*\)().*/\1/p' "$OKFILE"|sed q)"
133 test -z "$DEFAULT" && DEFAULT=all
134
135 if ! . "$OKFILE"
136 then
137 echo >&2 Cannot source okfile "$OKFILE"
138 exit 3
139 fi
140
141 if test $# -eq 0
142 then "$DEFAULT"
143 else
144 for tgt
145 do
146 if grep -q "$tgt" "$FRFILE"
147 then
148 if split "$(grep "$tgt" "$FRFILE"|cut -f3-)"| \
149 buildp "$tgt"
150 then TARGET="$tgt" eval \
151 "$(grep "$tgt" "$FRFILE"|cut -f2-)"
152 fi
153 else "$tgt"
154 fi
155 done
156 fi
157}
158
159### Utilities
160
161split() {
162 eval set -- "$*"
163 printf '%s\n' "$@"
164}
165
166### Do it
167
168go "$@" && echo ok