code / ok / ok.sh

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