Skip to content

Instantly share code, notes, and snippets.

@oconnore
Created September 29, 2016 08:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save oconnore/7ddc34aaff280ae38a20e313f8270b92 to your computer and use it in GitHub Desktop.
Save oconnore/7ddc34aaff280ae38a20e313f8270b92 to your computer and use it in GitHub Desktop.
# ===================================================================
# Git Configuration
#
# Bundle interface:
#
# git_repo(owner, group, path, shared, remote_name, remote, force)
# git_umask(owner, group, path, shared)
# git_worktree(owner, group, path, parent, force)
# git_fetch(owner, group, path, remote)
# git_checkout(owner, group, path, remote, branch, commit)
#
# ===================================================================
bundle agent git_repo(owner, group, path, shared, remote_name, remote, force) {
# Ensure that path is a git repository with a remote named $(remote_name) matching
# $(remote) url. $(force) will delete existing files if $(path) contains anything
# other than a git repository.
vars:
"parent" string => dirname("$(path)");
"reponame" string => lastnode("$(path)", "/");
classes:
"force" expression => strcmp("$(force)", "yes");
"is_git" expression => strcmp("$(gittest[is_git])", "true");
"is_not_git" expression => strcmp("$(gittest[is_git])", "false");
"is_remote" expression =>
returnszero("cd $(path) 2>/dev/null && git remote | grep -q ^$(remote_name)$ 2>&1 >/dev/null", "useshell");
"is_url" expression =>
strcmp("$(remote)", execresult("cd $(path) && git remote get-url $(remote_name)", "useshell"));
methods:
"test"
usebundle => git_test("$(owner)", "$(path)"),
useresult => "gittest";
files:
"$(path)/."
create => "true",
perms => owner("$(owner)");
force.is_not_git::
"$(path)/."
delete => file_remove_r,
depth_search => depth_children,
file_select => select_all;
commands:
is_not_git::
"git init" contain => user_group_dir_command("$(owner)", "$(group)", "022", "$(path)");
!is_remote::
"git remote add $(remote_name) $(remote)"
contain => user_group_dir_command("$(owner)", "$(group)", "022", "$(path)");
is_remote.!is_url::
"git remote set-url $(remote_name) $(remote)"
contain => user_group_dir_command("$(owner)", "$(group)", "022", "$(path)"),
action => cached("30", "3");
}
bundle agent git_worktree(owner, group, path, parent, force) {
vars:
"cpath" string => canonify("gwktree_$(path)");
"gitcb" string =>
execresult("cd $(parent) && git branch -lq | sed -n 's/^\* \(.*\)/\1/p'", "useshell");
classes:
"force" expression => strcmp("$(force)", "true");
"is_parent_repo" expression => strcmp("$(parent[is_git])", "true");
"is_worktree" expression => strcmp("$(worktree[is_worktree])", "true");
"is_not_worktree" or => {
strcmp("$(worktree[is_git])", "false"),
strcmp("$(worktree[is_worktree])", "false")
};
methods:
"test_parent"
usebundle => git_test("$(owner)", "$(parent)"),
useresult => "parent";
"test_self"
usebundle => git_test("$(owner)", "$(path)"),
useresult => "worktree";
files:
is_parent_repo::
"$(path)/."
create => "true",
perms => og("$(owner)", "$(group)");
force.is_parent_repo.is_not_worktree::
"$(path)/."
delete => file_remove_r,
depth_search => depth_children,
file_select => select_all,
handle => "del_$(cpath)";
commands:
force.is_parent_repo.is_not_worktree::
"git worktree add -f $(path) $(gitcb)"
contain => user_group_dir("$(owner)", "$(group)", "$(parent)"),
depends_on => { "del_$(cpath)" };
!force.is_parent_repo.is_not_worktree::
"git worktree add -f $(path) $(gitcb)"
contain => user_group_dir("$(owner)", "$(group)", "$(parent)");
is_parent_repo::
"git worktree prune -v"
contain => user_group_dir("$(owner)", "$(group)", "$(parent)");
}
bundle agent git_fetch(owner, group, path, remote, branch) {
commands:
# Ensure that we have synced with the remote
"git fetch $(remote) refs/heads/$(branch):refs/remotes/$(remote)/$(branch)"
contain => user_group_dir("$(owner)", "$(group)", "$(path)");
}
bundle agent git_checkout(owner, group, path, share, remote, branch, commit) {
#
# Ensure that $(path) contains a checkout of the remote at a certain branch
#
# If $(linked_repo) is a non-empty path, git worktree is used to link $(path)
# to the git checkout at $(linked-repository). Set $(force_dup) to allow multiple
# copies of the same branch.
#
vars:
"canonical_path" string => canonify("gcheckout_$(path)");
classes:
"done" expression => "done_$(canonical_path)";
methods:
"git_umask"
usebundle => git_get_umask("$(share)"),
useresult => "umask",
handle => "umask_$(canonical_path)";
"checkout_helper"
usebundle =>
git_checkout_helper( "$(owner)", "$(group)", "$(path)",
"$(remote)", "$(branch)", "$(commit)", "$(umask[git_umask])"),
useresult => "helper",
depends_on => { "umask_$(canonical_path)" },
classes => when_kept("done_$(canonical_path)");
reports:
done::
"$(helper[start])" bundle_return_value_index => "start";
"$(helper[final])" bundle_return_value_index => "final";
"$(helper[updated])" bundle_return_value_index => "updated";
}
bundle agent git_umask(owner, group, path, shared) {
methods:
"get" usebundle => git_get_umask("$(shared)"),
useresult => "umask";
"apply" usebundle =>
git_apply_umask("$(owner)", "$(group)", "$(path)", "$(shared)", "$(umask[git_share])");
}
# ===================================================================
# Helper bundles
# ===================================================================
bundle agent git_get_umask(shared) {
vars:
"share[all]" string => "0644";
"share[group]" string => "0640";
"share[none]" string => "0600";
# Compute the umask for this user based on $(shared)
"umask" string => ifelse("share_all", "022", ifelse("share_group", "027", "077"));
"git_share" string => "$(share[$(shared)])";
classes:
# Determine the sort of sharing we're doing based on the $(shared) variable
"share_all" expression => strcmp("$(shared)", "all");
"share_group" or => { "share_all", strcmp("$(shared)", "group") };
reports:
"$(umask)" bundle_return_value_index => "git_umask";
"$(share[$(shared)])" bundle_return_value_index => "git_share";
}
bundle agent git_apply_umask(owner, group, path, shared, git_config) {
vars:
# Detect if the repository is shared
"current_share" string => execresult(
"cd $(path) 2>/dev/null && git config --local --get core.sharedRepository 2>&1", "useshell");
"workdirs" slist =>
string_split(
execresult("cd $(path) && git worktree list --porcelain | awk '/^worktree/{print $2}'",
"useshell"),
"\n", 1000);
classes:
# Determine the sort of sharing we're doing based on the $(shared) variable
"share_all" expression => strcmp("$(shared)", "all");
"share_group" or => { "share_all", strcmp("$(shared)", "group") };
"share_changed" not => strcmp("$(current_share)", "$(git_config)");
commands:
# Update the git umask when changed
share_changed::
"git config --local core.sharedRepository $(git_config)"
contain => user_group_dir_quiet("$(owner)", "$(group)", "$(path)");
files:
# Enforce umasks for old files
share_all::
"$(workdirs)/."
depth_search => depth_all,
file_select => select_all,
perms => read_all_ug("$(owner)", "$(group)");
share_group.!share_all::
"$(workdirs)/."
depth_search => depth_all,
file_select => select_all,
perms => read_group_ug("$(owner)", "$(group)");
}
bundle agent git_test(owner, path) {
#
# Test git worktree -- returns array[found] = true/false and array[parent] = <parent dir>
#
vars:
"fullpath" string => execresult("cd $(path) && pwd", "useshell");
"cpath" string => canonify("$(fullpath)");
"context" string => "echo \"^context=gitctx\"";
"git_op" string => "git worktree list --porcelain";
"awk_op" string =>
"awk '/^worktree/{if($2==\"$(fullpath)\")wtree=\"yes\";else wtree=\"no\";printf(\"=worktree[%d]=%s\n+%s_$(cpath)\n\", i++, $2, wtree);}'";
"git_res"
string => ifelse("yes_$(cpath)", "true", "false"),
depends_on => { "wtree_list_$(cpath)" };
"found_res" string => ifelse("yes_$(cpath).not_primary", "true", "false"),
depends_on => { "wtree_list_$(cpath)" };
classes:
"not_primary" not => strcmp("$(fullpath)", "$(gitctx.worktree[0])");
"done" expression => "yes_$(cpath)|no_$(cpath)";
commands:
"if git log -n1 --format=%H >/dev/null 2>&1; then echo +git; else echo -git; fi"
contain => user_dir("$(owner)", "$(path)"),
module => "true";
"$(context); $(git_op) | $(awk_op)"
contain => user_dir("$(owner)", "$(path)"),
handle => "wtree_list_$(cpath)",
module => "true";
reports:
!done::
"false" bundle_return_value_index => "is_git";
"false" bundle_return_value_index => "is_worktree";
done::
"$(git_res)" bundle_return_value_index => "is_git";
"$(found_res)" bundle_return_value_index => "is_worktree";
"$(gitctx.worktree[0])" bundle_return_value_index => "parent";
}
bundle agent git_checkout_helper(owner, group, path, remote, branch, commit, umask) {
vars:
"cpath" string => canonify("gchelper_$(path)");
"checkout" string => "git checkout --ignore-other-worktrees -fB auto/$(branch)";
"module_cmd" string =>
"git log -n1 --format=%H | awk '{printf(\"^context=git\n=commitid=%s\n\", $1)}'";
# The commit id before this bundle is enforced
"start_commit" string => execresult("cd $(path); git log -n1 --format=%H", "useshell");
"updated"
string => ifelse(strcmp("$(git.commitid)", "$(start_commit)"), "false", "true"),
depends_on => { "checkout_$(cpath)" };
classes:
"specified_commit" not => strcmp("$(commit)", "");
"done" expression => "done_$(cpath)";
commands:
any::
"git clean -xfd"
contain => user_group_dir_command_noout("$(owner)", "$(group)", "$(umask)", "$(path)");
!specified_commit::
# Clean and sync the working directory
"$(checkout) $(remote)/$(branch)"
contain => user_group_dir_command_noout("$(owner)", "$(group)", "$(umask)", "$(path)");
specified_commit::
# Clean and sync the working directory
"$(checkout) $(commit)"
contain => user_group_dir_command_noout("$(owner)", "$(group)", "$(umask)", "$(path)");
any::
"$(module_cmd)"
contain => user_group_dir_command("$(owner)", "$(group)", "$(umask)", "$(path)"),
handle => "checkout_$(cpath)",
module => "true",
classes => when_kept("done_$(cpath)");
reports:
done::
"$(start_commit)" bundle_return_value_index => "start";
"$(git.commitid)" bundle_return_value_index => "final";
"$(updated)" bundle_return_value_index => "updated";
}
# EOF
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment