# # # patch "branch_name.cc" # from [3b62e04943bf835f0c47598a74c96092b9408821] # to [102b08ed30c0e69735391c6501ffccff43a66b06] # # patch "branch_name.hh" # from [670bf5103f0b79f79248d7323f4f90ca3cc7a871] # to [d961df061b8adac57a98a79af032a2d765bbb62b] # # patch "cmd_policy.cc" # from [1d01be7fa8231ac740ea25b6ca336309611a1ace] # to [6bcb61826311a778e7e4c04b263dc1912886c128] # # patch "policies/policy_branch.cc" # from [bc1af8d06fbee650c2b4c85372ab737499e0f2be] # to [b45efecab6f09651795ac4ef26f4c81e8022acbc] # # patch "project.cc" # from [f39e3052a7ef34bcb5d6a151bb41e943503cfae5] # to [8b1e22897df1bd5e81ce646873f95b5331b395d3] # # patch "project.hh" # from [298cd8010b3f4584139e7962bb3e3ab878468cae] # to [6ff3874fafcb15d1262a569e2bbeb395c907abbf] # # patch "tests/policy-basic/__driver__.lua" # from [db5b67a924dec8c7fd4b15ad511ea57c18c7bab0] # to [e3be590b724d92368d36f75a4705614b3343b373] # ============================================================ --- branch_name.cc 3b62e04943bf835f0c47598a74c96092b9408821 +++ branch_name.cc 102b08ed30c0e69735391c6501ffccff43a66b06 @@ -1,6 +1,8 @@ #include "base.hh" #include "branch_name.hh" +#include "sanity.hh" + using std::string; branch_name::branch_name() @@ -48,6 +50,33 @@ branch_name::strip_prefix(branch_name co return true; } +bool +branch_name::has_postfix(branch_name const & post) const +{ + if (post.data.empty()) + return true; + if (data.size() == post.data.size()) + return data == post.data; + else if (data.size() > post.data.size()) + { + size_t len_diff = data.size() - post.data.size(); + bool ends_with = data.substr(len_diff) == post.data; + return ends_with && data[len_diff-1] == '.'; + } + else + return false; +} + +branch_name +branch_name::without_postfix(branch_name const & post) const +{ + I(has_postfix(post)); + size_t len_diff = data.size() - post.data.size(); + branch_name ret(*this); + ret.data.erase(len_diff-1); + return ret; +} + void branch_name::prepend(branch_name const & pre) { @@ -69,6 +98,14 @@ branch_name::append(branch_name const & data += post.data; } +branch_name +branch_name::operator/(branch_name const & post) const +{ + branch_name ret(*this); + ret.append(post); + return ret; +} + bool operator < (branch_name const & lhs, branch_name const & rhs) ============================================================ --- branch_name.hh 670bf5103f0b79f79248d7323f4f90ca3cc7a871 +++ branch_name.hh d961df061b8adac57a98a79af032a2d765bbb62b @@ -37,13 +37,20 @@ public: std::string operator()() const; std::string::size_type size() const; + inline bool empty() const { return size() == 0; } // note that a branch name is a prefix of itself bool has_prefix(branch_name const & pre) const; bool strip_prefix(branch_name const & pre); + bool has_postfix(branch_name const & post) const; + // yes, this is inconsistent. probably the others should be changed to + // match, rather than this being changed. + branch_name without_postfix(branch_name const & post) const; + void prepend(branch_name const & pre); void append(branch_name const & post); + branch_name operator/(branch_name const & post) const; }; std::ostream & operator << (std::ostream & s, branch_name const & b); ============================================================ --- cmd_policy.cc 1d01be7fa8231ac740ea25b6ca336309611a1ace +++ cmd_policy.cc 6bcb61826311a778e7e4c04b263dc1912886c128 @@ -91,12 +91,14 @@ CMD(create_subpolicy, "create_subpolicy" project_t project(db, app.lua, app.opts); branch_name name = typecast_vocab(idx(args, 0)); + cache_user_key(app.opts, app.lua, db, keys, project); + policy_chain gov; - project.find_governing_policy(name(), gov); + project.find_governing_policy(name, gov); E(!gov.empty(), origin::user, F("Cannot find a parent policy for '%s'") % name); - E(gov.back().full_policy_name != name(), origin::user, + E(gov.back().full_policy_name != name, origin::user, F("Policy '%s' already exists") % name); E(gov.back().delegation.is_branch_type(), origin::user, F("cannot edit '%s', it is delegated to a specific revision") % name); @@ -114,7 +116,7 @@ CMD(create_subpolicy, "create_subpolicy" admin_keys.insert(typecast_vocab(ident.official_name)); } branch_name del_name(name); - del_name.strip_prefix(branch_name(gov.back().full_policy_name, origin::internal)); + del_name.strip_prefix(gov.back().full_policy_name); parent.set_delegation(del_name(), policies::delegation::create(app, admin_keys)); parent_branch.commit(project, keys, parent, @@ -135,8 +137,10 @@ CMD(create_branch, "create_branch", "", project_t project(db, app.lua, app.opts); branch_name branch = typecast_vocab(idx(args, 0)); + cache_user_key(app.opts, app.lua, db, keys, project); + policy_chain gov; - project.find_governing_policy(branch(), gov); + project.find_governing_policy(branch, gov); E(!gov.empty(), origin::user, F("Cannot find policy over '%s'") % branch); @@ -154,7 +158,7 @@ CMD(create_branch, "create_branch", "", admin_keys.insert(typecast_vocab(ident.official_name)); } branch_name suffix(branch); - suffix.strip_prefix(branch_name(gov.back().full_policy_name, origin::internal)); + suffix.strip_prefix(gov.back().full_policy_name); if (suffix().empty()) suffix = branch_name("__main__", origin::internal); ppol.set_branch(suffix(), policies::branch::create(app, admin_keys)); ============================================================ --- policies/policy_branch.cc bc1af8d06fbee650c2b4c85372ab737499e0f2be +++ policies/policy_branch.cc b45efecab6f09651795ac4ef26f4c81e8022acbc @@ -44,6 +44,11 @@ namespace { database & db) : db(db), badbit(false) { + if (!ros.has_node(dir_name)) + { + badbit = true; + return; + } const_node_t n = ros.get_node(dir_name); if (!is_dir_t(n)) { @@ -229,6 +234,10 @@ namespace policies { roster_t new_roster; if (parents.empty()) { + + parents.insert(make_pair(revision_id(), + make_pair(roster_t_cp(new roster_t()), + marking_map_cp(new marking_map())))); } else if (parents.size() == 1) { @@ -265,6 +274,12 @@ namespace policies { temp_node_id_source source; + if (!new_roster.has_root()) + { + node_id n = new_roster.create_dir_node(source); + new_roster.attach_node(n, file_path_internal("")); + } + policy::del_map const & p_delegations = p.list_delegations(); file_path delegation_path = file_path_internal("delegations"); if (!new_roster.has_node(delegation_path)) @@ -303,7 +318,7 @@ namespace policies { revision_id revid; calculate_ident(rev, revid); - string author = decode_hexenc(keys.signing_key.inner()(), origin::internal); + string author = encode_hexenc(keys.signing_key.inner()(), origin::internal); transaction_guard guard(project.db); project.db.put_revision(revid, rev); project.put_standard_certs(keys, revid, ============================================================ --- project.cc f39e3052a7ef34bcb5d6a151bb41e943503cfae5 +++ project.cc 8b1e22897df1bd5e81ce646873f95b5331b395d3 @@ -102,22 +102,25 @@ void walk_policies(project_t const & pro void walk_policies(project_t const & project, shared_ptr root, child_policy_map & children, - boost::function, string, + boost::function, branch_name const &, policies::delegation const &)> fn, - string current_prefix = "", + branch_name current_prefix = branch_name(), policies::delegation del = policies::delegation()) { - if (!root) - return; + L(FL("Walking policies; root = %d, current prefix = '%s'") + % (bool)root % current_prefix); fn(root, current_prefix, del); + if (!root) + return; + policy::del_map const & d(root->list_delegations()); for (policy::del_map::const_iterator i = d.begin(); i != d.end(); ++i) { - string child_prefix = current_prefix; + branch_name child_prefix = current_prefix; if (!i->first.empty()) - child_prefix += string(".") + i->first; + child_prefix.append(branch_name(i->first, origin::internal)); policy_key child_key; child_key.parent = root; @@ -150,21 +153,21 @@ public: map & branches; public: branch_lister(map & b) : branches(b) { } - void operator()(shared_ptr pol, string prefix, + void operator()(shared_ptr pol, branch_name const & prefix, policies::delegation const & del) { + if (!pol) + return; + map const & x = pol->list_branches(); for (map::const_iterator i = x.begin(); i != x.end(); ++i) { - if (prefix.empty()) - branches.insert(make_pair(branch_name(prefix, origin::internal), + if (i->first == "__self__") + branches.insert(make_pair(prefix, branch_info(i->second, pol))); - else if (i->first.empty()) - branches.insert(make_pair(branch_name(i->first, origin::internal), - branch_info(i->second, pol))); else - branches.insert(make_pair(branch_name(prefix + "." + i->first, - origin::internal), + branches.insert(make_pair(prefix / branch_name(i->first, + origin::internal), branch_info(i->second, pol))); } } @@ -177,12 +180,11 @@ public: public: policy_lister(branch_name const & b, set & p) : base(b), policies(p) { } - void operator()(shared_ptr pol, string prefix, + void operator()(shared_ptr pol, branch_name const &prefix, policies::delegation const & del) { - branch_name n(prefix, origin::internal); - if (n.has_prefix(n)) - policies.insert(n); + if (prefix.has_prefix(base)) + policies.insert(prefix); } }; @@ -191,19 +193,19 @@ public: set & tags; public: tag_lister(set & t) : tags(t) { } - void operator()(shared_ptr pol, string prefix, + void operator()(shared_ptr pol, branch_name const & prefix, policies::delegation const & del) { + if (!pol) + return; + map const & x = pol->list_tags(); for (map::const_iterator i = x.begin(); i != x.end(); ++i) { - string name = prefix; - if (!name.empty() && !i->first.empty()) - name += "."; - name += i->first; + branch_name name = prefix / branch_name(i->first, origin::internal); tags.insert(tag_t(i->second, - utf8(name, origin::internal), + utf8(name(), origin::internal), key_id())); } } @@ -214,16 +216,16 @@ class policy_finder // find the policy governing a particular name class policy_finder { - string target; + branch_name target; policy_chain & info; public: - policy_finder(string const & target, policy_chain & info) + policy_finder(branch_name const & target, policy_chain & info) : target(target), info(info) { info.clear(); } - void operator()(shared_ptr pol, string prefix, + void operator()(shared_ptr pol, branch_name const & prefix, policies::delegation const & del) { if (prefix.empty()) @@ -233,11 +235,9 @@ public: info.push_back(i); return; } - if (target.find(prefix) == 0) + if (target.has_prefix(prefix)) { - bool equals = target == prefix; - bool is_prefix = target.length() > prefix.length() && target[prefix.length()] == '.'; - if (equals || is_prefix) + if (target.has_prefix(prefix)) { policy_chain_item i; i.policy = pol; @@ -258,10 +258,12 @@ public: policy_info() : policy(), passthru(true) { + L(FL("Using empty passthru policy")); } policy_info(bool passthru, shared_ptr const & ep) : policy(ep), passthru(passthru) { + L(FL("Using policy with passthru = %d") % passthru); } policies::policy const & get_base_policy() const @@ -310,6 +312,7 @@ public: branch_uid translate_branch(project_t const & project, branch_name const & name) { + L(FL("Translating branch '%s'") % name); map branch_map; walk_policies(project, policy, child_policies, branch_lister(branch_map)); map::const_iterator i = branch_map.find(name); @@ -317,6 +320,29 @@ public: { return i->second.self.get_uid(); } + + L(FL("branch '%s' does not exist") % name); + branch_name postfix("__policy__", origin::internal); + if (name.has_postfix(postfix)) + { + branch_name pol_name = name.without_postfix(postfix); + L(FL("branch '%s' is named like a policy; checking for policy named '%s'") + % name % pol_name); + + policy_chain info; + find_governing_policy(project, pol_name, info); + if (!info.empty()) + { + if (info.back().full_policy_name == pol_name) + { + policies::delegation del = info.back().delegation; + if (del.is_branch_type()) + { + return del.get_branch_spec().get_uid(); + } + } + } + } I(false); } @@ -337,14 +363,15 @@ public: branch_name const & name, branch_uid & uid, set & signers) { + L(FL("Looking up branch '%s'") % name); map branch_map; walk_policies(project, policy, child_policies, branch_lister(branch_map)); map::const_iterator i = branch_map.find(name); if (i != branch_map.end()) { uid = i->second.self.get_uid(); - set raw_signers = i->second.self.get_signers(); - for (set::iterator k = raw_signers.begin(); + set const & raw_signers = i->second.self.get_signers(); + for (set::const_iterator k = raw_signers.begin(); k != raw_signers.end(); ++k) { id id; @@ -356,13 +383,49 @@ public: signers.insert(i->second.owner->get_key_id(kn)); } } - return ; + return; } + L(FL("branch '%s' does not exist") % name); + branch_name postfix("__policy__", origin::internal); + if (name.has_postfix(postfix)) + { + branch_name pol_name = name.without_postfix(postfix); + L(FL("branch '%s' is named like a policy; checking for policy named '%s'") + % name % pol_name); + + policy_chain info; + find_governing_policy(project, pol_name, info); + if (!info.empty()) + { + if (info.back().full_policy_name == pol_name) + { + policies::delegation del = info.back().delegation; + if (del.is_branch_type()) + { + uid = del.get_branch_spec().get_uid(); + set const & raw_signers = del.get_branch_spec().get_signers(); + for (set::const_iterator k = raw_signers.begin(); + k != raw_signers.end(); ++k) + { + id id; + if (try_decode_hexenc((*k)(), id)) + signers.insert(key_id(id)); + else + { + key_name kn = typecast_vocab(*k); + signers.insert(i->second.owner->get_key_id(kn)); + } + } + return; + } + } + } + } I(false); } void find_governing_policy(project_t const & project, - std::string const & of_what, + branch_name const & of_what, policy_chain & info) { walk_policies(project, policy, child_policies, @@ -434,10 +497,10 @@ project_t::policy_exists(branch_name con return name().empty(); policy_chain info; - find_governing_policy(name(), info); + find_governing_policy(name, info); if (info.empty()) return false; - return info.back().full_policy_name == name(); + return info.back().full_policy_name == name; } void @@ -984,7 +1047,7 @@ void } void -project_t::find_governing_policy(string const & of_what, +project_t::find_governing_policy(branch_name const & of_what, policy_chain & info) const { I(!project_policy->passthru); @@ -1001,7 +1064,9 @@ project_t::put_tag(key_store & keys, else { policy_chain info; - project_policy->find_governing_policy(*this, name, info); + project_policy->find_governing_policy(*this, + branch_name(name, origin::user), + info); E(!info.empty(), origin::user, F("Cannot find policy for tag '%s'") % name); E(info.back().delegation.is_branch_type(), origin::user, ============================================================ --- project.hh 298cd8010b3f4584139e7962bb3e3ab878468cae +++ project.hh 6ff3874fafcb15d1262a569e2bbeb395c907abbf @@ -83,7 +83,7 @@ struct policy_chain_item struct policy_chain_item { boost::shared_ptr policy; - std::string full_policy_name; + branch_name full_policy_name; policies::delegation delegation; }; @@ -131,7 +131,7 @@ public: policies::policy const & get_base_policy() const; - void find_governing_policy(std::string const & of_what, + void find_governing_policy(branch_name const & of_what, policy_chain & info) const; bool policy_exists(branch_name const & name) const; ============================================================ --- tests/policy-basic/__driver__.lua db5b67a924dec8c7fd4b15ad511ea57c18c7bab0 +++ tests/policy-basic/__driver__.lua e3be590b724d92368d36f75a4705614b3343b373 @@ -9,10 +9,14 @@ check(not qgrep("test_project.__policy__ check(mtn("ls", "branches"), 0, true, false) check(not qgrep("test_project.__policy__", "stdout")) -check(mtn("checkout", "checkout", "--branch=test_project.__policy__"), 0) +--check(mtn("checkout", "checkout", "--branch=test_project.__policy__"), 0) +check(mtn("setup", "checkout", "--branch=test_project.__policy__"), 0) chdir("checkout") +addfile("file0", "data0") +check(mtn("ci", "-mbase", "--branch=test_project.__policy__"), 0, false, false) + base=base_revision() addfile("file1", "data1") @@ -27,31 +31,47 @@ check(qgrep("already merged", "stderr")) check(mtn("merge", "--branch=test_project.__policy__"), 0, false, true) check(qgrep("already merged", "stderr")) +chdir("..") +addfile("branch_file", "datadatadata") +check(mtn("create_branch", "test_project.test_branch"), 0) +commit("test_project.test_branch", "hackhackhack") +chdir("checkout") + check(mtn("update", "-r", base), 0, false, false) addfile("file3", "data3") --- This will actually fail after the commit proper if --policy-revision --- isn't given, because you can't get the new head count because the --- policy is suddenly invalid... -check(mtn("ci", "-mtwogood", "--branch=test_project.__policy__", +commit("test_project.__policy__", "twogood") + +-- Can't do stuff now, because the policy branch has two heads. +chdir("..") +addfile("otherfile", "otherdata") +check(mtn("ci", "--branch=test_project.test_branch", "-mx"), 1) +check(mtn("heads", "--branch=test_project.test_branch"), 1) + +-- but can do stuff with the --policy-revision option +check(mtn("ci", "-mcommit", "--branch=test_project.test_branch", "--policy-revision=test_project@" .. base), 0, false, false) --- Can't do stuff now, because the policy branch has two heads. -check(mtn("heads", "--branch=test_project.__policy__"), 1, false, false) -check(mtn("merge", "--branch=test_project.__policy__"), 1, false, false) +chdir("checkout") -- check that we can recover from this -check(mtn("merge", "--branch=test_project.__policy__", - "--policy-revision=test_project@" .. base), 0, false, false) +check(mtn("merge", "--branch=test_project.__policy__"), 0, false, false) check(mtn("update", "-r", base), 0, false, false) check(mtn("up"), 0, false, false) check(base ~= base_revision()) +chdir("..") +addfile("foo", "bar") +commit("test_project.test_branch") +tip = base_revision() + +chdir("checkout") + -- check that we can delegate using a revision id mkdir("delegations") addfile("delegations/tp", "revision_id [" .. base .. "]"); check(mtn("ci", "-mx", "--branch=test_project.__policy__"), 0, false, false) -check(mtn("heads", "--branch=test_project.tp.__policy__"), 0, true, false) -check(qgrep(base_revision(), "stdout"), 0, false, false) +check(mtn("heads", "--branch=test_project.tp.test_branch"), 0, true, false) +check(qgrep(tip, "stdout"), 0, false, false)