59cd492010-09-05Marcus Comstedt #! /usr/bin/env pike
c528962010-09-26Marcus Comstedt #define DOLLAR "$" constant unexpanded_id = DOLLAR"Id"DOLLAR;
0c9c482010-09-25Marcus Comstedt mapping(string:program) hooks = ([
5179182010-09-25Marcus Comstedt  "pre-commit" : PreCommitHook,
efde062010-09-25Marcus Comstedt  "pre-receive" : PreReceiveHook,
fa4f8f2010-09-27Marcus Comstedt  "post-commit" : PostCommitHook,
59cd492010-09-05Marcus Comstedt ]);
0c9c482010-09-25Marcus Comstedt mapping(string:program) filters = ([
7b6b1b2010-09-25Marcus Comstedt #if 0
59cd492010-09-05Marcus Comstedt  "nice_ident" : NiceIdentFilter,
7b6b1b2010-09-25Marcus Comstedt #endif
59cd492010-09-05Marcus Comstedt ]); constant filterops = ({ "clean", "smudge" }); void fail(string msg, mixed ... args) { werror(msg, @args); exit(1); } void iofailn(int errno, string msg, mixed ... args) { fail(msg+": %s\n", @args, strerror(errno)); } void iofail(string msg, mixed ... args) { iofailn(errno(), msg, @args); }
0c9c482010-09-25Marcus Comstedt array(string) split_z(string data) { array(string) a = data / "\0"; if (sizeof(a) && a[-1] == "") a = a[..sizeof(a)-2]; return a; }
bb72622010-09-26Marcus Comstedt array(string) split_lf(string data) { array(string) a = data / "\n"; if (sizeof(a) && a[-1] == "") a = a[..sizeof(a)-2]; return a; }
59cd492010-09-05Marcus Comstedt string run_git_ex(int max_exitcode, string ... args) { mapping res = Process.run(({"git"})+args); if (res->exitcode > max_exitcode) { werror(res->stderr); fail("git exited with code %d\n", res->exitcode); } return res->stdout; } string run_git(string ... args) { return run_git_ex(0, @args); }
b668f12010-09-26Marcus Comstedt string get_staged_file(string filename, int|void allow_empty)
efde062010-09-25Marcus Comstedt {
b668f12010-09-26Marcus Comstedt  string blob; string treeentry = run_git("ls-files", "--stage", "--", filename); if (allow_empty && !sizeof(treeentry)) return ""; if (2 != sscanf(treeentry, "%*o %s ", blob))
efde062010-09-25Marcus Comstedt  fail("Unable to parse output from git ls-files...\n");
b668f12010-09-26Marcus Comstedt  return run_git("cat-file", "blob", blob);
efde062010-09-25Marcus Comstedt }
59cd492010-09-05Marcus Comstedt 
aeab9a2010-09-25Marcus Comstedt string get_committed_file(string sha, string filename, int|void allow_empty)
efde062010-09-25Marcus Comstedt { string blob;
b668f12010-09-26Marcus Comstedt  string treeentry = run_git("ls-tree", sha, "--", filename); if (allow_empty && !sizeof(treeentry))
aeab9a2010-09-25Marcus Comstedt  return "";
b668f12010-09-26Marcus Comstedt  if (2 != sscanf(treeentry, "%*o blob %s\t", blob))
efde062010-09-25Marcus Comstedt  fail("Unexpected output from git ls-tree\n"); return run_git("cat-file", "blob", blob); }
5179182010-09-25Marcus Comstedt 
e6367f2010-10-02Marcus Comstedt string check_commit_timestamps(string commit) { int cct, cat, pct, pat; string parents; int sysclock = time() + 60; if(3 != sscanf(run_git("log", "-n", "1", "--format=%ct %at %P", commit), "%d %d %s\n", cct, cat, parents)) fail("Unexpected output from git log"); if (cat > sysclock) return "Author time is in the future"; if (cct > sysclock) return "Commit time is in the future"; if (cat > cct) return "Author time is later than commit time"; foreach(parents/" ", string parent) { if(2 != sscanf(run_git("log", "-n", "1", "--format=%ct %at", parent), "%d %d", pct, pat)) fail("Unexpected output from git log"); if (cct < pct) return "Commit time is before that of parent "+parent; } return 0; }
bdb9782010-10-03Marcus Comstedt int is_encoding_utf8(string name) { return (!name) || (<"utf-8", "utf8">)[lower_case(name)]; } string check_encoding(string data, string|void encoding) { if(is_encoding_utf8(encoding)) encoding = "UTF-8"; mixed err = catch { Locale.Charset.Decoder decoder = Locale.Charset.decoder(encoding);
3b6d0f2010-10-03Marcus Comstedt  foreach(Array.uniq(values(decoder->feed(data)->drain())), int c) switch(c) { case 0xfffd: return "Undefinied character detected\n"; case '\t': case '\n': case '\r': /* ? */ /* Allowed control character */ break; default: if (c<32 || (c>=0x80 && c<0xa0)) return sprintf("Forbidden control character 0x%02x detected\n", c); }
bdb9782010-10-03Marcus Comstedt  }; return err && err[0]; } string check_commit_msg(string commit) { string message = run_git("cat-file", "commit", commit); string encoding = 0; string headers = (message/"\n\n")[0]; foreach(headers/"\n", string headerline) { if(has_prefix(headerline, "encoding ")) encoding = headerline[9..]; } return check_encoding(message, encoding); }
efde062010-09-25Marcus Comstedt class GitAttributes
59cd492010-09-05Marcus Comstedt {
efde062010-09-25Marcus Comstedt  enum { ATTR_TRUE = 1, ATTR_FALSE = 2, ATTR_UNSET = 3 }; class AttrState(string attr, string|int setto) { static string _sprintf(int type) { return type=='O' && sprintf("AttrState(%O, %O)\n", attr, setto); } }; class MatchAttr(string name, int is_macro, array(AttrState) states) { static string _sprintf(int type) { return type=='O' && sprintf("MatchAttr(%O, %d, %O)\n", name, is_macro, states); } }; static array(MatchAttr) attrs = ({});
8b2c1e2010-09-27Marcus Comstedt  static mapping(string:MatchAttr) macros = ([]);
efde062010-09-25Marcus Comstedt  static int invalid_attr_name(string name)
08686f2010-09-25Marcus Comstedt  {
efde062010-09-25Marcus Comstedt  int n; if(name == "" || name[0] == '-') return 1; sscanf(name, "%*[-._0-9a-zA-Z]%n", n); return n != sizeof(name);
08686f2010-09-25Marcus Comstedt  }
efde062010-09-25Marcus Comstedt  static AttrState parse_attr(string src)
0c9c482010-09-25Marcus Comstedt  {
efde062010-09-25Marcus Comstedt  string equals = 0; string|int setto; sscanf(src, "%s=%s", src, equals); if(src[0] == '-' || src[0] == '!') { setto = (src[0]=='-'? ATTR_FALSE : ATTR_UNSET); src = src[1..]; } else setto = equals || ATTR_TRUE; if(invalid_attr_name(src)) fail("%s is not a valid attribute name\n", src); return AttrState(src, setto); }
0c9c482010-09-25Marcus Comstedt 
efde062010-09-25Marcus Comstedt  static MatchAttr parse_attr_line(string line, int macro_ok) { int is_macro=0; string name; line = String.trim_whites(replace(line, ({"\t","\r","\n"}), ({" ", " ", " "}))); if(!sizeof(line) || line[0] == '#') return 0; if(has_prefix(line, "[attr]")) { if(!macro_ok) fail("%s not allowed\n", name); is_macro=1; sscanf(line, "[attr]%*[ ]%s%*[ ]%s", name, line); } else { sscanf(line, "%s%*[ ]%s", name, line); }
19bf732010-09-26Marcus Comstedt  return MatchAttr(name, is_macro, reverse(map(line/" "-({""}), parse_attr)));
efde062010-09-25Marcus Comstedt  } static void handle_attr_line(string line, int macro_ok) { MatchAttr a = parse_attr_line(line, macro_ok); if(a) attrs += ({ a }); } static void create(string data) { foreach(data/"\n", string line) handle_attr_line(line, 1);
19bf732010-09-26Marcus Comstedt  attrs = reverse(attrs);
8b2c1e2010-09-27Marcus Comstedt  foreach(attrs, MatchAttr a) if(a->is_macro) macros[a->name] = a; attrs = filter(attrs, lambda(MatchAttr a) { return !a->is_macro; });
efde062010-09-25Marcus Comstedt  } static int path_matches(string path, string pattern) { if(search(pattern, "/")<0) return glob(pattern, (path/"/")[-1]); if(has_prefix(pattern, "/")) pattern = pattern[1..]; return glob(pattern, path); } static void macroexpand_one(string attrname, array(MatchAttr) attrs, mapping(string:string|int) all_attr) { if(all_attr[attrname] != ATTR_TRUE) return;
8b2c1e2010-09-27Marcus Comstedt  MatchAttr ma = macros[attrname];
19bf732010-09-26Marcus Comstedt  if(ma) fill_one(ma, attrs, all_attr);
efde062010-09-25Marcus Comstedt  } static void fill_one(MatchAttr attr, array(MatchAttr) attrs, mapping(string:string|int) all_attr) {
19bf732010-09-26Marcus Comstedt  foreach(attr->states, AttrState s) {
efde062010-09-25Marcus Comstedt  if(!all_attr[s->attr]) { all_attr[s->attr] = s->setto; macroexpand_one(s->attr, attrs, all_attr); }
0c9c482010-09-25Marcus Comstedt  } }
efde062010-09-25Marcus Comstedt  static void fill(string path, array(MatchAttr) attrs, mapping(string:string|int) all_attr) {
19bf732010-09-26Marcus Comstedt  foreach(attrs, MatchAttr a)
8b2c1e2010-09-27Marcus Comstedt  if(/*!a->is_macro &&*/ path_matches(path, a->name))
19bf732010-09-26Marcus Comstedt  fill_one(a, attrs, all_attr);
efde062010-09-25Marcus Comstedt  } mapping(string:string|int) checkattr(string path) { mapping(string:string|int) all_attr = ([]); fill(path, attrs, all_attr); return all_attr; }
aeab9a2010-09-25Marcus Comstedt  array(string) findattr(string attrname) { array(string) r = ({});
8b2c1e2010-09-27Marcus Comstedt  foreach(attrs+values(macros), MatchAttr attr) {
aeab9a2010-09-25Marcus Comstedt  int z=0; foreach(attr->states, AttrState state) if(state->attr == attrname && state->setto == ATTR_TRUE) { z = 1; break; } if (z) r += ({ attr->name }); } return r; }
efde062010-09-25Marcus Comstedt  static string _sprintf(int type) { return type=='O' && sprintf("GitAttributes(%O)\n", attrs); } } /* Hooks */ class CommitHookUtils {
d645802010-09-26Marcus Comstedt  static array(string) files_to_commit;
b668f12010-09-26Marcus Comstedt  GitAttributes attrs;
d645802010-09-26Marcus Comstedt 
b668f12010-09-26Marcus Comstedt  string get_file(string filename, int|void allow_empty);
2c8b302010-09-26Marcus Comstedt  string get_old_file(string filename, int|void allow_empty);
b668f12010-09-26Marcus Comstedt  int entry_is_new(string filename) { return 0; }
d645802010-09-26Marcus Comstedt 
0ef2fc2010-09-25Marcus Comstedt  int find_expanded_ident(string data)
08686f2010-09-25Marcus Comstedt  { int p=0;
c528962010-09-26Marcus Comstedt  while ((p = search(data, DOLLAR"Id", p))>=0) { if (data[p..p+3] != unexpanded_id)
0ef2fc2010-09-25Marcus Comstedt  return 1; p += 4; } return 0; }
efde062010-09-25Marcus Comstedt 
d645802010-09-26Marcus Comstedt  int check_ident(string filename)
efde062010-09-25Marcus Comstedt  {
d645802010-09-26Marcus Comstedt  if (find_expanded_ident(get_file(filename))) { write("File %s contains an expanded ident.\n", filename); if(this_program == PreCommitHook) { write("Try 'git reset %s; git add %s', " "or remove the ident manually.\n", @({filename})*2);; } return 1; } return 0;
efde062010-09-25Marcus Comstedt  }
b668f12010-09-26Marcus Comstedt  int check_blocker_attributes() { foreach(files_to_commit, string filename) { mapping(string:string|int) a = attrs->checkattr(filename); if(a->foreign_ident == GitAttributes.ATTR_TRUE) { if (!entry_is_new(filename)) { write("File %s has the foreign_ident attribute. Please remove it before commit.\n", filename); return 1; } } if(stringp(a->block_commit) || a->block_commit == GitAttributes.ATTR_TRUE) { if (!entry_is_new(filename)) { write("File %s is blocked from committing: %s\n", filename, replace((stringp(a->block_commit)? a->block_commit : "no explanation given"), "-", " ")); return 1; } } if(a->ident && a->ident != GitAttributes.ATTR_FALSE && a->ident != GitAttributes.ATTR_UNSET) { if (check_ident(filename)) return 1; } } return 0; }
2c8b302010-09-26Marcus Comstedt  int check_gitattributes_files() { foreach(files_to_commit, string filename) if(has_suffix(filename, "/.gitattributes")) { write(".gitattributes are not allowed in subdirectories\n"); return 1; } if(search(files_to_commit, ".gitattributes")>=0) { GitAttributes old_attrs = GitAttributes(get_old_file(".gitattributes", 1));
2481672010-09-26Marcus Comstedt  array(string) new_f_i = sort(attrs->findattr("foreign_ident")); array(string) old_f_i = sort(old_attrs->findattr("foreign_ident")); array(string) added_fi = new_f_i - old_f_i; array(string) removed_fi = old_f_i - new_f_i;
2c8b302010-09-26Marcus Comstedt 
2481672010-09-26Marcus Comstedt  foreach(added_fi, string path) {
2c8b302010-09-26Marcus Comstedt  if(!has_prefix(path, "/") || search(path, "*")>=0) { write("Added unsupported foreign_ident: %s\n", path); return 1; } path = path[1..]; if (!entry_is_new(path)) { write("Added foreign_ident to file %s\n", path); return 1; } }
2481672010-09-26Marcus Comstedt  foreach(removed_fi, string path) {
2c8b302010-09-26Marcus Comstedt  if(has_prefix(path, "/")) path = path[1..]; if (search(files_to_commit, path)<0) { write("Removed foreign_ident from unchanged file %s\n", path); return 1; } } } return 0; }
efde062010-09-25Marcus Comstedt } /* Checks run before editing a commit message */ class PreCommitHook { inherit CommitHookUtils;
b668f12010-09-26Marcus Comstedt  string get_file(string filename, int|void allow_empty)
d645802010-09-26Marcus Comstedt  {
b668f12010-09-26Marcus Comstedt  return get_staged_file(filename, allow_empty);
d645802010-09-26Marcus Comstedt  }
2c8b302010-09-26Marcus Comstedt  string get_old_file(string filename, int|void allow_empty) { return get_committed_file("HEAD", filename, allow_empty); }
efde062010-09-25Marcus Comstedt  int check_attributes_staged() { // We don't allow .gitattributes to differ between wt and index, // because that could mean the committed stuff ends up with different // attributes than they have right now...
12fbdc2010-10-02Marcus Comstedt  if (sizeof(run_git("diff", "--name-only", "--", ".gitattributes"))) {
efde062010-09-25Marcus Comstedt  write("You have unstaged changes to .gitattributes.\n" "Please add or stash them before commit.\n"); return 1; } }
0ef2fc2010-09-25Marcus Comstedt 
0c9c482010-09-25Marcus Comstedt  int hook() {
d645802010-09-26Marcus Comstedt  files_to_commit =
0c9c482010-09-25Marcus Comstedt  split_z(run_git("diff", "--staged", "--name-only", "-z"));
b668f12010-09-26Marcus Comstedt  attrs = GitAttributes(get_file(".gitattributes", 1));
0c9c482010-09-25Marcus Comstedt  return check_attributes_staged() ||
d645802010-09-26Marcus Comstedt  check_blocker_attributes() || check_gitattributes_files();
0c9c482010-09-25Marcus Comstedt  }
59cd492010-09-05Marcus Comstedt }
efde062010-09-25Marcus Comstedt /* Checks run before accepting a push */ class PreReceiveHook { inherit CommitHookUtils;
d645802010-09-26Marcus Comstedt  static string sha;
b668f12010-09-26Marcus Comstedt  string get_file(string filename, int|void allow_empty)
efde062010-09-25Marcus Comstedt  {
b668f12010-09-26Marcus Comstedt  return get_committed_file(sha, filename, allow_empty);
efde062010-09-25Marcus Comstedt  }
2c8b302010-09-26Marcus Comstedt  string get_old_file(string filename, int|void allow_empty)
efde062010-09-25Marcus Comstedt  {
2c8b302010-09-26Marcus Comstedt  return get_committed_file(sha+"^", filename, allow_empty);
efde062010-09-25Marcus Comstedt  }
2c8b302010-09-26Marcus Comstedt  int entry_is_new(string filename)
efde062010-09-25Marcus Comstedt  {
2c8b302010-09-26Marcus Comstedt  return (!sizeof(run_git("ls-tree", sha+"^", "--", filename))) && sizeof(run_git("ls-tree", sha, "--", filename));
efde062010-09-25Marcus Comstedt  } int check_commit(string sha) { write("Checking commit %s\n", sha);
d645802010-09-26Marcus Comstedt  this_program::sha = sha; files_to_commit =
efde062010-09-25Marcus Comstedt  split_z(run_git("diff", "--name-only", "-z", sha, sha+"^"));
b668f12010-09-26Marcus Comstedt  attrs = GitAttributes(get_file(".gitattributes", 1));
e6367f2010-10-02Marcus Comstedt  string ts_test = check_commit_timestamps(sha); if (ts_test) { write("Invalid timestamps: %s\n", ts_test); return 1; }
bdb9782010-10-03Marcus Comstedt  string cm_test = check_commit_msg(sha); if (cm_test) { write("Commit message encoding problem:\n%s", cm_test); return 1; }
b668f12010-09-26Marcus Comstedt  return check_blocker_attributes() || check_gitattributes_files();
efde062010-09-25Marcus Comstedt  }
eecd8a2010-09-27Marcus Comstedt  int check_tag_push(string old_sha, string new_sha, string ref_name)
efde062010-09-25Marcus Comstedt  {
eecd8a2010-09-27Marcus Comstedt  string oldtag = String.trim_all_whites(run_git_ex(1, "rev-parse", "--verify", "-q", ref_name)); if (sizeof(oldtag) && oldtag != new_sha) { write("Tag %s already exists with value %s, will not move it\n", ref_name, oldtag); return 1; } return 0; } int check_branch_push(string old_sha, string new_sha, string ref_name) { if (old_sha == "0"*40) { // New branch, maybe check if the name is allowed...
efde062010-09-25Marcus Comstedt  return 0; } else {
eecd8a2010-09-27Marcus Comstedt  string merge_base = String.trim_all_whites(run_git("merge-base", old_sha, new_sha)); if (merge_base != old_sha) { write("Push to %s is not fast-forward.\n", ref_name); return 1; }
bb72622010-09-26Marcus Comstedt  foreach(split_lf(run_git("rev-list", old_sha+".."+new_sha)), string sha) if(check_commit(sha))
efde062010-09-25Marcus Comstedt  return 1; return 0; } }
eecd8a2010-09-27Marcus Comstedt  int check_push(string old_sha, string new_sha, string ref_name) { if (has_prefix(ref_name, "refs/tags/")) { return check_tag_push(old_sha, new_sha, ref_name); } else if (has_prefix(ref_name, "refs/heads/")) { return check_branch_push(old_sha, new_sha, ref_name); } else { write("Trying to push a ref which is neither under refs/tags/ or refs/heads/...\n"); return 1; } }
efde062010-09-25Marcus Comstedt  int hook() {
bb72622010-09-26Marcus Comstedt  foreach(split_lf(Stdio.stdin->read()), string line) { array(string) args = line / " "; if(sizeof(args) != 3) fail("Unexpected input line to pre-receive hook: %s\n", line); if(check_push(@args)) return 1; }
efde062010-09-25Marcus Comstedt  return 0; } }
fa4f8f2010-09-27Marcus Comstedt /* Do housekeeping after a commit */ class PostCommitHook { void cleanup(string filename, mapping(string:string|int) attr) { if(attr->ident && attr->ident != GitAttributes.ATTR_FALSE && attr->ident != GitAttributes.ATTR_UNSET && search(get_committed_file("HEAD", filename, 1), unexpanded_id)>=0) if(sizeof(run_git("diff", "--name-only", "--", filename))) { write("NOTICE: The file %s has a stale ident,\n but I won't touch it since you have unstaged changes.\n", filename); } else { // write("Checking out %s, to fix stale ident...\n", filename); run_git("checkout", "HEAD", "--", filename); } } int hook() { array(string) committed_files = split_z(run_git("diff", "--name-only", "-z", "HEAD", "HEAD^")); GitAttributes attrs = GitAttributes(get_committed_file("HEAD", ".gitattributes", 1)); foreach(committed_files, string filename) cleanup(filename, attrs->checkattr(filename));
e6367f2010-10-02Marcus Comstedt  string ts_test = check_commit_timestamps("HEAD"); if (ts_test) { write("NOTICE: Your commit has invalid timestamps: %s\n", ts_test); write("Please amend it before pushing.\n"); }
bdb9782010-10-03Marcus Comstedt  string cm_test = check_commit_msg("HEAD"); if (cm_test) { write("NOTICE: Your commit message has an encoding problem:\n%s", cm_test); write("Please ament it before pushing.\n"); }
fa4f8f2010-09-27Marcus Comstedt  return 0; } }
59cd492010-09-05Marcus Comstedt /* Filters */
5179182010-09-25Marcus Comstedt /* A sample filter, not really useful... */
59cd492010-09-05Marcus Comstedt class NiceIdentFilter {
80f91d2010-09-05Marcus Comstedt  static string replace_id(string f, function(string:string) replace) { int p=0;
c528962010-09-26Marcus Comstedt  while((p=search(f, DOLLAR"Id", p)) >= 0) { int p2 = search(f, DOLLAR, p+3), p3 = search(f, "\n", p+3);
80f91d2010-09-05Marcus Comstedt  if (p2 > p && p2 < p3) { string r = replace(f[p..p2]); if (r) {
5940512010-09-05Marcus Comstedt  // werror("Replacing %O with %O\n", f[p..p2], r);
80f91d2010-09-05Marcus Comstedt  f = f[..p-1]+r+f[p2+1..]; p += sizeof(r);
5940512010-09-05Marcus Comstedt  } else { // werror("Not replacing %O\n", f[p..p2]); p = p2+1; }
80f91d2010-09-05Marcus Comstedt  } else p += 3; } return f; } static string clean_ident(string i) {
c528962010-09-26Marcus Comstedt  if(has_prefix(i, DOLLAR"Id:") && sizeof(i/" ")==13) return unexpanded_id;
80f91d2010-09-05Marcus Comstedt  } static string smudge_ident(string i) {
c528962010-09-26Marcus Comstedt  return DOLLAR"Id: some nice ident perhaps, but based on what? "DOLLAR;
80f91d2010-09-05Marcus Comstedt  } int clean()
59cd492010-09-05Marcus Comstedt  {
80f91d2010-09-05Marcus Comstedt  write(replace_id(Stdio.stdin->read(), clean_ident)); return 0;
59cd492010-09-05Marcus Comstedt  }
c1f54a2010-09-05Marcus Comstedt  int smudge()
59cd492010-09-05Marcus Comstedt  {
80f91d2010-09-05Marcus Comstedt  write(replace_id(Stdio.stdin->read(), smudge_ident)); return 0;
59cd492010-09-05Marcus Comstedt  } } /* Main helper */ class GitHelper { void setup_hooks() { constant hooksdir = "hooks"; if (!sizeof(hooks)) return; if (!file_stat(hooksdir)) { write("Creating the hooks directory\n");
52d8152010-09-05Marcus Comstedt  if (!mkdir(hooksdir))
59cd492010-09-05Marcus Comstedt  iofail("Failed to create %s", hooksdir); } foreach (hooks; string name; ) { string path = combine_path(hooksdir, name); Stdio.Stat s = file_stat(path, 1); if (!s) { write("Installing %s\n", path); System.symlink(__FILE__, path);
52d8152010-09-05Marcus Comstedt  } else if (s->islnk) {
59cd492010-09-05Marcus Comstedt  /* Already setup ok, it seems */ } else {
5179182010-09-25Marcus Comstedt  write("Hook %s already exists, so won't overwrite it...\n", name);
59cd492010-09-05Marcus Comstedt  } } } void setup_filter(string name, string op) { string confname = "filter."+name+"."+op; string old = String.trim_all_whites(run_git_ex(1, "config", "--get", confname)); string cmd = __FILE__+" filter_"+name+"_"+op;
52d8152010-09-05Marcus Comstedt  if (old == "") {
59cd492010-09-05Marcus Comstedt  write("Installing filter operation %s\n", confname); run_git("config", confname, cmd); } else if(old == cmd) { /* Already has correct value */ } else { write("Filter operation %s is already set to %s, not modifying\n", confname, old); } } void setup_filters() { foreach (filters; string name; program fprog) { object filter = fprog(); foreach (filterops; ; string op)
52d8152010-09-05Marcus Comstedt  if (filter[op])
59cd492010-09-05Marcus Comstedt  setup_filter(name, op); } } int setup(array(string) args) { if (sizeof(args)) { werror("githelper.pike should be invoked without arguments...\n"); return 1; } if (!cd(String.trim_all_whites(run_git("rev-parse", "--git-dir")))) iofail("Failed to cd to .git directory"); setup_hooks(); setup_filters(); return 0; } } string get_filter_op(string arg) { if (!has_prefix(arg, "filter_")) return 0; foreach (filterops; ; string op) if (has_suffix(arg, "_"+op)) return op;
070acd2010-09-05Marcus Comstedt  return 0;
59cd492010-09-05Marcus Comstedt } int main(int argc, array(string) argv) { string command_name = basename(argv[0]); if (hooks[command_name]) return hooks[command_name]()->hook(@argv[1..]); else if (command_name == "githelper.pike") { string fop; if (argc>1 && (fop = get_filter_op(argv[1]))) { string filter = argv[1][7..sizeof(argv[1])-(sizeof(fop)+2)]; if (filters[filter]) { object f = filters[filter](); if (!f[fop]) {
52d8152010-09-05Marcus Comstedt  werror("Filter %s does not implement %s!\n", filter, fop); return 1;
59cd492010-09-05Marcus Comstedt  } else return f[fop](@argv[2..]); } else { werror("Unknown filter %s!\n", filter); return 1; } } else return GitHelper()->setup(argv[1..]); } else { werror("Unknown invocation method %s!\n", command_name); return 1; } }