githelper.git / githelper.pike

version» Context lines:

githelper.git/githelper.pike:331:            /* Hooks */      class CommitHookUtils   {    static array(string) files_to_commit;    GitAttributes attrs;    +  private string git_dir; +  +  string get_git_dir() +  { +  return git_dir || +  (git_dir = String.trim_all_whites(run_git("rev-parse", "--git-dir"))); +  } +     string get_file(string filename, int|void allow_empty);    string get_old_file(string filename, int|void allow_empty);    int entry_is_new(string filename) { return 0; }       int find_expanded_ident(string data)    {    int p=0;    while ((p = search(data, DOLLAR"Id", p))>=0) {    if (data[p..p+3] != unexpanded_id) {    int p2 = search(data, DOLLAR, p+3), p3 = search(data, "\n", p+3);
githelper.git/githelper.pike:535:    check_gitattributes_files();    }   }      /* Checks run before accepting a push */      class PreReceiveHook   {    inherit CommitHookUtilsRepo;    +  enum AccessLevel { +  ACCESS_NONE = 0, +  ACCESS_BASIC = 1, +  ACCESS_FULL = 2, // rebase/delete branch, move/delete tag, etc. +  }; +  +  static mapping(string:AccessLevel) groups = ([ +  "scratch": ACCESS_FULL, +  ]); +     static array(string) commits_to_check = ({});    -  int check_access(string ref_name, string user) +  static void parse_groups(string user)    { -  /* Return 0 for no access, 1 for basic access, and 2 for full -  access (including rebase/delete branch, and move/delete tag) */ +  string git_dir = get_git_dir(); +  +  groups[user] = ACCESS_FULL; +  +  string group_data = Stdio.read_bytes(combine_path(git_dir, "info/group")); +  +  if (!group_data) return; +  +  foreach(replace(group_data, "\r", "\n")/"\n", string line) { +  array(string) fields = map(line/":", String.trim_all_whites); +  +  // NB: We currently only care about fields 0 (group name) +  // and 3 (member list). The first member of a group is +  // considered the primary member, and has full access. +  +  if ((sizeof(fields) != 4) || (fields[0] == "")) continue; +  array(string) members = map(fields[3]/",", String.trim_all_whites); +  if (members[0] == user) { +  // Primary member. +  groups[fields[0]] = ACCESS_FULL; +  continue; +  } +  if (groups[fields[0]]) continue; // Already a member. +  if (has_value(members, user)) { +  groups[fields[0]] = ACCESS_BASIC; +  continue; +  } +  groups[fields[0]] = ACCESS_NONE; +  } +  } +  +  AccessLevel check_access(string ref_name, string user) +  { +  /* Return ACCESS_NONE (0) for no access, +  * ACCESS_BASIC (1) for basic access, and +  * ACCESS_FULL (2) for full access +  * (including rebase/delete branch, and move/delete tag) +  */    string shortref = ref_name;    sscanf(shortref, "refs/%*[^/]/%s", shortref); -  if (has_prefix(shortref, "scratch/") || has_prefix(shortref, user+"/")) -  return 2; +  foreach(groups; string group; AccessLevel ac) { +  if (has_prefix(shortref, group + "/")) +  return ac; +  }    if (search(ref_name, "/x-") >= 0) {    write("The ref %s can only be modified by its owner\n", ref_name); -  return 0; +  return ACCESS_NONE;    } -  return 1; +  return ACCESS_BASIC;    }       int check_tag_push(string old_sha, string new_sha, string ref_name, -  int access_level) +  AccessLevel access_level)    { -  if (access_level >= 2) +  if (access_level >= ACCESS_FULL)    return 0;       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 %s it\n",    ref_name, oldtag, (new_sha == "0"*40? "delete":"move"));    return 1;    }       if (!sizeof(oldtag) && search(ref_name[10..], "/") >= 0) {    write("Common tags are not allowed to contain /.\n");    return 1;    }       return 0;    }       int check_branch_push(string old_sha, string new_sha, string ref_name, -  int access_level) +  AccessLevel access_level)    {    if (old_sha == "0"*40) {    // New branch, check if the name is allowed...    if (sscanf(ref_name, "refs/heads/%*[0-9.]%*c") < 2) {    write("Main version branches can not be created remotely.\n");    return 1;    }    if (access_level < 2 && search(ref_name[11..], "/")>=0) {    write("Common topic branch names are not allowed to contain /.\n");    return 1;    }    return 0;    } else if (new_sha == "0"*40) {    // Delete old branch    if (access_level < 2) {    write("You may not delete branches which do not belong to you.\n");    return 1;    }    return 0;    } else { -  if (access_level >= 2) +  if (access_level >= ACCESS_FULL)    /* Skip checks */    return 0;       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;    }    array(string) old_depth = split_lf(run_git("rev-list", "--first-parent",
githelper.git/githelper.pike:623:    if (search(fp_path, old_sha)<0) {    write("Commit %s does not contain %s in its first-parent ancestry.\nDid you pull with merge instead of rebase?\n", new_sha, old_sha);    return 1;    }       commits_to_check += split_lf(run_git("rev-list", old_sha+".."+new_sha));    return 0;    }    }    -  int check_push(string old_sha, string new_sha, string ref_name) +  int check_push(string git_user, +  string old_sha, string new_sha, string ref_name)    { -  string git_user = getenv("GIT_USER")||getenv("USER")||"nobody"; -  int access_level; +  AccessLevel access_level;    if(!(access_level = check_access(ref_name, git_user))) return 1;    if (has_prefix(ref_name, "refs/tags/")) {    return check_tag_push(old_sha, new_sha, ref_name, access_level);    } else if (has_prefix(ref_name, "refs/heads/")) {    return check_branch_push(old_sha, new_sha, ref_name, access_level);    } else {    write("Trying to push a ref which is neither under refs/tags/ or refs/heads/...\n");    return 1;    }    }       int hook()    { -  +  string git_user = getenv("GIT_USER")||getenv("USER")||"nobody"; +  parse_groups(git_user);    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)) +  if(check_push(git_user, @args))    return 1;    }    foreach(Array.uniq(commits_to_check), string sha)    if(check_commit(sha))    return 1;    return 0;    }   }      /* Do housekeeping after a commit */