#ifndef LOON_H
#define LOON_H
#include <stdlib.h>
#include <stdbool.h>
#include <sys/types.h>
#include <time.h>
#include <string.h>
#include "lib/sha1.h"
#include "lib/listset.h"
#include "lib/iterablehash.h"
#ifdef _WIN32
char *realpath(const char *p, char *unused);
#endif
extern int num_jobs;
extern int show_output;
extern const char *root;
static inline bool is_in_root(const char *path) {
int lenpath = strlen(path);
int lenroot = strlen(root);
if (lenpath < lenroot + 1) return false;
return path[lenroot] == '/' && !memcmp(path, root, lenroot);
}
static inline bool is_facfile(const char *path) {
int len = strlen(path);
return len >= 4 && !strcmp(path+len-4, ".fac");
}
enum target_status {
unknown = 0,
being_determined,
clean,
built,
building,
failed,
marked, unready, dirty,
num_statuses };
static inline const char *pretty_status(enum target_status status) {
switch (status) {
case unknown: return "unknown";
case unready: return "unready";
case dirty: return "dirty";
case marked: return "marked";
case failed: return "failed";
case building: return "building";
case clean: return "clean";
case built: return "built";
case being_determined: return "being_determined";
case num_statuses: return "num_statuses";
}
return "ERROR-ERROR";
}
struct rule;
struct hashstat {
time_t time;
off_t size;
sha1hash hash;
};
struct target {
struct hash_entry e;
enum target_status status;
struct hashstat stat;
bool is_file, is_dir, is_symlink;
bool is_in_git, is_printed;
struct rule *rule;
int num_children, children_size;
struct rule **children;
const char path[];
};
struct rule {
struct hash_entry e;
struct rule *status_next, **status_prev;
int facfile_linenum;
enum target_status status;
int num_cache_prefixes, num_cache_suffixes;
const char **cache_suffixes_reversed;
const char **cache_prefixes;
int num_inputs, num_explicit_inputs;
int input_array_size;
struct target **inputs;
struct hashstat *input_stats;
sha1hash env;
int num_outputs, num_explicit_outputs;
struct target **outputs;
struct hashstat *output_stats;
double build_time, old_build_time;
double latency_estimate;
bool latency_handled, is_printed, is_default;
const char *working_directory;
const char *facfile_path;
const char command[];
};
struct all_targets {
struct hash_table t, r;
struct rule *lists[num_statuses];
int num_with_status[num_statuses];
double estimated_times[num_statuses];
};
struct target *create_target(struct all_targets *all, const char *path);
void free_all_targets(struct all_targets *all);
struct rule *create_rule(struct all_targets *all, const char *facfile_path,
const char *command, const char *working_directory);
struct rule *lookup_rule(struct all_targets *all, const char *command,
const char *working_directory);
void add_input(struct rule *t, struct target *inp);
void add_output(struct rule *t, struct target *out);
void add_explicit_input(struct rule *r, struct target *dep);
void add_explicit_output(struct rule *r, struct target *dep);
void add_cache_prefix(struct rule *r, const char *prefix);
void add_cache_suffix(struct rule *r, const char *suffix);
bool is_interesting_path(struct rule *r, const char *path);
void set_status(struct all_targets *all, struct rule *r, enum target_status status);
struct target *lookup_target(struct all_targets *, const char *path);
void read_fac_file(struct all_targets *all, const char *path);
char *absolute_path(const char *dir, const char *rel);
void print_fac_file(struct all_targets *all);
void fprint_facfile(FILE *f, struct all_targets *tt, const char *facfile_path);
void fprint_dot(FILE *f, struct all_targets *tt);
void fprint_makefile(FILE *f, struct all_targets *tt);
void fprint_tupfile(FILE *f, struct all_targets *tt);
void fprint_script(FILE *f, struct all_targets *tt);
void cp_inputs(const char *dir, struct all_targets *tt);
struct rule *run_rule(struct all_targets *all, struct rule *r);
void parallel_build_all(struct all_targets *all,
listset *cmd_line_args, bool facfiles_only);
void clean_all(struct all_targets *all);
char *done_name(const char *facfile);
char *go_to_git_top();
char *git_revparse(const char *flag);
void git_add(const char *path);
void add_git_files(struct all_targets *all);
void init_all(struct all_targets *all);
static inline int path_depth(const char *path) {
int len = strlen(root);
if (path[len] == '/' && !memcmp(path, root, len)) {
const char *sub = path + len + 1;
int total = 0;
for (int i=0; sub[i]; i++) {
if (sub[i] == '/') total++;
}
return total;
}
return -1;
}
static inline const char *pretty_path(const char *path) {
int len = strlen(root);
if (path[len] == '/' && !memcmp(path, root, len)) {
return path + len + 1;
}
return path;
}
static inline const char *pretty_rule(struct rule *r) {
if (!r) return "<nil rule>";
if (r->num_outputs && strlen(pretty_path(r->outputs[0]->path)) <= strlen(r->command)) {
return pretty_path(r->outputs[0]->path);
}
return r->command;
}
static inline const char *easy_rule(struct rule *r) {
if (!r) return "<nil rule>";
if (r->num_explicit_outputs && strlen(pretty_path(r->outputs[0]->path)) <= strlen(r->command)) {
return pretty_path(r->outputs[0]->path);
}
return r->command;
}
static inline const char *pretty_reason(struct rule *r) {
if (r->is_default) return pretty_rule(r);
for (int i=0;i<r->num_outputs;i++) {
for (int j=0;j<r->outputs[i]->num_children;j++) {
if (r->outputs[i]->children[j]->status == unready ||
r->outputs[i]->children[j]->status == failed) {
return pretty_path(r->outputs[i]->path);
}
}
}
return pretty_rule(r); }
int rm_recursive(const char *dir);
void cp_to_dir(const char *fname, const char *dir);
int run_fac(int argc, const char **argv);
#endif