Fix formatting
[tmk.git] / tm_update.c
blobb75969ef2ffbe17d8b96a3bb5f43525e303300fd
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
5 #include <sqlite3.h>
7 #define JIM_EMBEDDED
8 #include <jim.h>
10 #include "tmake.h"
11 #include "tm_target.h"
12 #include "tm_crypto.h"
13 #include "tm_update.h"
16 /* A list of targets that were updated during the current run */
17 target_list *updated_targets = NULL;
20 /* Returns true if a file exists and is readable.
22 int file_exists(const char *filename)
24 FILE *fp;
26 if ((fp = fopen(filename, "r"))) {
27 fclose(fp);
28 return 1;
31 return 0;
35 /* Used takes a Jim interpreter and a Jim error code.
36 * If there was an error, display an error message and exit.
37 * Otherwise, do nothing.
39 void wrap(Jim_Interp *interp, int error)
41 if (error == JIM_ERR) {
42 Jim_MakeErrorMessage(interp);
43 fprintf(stderr, "%s\n", Jim_String(Jim_GetResult(interp)));
44 Jim_FreeInterp(interp);
45 exit(EXIT_FAILURE);
50 /* Update a target using the associated rule from tm_rules.
51 * Takes a SQLite database handle representing the sha1sum cache
52 * and the name of the TMakefile being evaluated, along with
53 * the name of the target to update.
55 int update(sqlite3 *db, const char *tmfile, const char *target)
57 unsigned char digest[CRYPTO_HASH_SIZE];
58 char newhash[CRYPTO_HASH_STRING_LENGTH];
59 tm_rule *rule = NULL;
60 const char *fmt = "INSERT OR REPLACE INTO TMCache (TMakefile, Target, Hash) VALUES (?, ?, ?)";
61 sqlite3_stmt *stm = NULL;
62 const char *stmtail;
63 int sqlrc;
65 rule = find_rule(target, tm_rules);
67 if (!rule) {
68 return (JIM_ERR);
71 updated_targets = target_cons(rule->target, updated_targets);
73 if (rule->type == TM_EXPLICIT) {
74 TM_CRYPTO_HASH_DATA(rule->recipe, digest);
75 } else if (rule->type == TM_FILENAME) {
76 TM_CRYPTO_HASH_FILE(target, digest);
77 } else {
78 fprintf(stderr, "WARNING: Unknown rule type %d\n"
79 " Don't know how to update cache for %s\n", rule->type, target);
80 return (JIM_ERR);
83 TM_CRYPTO_HASH_TO_STRING(digest, newhash);
85 sqlrc = sqlite3_prepare(db, fmt, -1, &stm, &stmtail);
86 if (sqlrc != SQLITE_OK) {
87 fprintf(stderr, "WARNING: Unable to update cache for target %s\n", target);
88 return (JIM_ERR);
91 sqlite3_bind_text(stm, 1, tmfile, -1, SQLITE_TRANSIENT);
92 sqlite3_bind_text(stm, 2, target, -1, SQLITE_TRANSIENT);
93 sqlite3_bind_text(stm, 3, newhash, -1, SQLITE_TRANSIENT);
94 sqlrc = sqlite3_step(stm);
95 if (sqlrc != SQLITE_DONE) {
96 fprintf(stderr, "WARNING: Error updating cache for target %s\n", target);
97 sqlite3_finalize(stm);
98 return (JIM_ERR);
100 sqlite3_finalize(stm);
102 Adding this return to squelch compilation warning.
103 Cory should review this code
105 return (JIM_OK);
109 /* Return 1 if target was updated, else return 0.
111 int was_updated(const char *target)
113 return target_exists(target, updated_targets);
117 /* Return 1 if a given target is out of date, else return 0.
118 * Takes a SQLite database handle and the name of the TMakefile
119 * being evaluated along with the name of the target.
121 int needs_update(sqlite3 *db, const char *tmfile, const char *target)
123 unsigned char digest[CRYPTO_HASH_SIZE];
124 const char *oldhash = NULL;
125 char newhash[CRYPTO_HASH_STRING_LENGTH];
126 target_list *deps = NULL;
127 tm_rule *rule = NULL;
128 const char *fmt = "SELECT Hash FROM TMCache WHERE TMakefile = ? AND Target = ?";
129 const char *stmtail = NULL;
130 sqlite3_stmt *stm = NULL;
131 int sqlrc;
133 rule = find_rule(target, tm_rules);
135 if (!rule) {
136 goto yes;
139 if (rule->always_oodate) {
140 goto yes;
143 for (deps = rule->deps; deps; deps = deps->next) {
144 if (was_updated(deps->name)) {
145 goto yes;
149 sqlrc = sqlite3_prepare(db, fmt, -1, &stm, &stmtail);
150 if (sqlrc != SQLITE_OK) {
151 fprintf(stderr, "WARNING: Unable to prepare database statement.\n"
152 " Assuming %s needs update.\n", target);
153 return 1;
156 sqlite3_bind_text(stm, 1, tmfile, -1, SQLITE_TRANSIENT);
157 sqlite3_bind_text(stm, 2, target, -1, SQLITE_TRANSIENT);
158 sqlrc = sqlite3_step(stm);
159 if (sqlrc != SQLITE_ROW) {
160 /* There was no row in the cache for this target, so update it */
161 goto yes;
164 oldhash = (const char *)sqlite3_column_text(stm, 0);
165 if (!oldhash) {
166 fprintf(stderr, "WARNING: Error getting cache for target %s\n", target);
167 goto yes;
170 if (rule->type == TM_EXPLICIT) {
171 TM_CRYPTO_HASH_DATA(rule->recipe, digest);
172 } else if (rule->type == TM_FILENAME) {
173 TM_CRYPTO_HASH_FILE(target, digest);
174 } else {
175 fprintf(stderr, "WARNING: Unexpected rule type %d\n"
176 " Assuming %s needs update.\n", rule->type, target);
177 goto yes;
179 TM_CRYPTO_HASH_TO_STRING(digest, newhash);
181 if (strcmp(oldhash, newhash) == 0) {
182 goto no;
183 } else {
184 goto yes;
188 sqlite3_finalize(stm);
189 return 0;
190 yes:
191 sqlite3_finalize(stm);
192 return 1;
195 /* Take a list of targets to check and return a sublist containing only
196 * the targets that are out of date.
197 * Takes a SQLite database handle and the name of the TMakefile being
198 * evaluated along with the list of targets.
200 target_list *need_update(sqlite3 *db, const char *tmfile, target_list *targets)
202 target_list *oodate = NULL;
204 for (; targets; targets = targets->next) {
205 if (needs_update(db, tmfile, targets->name)) {
206 oodate = target_cons(targets->name, oodate);
210 return oodate;
214 /* Update all the rules in sorted_rules that need updating.
215 * Takes a SQLite database handle, a Jim interpreter containing
216 * the recipe definitions, the name of the TMakefile that was
217 * evaluated in the interpreter, the rules to be updated if needed
218 * (in the order they are to be updated), whether or not to force
219 * updates regardless of out-of-date status, and whether or not
220 * we're running in silent mode.
222 void update_rules(sqlite3 *db, Jim_Interp *interp,
223 const char *tmfile,
224 tm_rule_list *sorted_rules,
225 int force,
226 int silence)
228 if (!sorted_rules) {
229 /* nothing to do */
230 return;
233 for (; sorted_rules; sorted_rules = sorted_rules->next) {
234 tm_rule *rule = sorted_rules->rule;
235 if (rule->type == TM_EXPLICIT) {
236 /* If the rule has a recipe and needs an update */
237 if (rule->recipe
238 && (force || needs_update(db, tmfile, rule->target))) {
239 /* Execute the recipe for the current rule */
240 const char *fmt = "recipe::%s {%s} {%s} {%s}";
241 int len = 0;
242 char *cmd = NULL;
243 const char *target = rule->target;
244 char *inputs = target_list_to_string(rule->deps);
245 target_list *oodate_deps = need_update(db, tmfile, rule->deps);
246 char *oodate = target_list_to_string(oodate_deps);
247 tm_rule_list *oodate_rules = find_rules(oodate_deps, tm_rules);
249 if (was_updated(target)) {
250 goto done;
253 update_rules(db, interp, tmfile, oodate_rules, force, silence);
255 if (!silence)
256 printf("Making target %s:\n", rule->target);
258 len = strlen(fmt) + strlen(target)*2 + strlen(inputs) + strlen(oodate) + 1;
259 cmd = malloc(len);
260 sprintf(cmd, fmt, target, target, inputs, oodate);
261 wrap(interp, Jim_Eval(interp, cmd));
263 update(db, tmfile, rule->target);
264 if (!silence)
265 printf("\n");
267 done:
268 free(cmd);
269 free(oodate);
270 free(inputs);
271 free_rule_list(oodate_rules);
272 free_target_list(oodate_deps);
274 rule->type = TM_UPDATED;
276 } else if (rule->type == TM_FILENAME) {
277 /* Check that the file actually exists */
278 if (!file_exists(rule->target)) {
279 fprintf(stderr, "ERROR: Unable to find rule for target %s\n", rule->target);
280 exit(EXIT_FAILURE);
282 if (force || needs_update(db, tmfile, rule->target)) {
283 update(db, tmfile, rule->target);
284 rule->type = TM_UPDATED;