59cd492010-09-05Marcus Comstedt #! /usr/bin/env pike constant hooks = ([ "post-checkout" : PostCheckoutHook, ]); constant filters = ([ "nice_ident" : NiceIdentFilter, ]); 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); } 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); } /* Hooks */ class PostCheckoutHook { int hook(string ... args) { write("post-checkout %O\n", args); } } /* Filters */ class NiceIdentFilter { int clean(string ... args) { werror("clean %O\n", args); Process.system("cat"); } int smudge(string ... args) { werror("smudge %O\n", args); Process.system("cat"); } } /* Main helper */ class GitHelper { void setup_hooks() { constant hooksdir = "hooks"; if (!sizeof(hooks)) return; if (!file_stat(hooksdir)) { write("Creating the hooks directory\n"); if(!mkdir(hooksdir)) 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); } else if(s->islnk) { /* Already setup ok, it seems */ } else { write("Hook %s already exists, so won't overwrite it...", name); } } } 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; if(old == "") { 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) if(filter[op]) 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; } 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]) { } 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; } }