aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTharre <tharre3@gmail.com>2014-11-16 17:30:35 +0100
committerTharre <tharre3@gmail.com>2014-11-16 17:30:35 +0100
commitb4c1b2145d6a0b1ec4219847dc26877046f84e8b (patch)
tree6bb3bc8b35afc7a76bf53d93227b07e91501b807
parent19cba89127381d9dc06d1e823b123231496e9a3d (diff)
downloadredo-b4c1b2145d6a0b1ec4219847dc26877046f84e8b.tar.gz
redo-b4c1b2145d6a0b1ec4219847dc26877046f84e8b.tar.xz
redo-b4c1b2145d6a0b1ec4219847dc26877046f84e8b.zip
Change the way redo updates targets.
It's done a lot more efficiently now, as we are no longer checking if a target is out-of-date before we rebuild it, but instead rebuild subtargets directly when they are checked. We also now correctly depend on .do files.
-rw-r--r--src/build.c116
-rw-r--r--src/build.h2
-rw-r--r--src/redo-always.c2
-rw-r--r--src/redo-ifchange.c12
-rw-r--r--src/redo-ifcreate.c3
-rw-r--r--src/redo.c4
6 files changed, 81 insertions, 58 deletions
diff --git a/src/build.c b/src/build.c
index 8b0ed94..c002cc8 100644
--- a/src/build.c
+++ b/src/build.c
@@ -36,7 +36,6 @@ static char **parsecmd(char *cmd, size_t *i, size_t keep_free);
static char *get_relpath(const char *target);
static char *get_dep_path(const char *target);
static void write_dep_hash(const char *target);
-static bool dependencies_changed(char buf[], size_t read);
struct do_attr {
char *specific;
@@ -139,8 +138,13 @@ int build_target(const char *target) {
}
/* depend on the do-file */
+ char *temp = get_dep_path(dofiles->chosen);
+ if (!fexists(temp)) {
+ write_dep_hash(dofiles->chosen);
+ }
+ free(temp);
+
add_dep(dofiles->chosen, target, 'c');
- write_dep_hash(dofiles->chosen);
/* redo-ifcreate on specific if general was chosen */
if (dofiles->general == dofiles->chosen)
@@ -203,8 +207,16 @@ static struct do_attr *get_dofiles(const char *target) {
struct do_attr *dofiles = safe_malloc(sizeof(struct do_attr));
dofiles->specific = concat(2, target, ".do");
- dofiles->general = concat(3, "default", take_extension(target), ".do");
- dofiles->redofile = safe_strdup("Redofile");
+ if (!is_absolute(target)) {
+ dofiles->general = concat(3, "default", take_extension(target), ".do");
+ dofiles->redofile = safe_strdup("Redofile");
+ } else {
+ char *dirc = safe_strdup(target);
+ char *dt = dirname(dirc);
+
+ dofiles->general = concat(4, dt, "/default", take_extension(target), ".do");
+ dofiles->redofile = concat(2, dt, "/Redofile");
+ }
if (fexists(dofiles->specific))
dofiles->chosen = dofiles->specific;
@@ -392,40 +404,27 @@ static void write_dep_hash(const char *target) {
free(dep_path);
}
-/* Parse the dependency information from the dependency record and check if
- those are up-to-date. */
-static bool dependencies_changed(char buf[], size_t read) {
- char *root = getenv("REDO_ROOT");
- char *ptr = buf;
-
- for (size_t i = 0; i < read; ++i) {
- if (buf[i])
- continue;
- if (is_absolute(&ptr[1])) {
- if (has_changed(&ptr[1], ptr[0], true))
- return true;
- } else {
- char *abs = concat(3, root, "/", &ptr[1]);
- if (has_changed(abs, ptr[0], true)) {
- free(abs);
- return true;
- }
- free(abs);
- }
- ptr = &buf[i+1];
- }
- return false;
-}
-
-/* Checks if a target should be rebuild, given it's identifier. */
-bool has_changed(const char *target, int ident, bool is_sub_dependency) {
+int update_target(const char *target, int ident) {
switch(ident) {
- case 'a': return true;
- case 'e': return fexists(target);
+ case 'a':
+ debug("%s is not up-to-date: always rebuild\n", target);
+ build_target(target);
+ return 1;
+ case 'e':
+ if (fexists(target)) {
+ debug("%s is not up-to-date: target exist and e ident was chosen\n", target);
+ build_target(target);
+ return 1;
+ }
+ return 0;
case 'c':
#define HEADERSIZE HASHSIZE + sizeof(unsigned)
- if (!fexists(target))
- return true;
+ if (!fexists(target)) {
+ /* target does not exist */
+ debug("%s is not up-to-date: target doesn't exist\n", target);
+ build_target(target);
+ return 1;
+ }
char *dep_path = get_dep_path(target);
@@ -433,7 +432,10 @@ bool has_changed(const char *target, int ident, bool is_sub_dependency) {
if (!fp) {
if (errno == ENOENT) {
/* dependency file does not exist */
- return true;
+ debug("%s is not up-to-date: dependency file (%s) doesn't exist\n",
+ target, dep_path);
+ build_target(target);
+ return 1;
} else {
fatal(ERRM_FOPEN, dep_path);
}
@@ -446,29 +448,57 @@ bool has_changed(const char *target, int ident, bool is_sub_dependency) {
free(dep_path);
if (*(unsigned *) buf == (unsigned) atoi(getenv("REDO_MAGIC")))
- return is_sub_dependency;
+ /* magic number matches */
+ return 1;
+ char *root = getenv("REDO_ROOT");
+ bool rebuild = false;
unsigned char hash[HASHSIZE];
hash_file(target, hash);
if (memcmp(hash, buf+sizeof(unsigned), HASHSIZE)) {
- /*debug("Hash doesn't match for %s\n", target);*/
- return true;
+ debug("%s is not-up-to-date: hashes don't match\n", target);
+ build_target(target);
+ return 1;
}
+ /* FIXME: this doesn't work properly if we actually read beyond 8096 bytes */
while (!feof(fp)) {
size_t read = fread(buf, 1, sizeof buf, fp);
if (ferror(fp))
fatal("redo: failed to read %zu bytes from file descriptor", sizeof buf);
- if (dependencies_changed(buf, read)) {
- fclose(fp);
- return true;
+ char *ptr = buf;
+ for (size_t i = 0; i < read; ++i) {
+ if (buf[i])
+ continue;
+ if (!is_absolute(&ptr[1])) {
+ /* if our path is relative we need to prefix it with the
+ root project directory or the path will be invalid */
+ char *abs = concat(3, root, "/", &ptr[1]);
+ if (update_target(abs, ptr[0])) {
+ debug("%s is not up-to-date: subdependency %s is out-of-date\n",
+ target, abs);
+ rebuild = true;
+ }
+ free(abs);
+ } else {
+ if (update_target(&ptr[1], ptr[0])) {
+ debug("%s is not up-to-date: subdependency %s is out-of-date\n",
+ target, &ptr[1]);
+ rebuild = true;
+ }
+ }
+ ptr = &buf[i+1];
}
}
fclose(fp);
- return false;
+ if (rebuild) {
+ build_target(target);
+ return 1;
+ }
+ return 0;
default:
log_err("Unknown identifier '%c'\n", ident);
diff --git a/src/build.h b/src/build.h
index 8a5f072..e4ef626 100644
--- a/src/build.h
+++ b/src/build.h
@@ -12,7 +12,7 @@
#include <stdbool.h>
extern void add_dep(const char *target, const char *parent, int ident);
-extern bool has_changed(const char *target, int ident, bool is_sub_dependency);
+extern int update_target(const char *target, int ident);
extern int build_target(const char *target);
extern bool environment_sane();
diff --git a/src/redo-always.c b/src/redo-always.c
index 5f0c24c..0e1d849 100644
--- a/src/redo-always.c
+++ b/src/redo-always.c
@@ -12,7 +12,7 @@
int main(int argc, char *argv[]) {
for (int i = 1; i < argc; ++i) {
- build_target(argv[i]);
+ update_target(argv[i], 'a');
add_dep(argv[i], NULL, 'a');
}
}
diff --git a/src/redo-ifchange.c b/src/redo-ifchange.c
index cfc017b..d7b4af0 100644
--- a/src/redo-ifchange.c
+++ b/src/redo-ifchange.c
@@ -14,19 +14,13 @@
int main(int argc, char *argv[]) {
if (!environment_sane()) {
- fprintf(stderr, "redo: environment variables are missing, \
- please use %s only in do scripts.\n", argv[0]);
+ fprintf(stderr, "redo: environment variables are missing, "
+ "please use %s only in do scripts.\n", argv[0]);
exit(1);
}
for (int i = 1; i < argc; ++i) {
- /*debug("Testing if %s is up-to-date ...\n", argv[i]);*/
- if (has_changed(argv[i], 'c', false)) {
- /*printf("=> no\n");*/
- build_target(argv[i]);
- } else {
- /*printf("=> yes\n");*/
- }
+ update_target(argv[i], 'c');
add_dep(argv[i], NULL, 'c');
}
diff --git a/src/redo-ifcreate.c b/src/redo-ifcreate.c
index eba1c6b..77e51cc 100644
--- a/src/redo-ifcreate.c
+++ b/src/redo-ifcreate.c
@@ -12,8 +12,7 @@
int main(int argc, char *argv[]) {
for (int i = 1; i < argc; ++i) {
- if (has_changed(argv[i], 'e', false))
- build_target(argv[i]);
+ update_target(argv[i], 'e');
add_dep(argv[i], NULL, 'e');
}
}
diff --git a/src/redo.c b/src/redo.c
index 1458391..53b5e43 100644
--- a/src/redo.c
+++ b/src/redo.c
@@ -51,11 +51,11 @@ int main(int argc, char *argv[]) {
prepare_env();
if (argc < 2) {
- build_target("all");
+ update_target("all", 'a');
} else {
int i;
for (i = 1; i < argc; ++i) {
- build_target(argv[i]);
+ update_target(argv[i], 'a');
}
}
}