# # # add_file "policy.cc" # content [04e59e18562970f23c3cd54af71fe2c9f9993d13] # # add_file "policy.hh" # content [9a6cdc2fb6f69de9c4308947298b4df5fedd4b51] # # patch "Makefile.am" # from [07958b10c18fbe74b99312f78099b6b5cc7bbeb9] # to [aa9ea8b141c2bdec08223db4adfcc2898e90151f] # # patch "cmd_policy.cc" # from [a6767f052d77500ef08f244bfa2890988f20de09] # to [4ccd62c139a8a66293200a5739f4a52cee056386] # # patch "project.cc" # from [43edeaf955b2d43ee616a2f075f216b90868ac32] # to [a8f1d9f178cf47aa2f1e8790b96499ac55d05f65] # # patch "project.hh" # from [94babe3c0c3533abdced8bd5f297d279719a20d6] # to [ffe7dc72a2c7bef85019a87ba4f852e2e688c290] # ============================================================ --- policy.cc 04e59e18562970f23c3cd54af71fe2c9f9993d13 +++ policy.cc 04e59e18562970f23c3cd54af71fe2c9f9993d13 @@ -0,0 +1,451 @@ +// Copyright 2008 Timothy Brownawell +// GNU GPL v2 or later + +#include "base.hh" + +#include + +#include "basic_io.hh" +#include "policy.hh" +#include "project.hh" +#include "revision.hh" +#include "transforms.hh" + +using boost::shared_ptr; + +using std::make_pair; +using std::map; +using std::multimap; +using std::set; +using std::string; +using std::vector; + +namespace basic_io +{ + namespace syms + { + symbol const branch_uid("branch_uid"); + symbol const committer("committer"); + symbol const revision_id("revision_id"); + } +} + +policy_branch::policy_branch(database & db) + : db(db) +{ +} + +policy_branch +policy_branch::empty_policy(database & db) +{ + return policy_branch(db); +} + +policy_branch::policy_branch(data const & spec, + branch_prefix const & prefix, + database & db) + : prefix(prefix), db(db) +{ + init(spec); +} + +shared_ptr +policy_branch::maybe_get_branch_policy(branch_name const & name) +{ + map bm = branches(); + map::const_iterator i = bm.find(name); + if (i != bm.end()) + return shared_ptr(new branch_policy(i->second)); + else + return shared_ptr(); +} + +policy_branch::policy_branch(revision_id const & rid, + branch_prefix const & prefix, + database & db) + : prefix(prefix), db(db) +{ + rev.reset(new policy_revision(db, rid, prefix)); +} + +void +policy_branch::init(data const & spec) +{ + bool seen_revid = false; + bool seen_branchspec = false; + revision_id rev_id; + + basic_io::input_source src(spec(), "policy spec"); + basic_io::tokenizer tok(src); + basic_io::parser pa(tok); + + while (pa.symp()) + { + if(pa.symp(basic_io::syms::branch_uid)) + { + seen_branchspec = true; + pa.sym(); + string branch; + pa.str(branch); + my_branch_cert_value = branch_uid(branch); + } + else if (pa.symp(basic_io::syms::committer)) + { + seen_branchspec = true; + pa.sym(); + string key; + pa.str(key); + my_committers.insert(rsa_keypair_id(key)); + } + else if (pa.symp(basic_io::syms::revision_id)) + { + seen_revid = true; + pa.sym(); + string rid; + pa.hex(rid); + rev_id = revision_id(rid); + } + else + { + N(false, F("Unable to understand policy spec file for %s") % prefix); + } + } + + I(src.lookahead == EOF); + + E(seen_revid || seen_branchspec, + F("Policy spec file for %s seems to be empty") % prefix); + + E(seen_revid != seen_branchspec, + F("Policy spec file for %s contains both a revision id and a branch spec") + % prefix); + + if (!null_id(rev_id)) + { + rev.reset(new policy_revision(db, rev_id, prefix)); + } +} + + +policy_revision::policy_revision(database & db, + revision_id const & rev, + branch_prefix const & prefix) +{ + roster_t roster; + db.get_roster(rev, roster); + + file_path branch_dir = file_path_internal("branches"); + file_path delegation_dir = file_path_internal("delegations"); + + if (roster.has_node(branch_dir)) + { + dir_t branch_node = downcast_to_dir_t(roster.get_node(branch_dir)); + for (dir_map::const_iterator i = branch_node->children.begin(); + i != branch_node->children.end(); ++i) + { + branch_name branch; + if (i->first() != "__main__") + { + branch = branch_name(prefix() + "." + i->first()); + } + else + { + branch = branch_name(prefix()); + } + file_id ident = downcast_to_file_t(i->second)->content; + file_data spec; + db.get_file_version(ident, spec); + + branch_uid branch_cert_value; + set committers; + + basic_io::input_source src(spec.inner()(), "branch spec"); + basic_io::tokenizer tok(src); + basic_io::parser pa(tok); + + while (pa.symp()) + { + if (pa.symp(basic_io::syms::branch_uid)) + { + pa.sym(); + string branch; + pa.str(branch); + branch_cert_value = branch_uid(branch); + } + else if (pa.symp(basic_io::syms::committer)) + { + pa.sym(); + string key; + pa.str(key); + committers.insert(rsa_keypair_id(key)); + } + else + { + N(false, + F("Unable to understand branch spec file for %s in revision %s") + % i->first() % rev); + } + } + + branches.insert(make_pair(branch, + branch_policy(branch, + branch_cert_value, + committers))); + } + } + if (roster.has_node(delegation_dir)) + { + dir_t delegation_node = downcast_to_dir_t(roster.get_node(delegation_dir)); + for (dir_map::const_iterator i = delegation_node->children.begin(); + i != delegation_node->children.end(); ++i) + { + branch_prefix subprefix(prefix() + "." + i->first()); + file_id ident = downcast_to_file_t(i->second)->content; + file_data spec; + db.get_file_version(ident, spec); + + delegations.insert(make_pair(subprefix, + policy_branch(spec.inner(), + subprefix, + db))); + } + } +} + +map +policy_revision::all_branches() +{ + typedef map branch_policies; + typedef map policy_branches; + branch_policies out = branches; + for (policy_branches::iterator i = delegations.begin(); + i != delegations.end(); ++i) + { + branch_policies del = i->second.branches(); + for (branch_policies::const_iterator i = del.begin(); + i != del.end(); ++i) + { + out.insert(*i); + } + } + return out; +} + +namespace +{ + struct not_in_managed_branch : public is_failure + { + database & db; + base64 const & branch_encoded; + set const & trusted_signers; + bool is_trusted(set const & signers, + hexenc const & rid, + cert_name const & name, + cert_value const & value) + { + for (set::const_iterator i = signers.begin(); + i != signers.end(); ++i) + { + set::const_iterator t = trusted_signers.find(*i); + if (t != trusted_signers.end()) + return true; + } + return false; + } + not_in_managed_branch(database & db, + base64 const & branch_encoded, + set const & trusted) + : db(db), branch_encoded(branch_encoded), trusted_signers(trusted) + {} + virtual bool operator()(revision_id const & rid) + { + vector< revision > certs; + db.get_revision_certs(rid, + cert_name(branch_cert_name), + branch_encoded, + certs); + erase_bogus_certs(db, + boost::bind(¬_in_managed_branch::is_trusted, + this, _1, _2, _3, _4), + certs); + return certs.empty(); + } + }; + + struct suspended_in_managed_branch : public is_failure + { + database & db; + base64 const & branch_encoded; + set const & trusted_signers; + bool is_trusted(set const & signers, + hexenc const & rid, + cert_name const & name, + cert_value const & value) + { + for (set::const_iterator i = signers.begin(); + i != signers.end(); ++i) + { + set::const_iterator t = trusted_signers.find(*i); + if (t != trusted_signers.end()) + return true; + } + return false; + } + suspended_in_managed_branch(database & db, + base64 const & branch_encoded, + set const & trusted) + : db(db), branch_encoded(branch_encoded), trusted_signers(trusted) + {} + virtual bool operator()(revision_id const & rid) + { + vector< revision > certs; + db.get_revision_certs(rid, + cert_name(suspend_cert_name), + branch_encoded, + certs); + erase_bogus_certs(db, + boost::bind(&suspended_in_managed_branch::is_trusted, + this, _1, _2, _3, _4), + certs); + return !certs.empty(); + } + }; +} + +outdated_indicator +get_branch_heads(branch_policy const & pol, + bool ignore_suspend_certs, + database & db, + std::set & heads, + multimap + * inverse_graph_cache_ptr) +{ + outdated_indicator ret; + base64 branch_encoded; + encode_base64(cert_value(pol.branch_cert_value()), branch_encoded); + + ret = db.get_revisions_with_cert(cert_name(branch_cert_name), + branch_encoded, heads); + + not_in_managed_branch p(db, branch_encoded, pol.committers); + erase_ancestors_and_failures(db, heads, p, inverse_graph_cache_ptr); + + if (!ignore_suspend_certs) + { + suspended_in_managed_branch s(db, branch_encoded, pol.committers); + std::set::iterator it = heads.begin(); + while (it != heads.end()) + { + if (s(*it)) + heads.erase(it++); + else + it++; + } + } + return ret; +} + + +bool maybe_get_policy_branch_head(branch_uid const & name, + set const & trusted_signers, + database & db, + revision_id & rid) +{ + L(FL("getting heads of policy branch %s") % name); + base64 branch_encoded; + encode_base64(cert_value(name()), branch_encoded); + set heads; + + db.get_revisions_with_cert(cert_name(branch_cert_name), + branch_encoded, + heads); + + not_in_managed_branch p(db, branch_encoded, trusted_signers); + erase_ancestors_and_failures(db, heads, p, NULL); + + if (heads.size() != 1) + { + W(F("Policy branch %s has %d heads, should have 1 head.") + % name % heads.size()); + W(F("Some branches may not be available.")); + return false; + } + else + { + rid = *heads.begin(); + return true; + } +} + + +shared_ptr policy_branch::get_policy() +{ + if (!rev) + { + revision_id rid; + if (maybe_get_policy_branch_head(my_branch_cert_value, + my_committers, db, rid)) + { + rev.reset(new policy_revision(db, rid, prefix)); + } + } + return rev; +} +map policy_branch::branches() +{ + shared_ptr policy = get_policy(); + if (policy) + { + return policy->all_branches(); + } + else + return map(); +} + + +bool +policy_branch::get_nearest_policy(branch_name const & name, + branch_policy & policy_policy, + branch_prefix & policy_prefix, + std::string const & accumulated_prefix) +{ + shared_ptr policy = get_policy(); + if (!policy) + return false; + + policy_policy = branch_policy(branch_name(), + my_branch_cert_value, + my_committers); + return policy->get_nearest_policy(name, policy_policy, policy_prefix, + accumulated_prefix); +} + +bool +policy_revision::get_nearest_policy(branch_name const & name, + branch_policy & policy_policy, + branch_prefix & policy_prefix, + std::string const & accumulated_prefix) +{ + for (std::map::iterator + i = delegations.begin(); i != delegations.end(); ++i) + { + std::string mypref(accumulated_prefix + "." + i->first()); + if (name().find(mypref) == 0) + { + return i->second.get_nearest_policy(name, + policy_policy, + policy_prefix, + mypref); + } + } + policy_prefix = branch_prefix(accumulated_prefix); + return true; +} + +// Local Variables: +// mode: C++ +// fill-column: 76 +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +// vim: et:sw=2:sts=2:ts=2:cino=>2s,{s,\:s,+s,t0,g0,^-2,e-2,n-2,p2s,(0,=s: ============================================================ --- policy.hh 9a6cdc2fb6f69de9c4308947298b4df5fedd4b51 +++ policy.hh 9a6cdc2fb6f69de9c4308947298b4df5fedd4b51 @@ -0,0 +1,121 @@ +// Copyright 2007 Timothy Brownawell +// GNU GPL v2 or later + +#ifndef __POLICY_HH__ +#define __POLICY_HH__ + +#include +#include + +#include + +#include "database.hh" +#include "vocab.hh" + + +class branch_policy +{ + branch_name _visible_name; + branch_uid _branch_cert_value; + std::set _committers; +public: + branch_name const & visible_name; + branch_uid const & branch_cert_value; + std::set const & committers; + + branch_policy() + : visible_name(_visible_name), + branch_cert_value(_branch_cert_value), + committers(_committers) + { } + branch_policy(branch_name const & name, + branch_uid const & value, + std::set const & keys) + : _visible_name(name), + _branch_cert_value(value), + _committers(keys), + visible_name(_visible_name), + branch_cert_value(_branch_cert_value), + committers(_committers) + { } + branch_policy const & + operator=(branch_policy const & rhs) + { + _visible_name = rhs._visible_name; + _branch_cert_value = rhs._branch_cert_value; + _committers = rhs._committers; + return *this; + } +}; + +outdated_indicator +get_branch_heads(branch_policy const & pol, + bool ignore_suspend_certs, + database & db, + std::set & heads, + std::multimap + * inverse_graph_cache_ptr); + + +class policy_revision; + +class policy_branch +{ + branch_prefix prefix; + branch_uid my_branch_cert_value; + std::set my_committers; + + database & db; + boost::shared_ptr rev; + void init(data const & spec); + + policy_branch(database & db); +public: + static policy_branch empty_policy(database & db); + policy_branch(data const & spec, + branch_prefix const & prefix, + database & db); + policy_branch(revision_id const & rid, + branch_prefix const & prefix, + database & db); + boost::shared_ptr get_policy(); + std::map branches(); + + boost::shared_ptr + maybe_get_branch_policy(branch_name const & name); + + bool + get_nearest_policy(branch_name const & name, + branch_policy & policy_policy, + branch_prefix & policy_prefix, + std::string const & accumulated_prefix); +}; + +class policy_revision +{ + std::map branches; + std::map delegations; +public: + policy_revision(database & db, + revision_id const & rev, + branch_prefix const & prefix); + std::map all_branches(); + + bool + get_nearest_policy(branch_name const & name, + branch_policy & policy_policy, + branch_prefix & policy_prefix, + std::string const & accumulated_prefix); +}; + + + +#endif + +// Local Variables: +// mode: C++ +// fill-column: 76 +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +// vim: et:sw=2:sts=2:ts=2:cino=>2s,{s,\:s,+s,t0,g0,^-2,e-2,n-2,p2s,(0,=s: ============================================================ --- Makefile.am 07958b10c18fbe74b99312f78099b6b5cc7bbeb9 +++ Makefile.am aa9ea8b141c2bdec08223db4adfcc2898e90151f @@ -32,6 +32,7 @@ MOST_SOURCES = \ update.cc update.hh \ work.cc work_migration.cc work.hh \ cert.cc cert.hh \ + policy.cc policy.hh \ project.cc project.hh \ outdated_indicator.cc outdated_indicator.hh \ database.cc database.hh \ ============================================================ --- cmd_policy.cc a6767f052d77500ef08f244bfa2890988f20de09 +++ cmd_policy.cc 4ccd62c139a8a66293200a5739f4a52cee056386 @@ -12,6 +12,8 @@ #include "file_io.hh" #include "keys.hh" #include "key_store.hh" +#include "policy.hh" +#include "project.hh" #include "revision.hh" #include "roster.hh" #include "transforms.hh" @@ -176,9 +178,86 @@ CMD(create_subpolicy, "create_subpolicy" } CMD(create_subpolicy, "create_subpolicy", "", CMD_REF(policy), - N_("NAME"), + N_("BRANCH_PREFIX"), N_("Create a policy for a new subtree of an existing project."), "", options::opts::none) { + N(args.size() == 1, + F("Wrong argument count.")); + + database db(app); + key_store keys(app); + project_set projects(db, app.lua, app.opts); + branch_prefix prefix(idx(args, 0)()); + branch_name name(prefix() + ".__policy__"); + + branch_policy policy_policy; + branch_prefix parent_prefix; + E(projects.get_project_of_branch(name) + .get_policy_branch_policy_of(name, policy_policy, parent_prefix), + F("Cannot find parent policy for %s") % prefix); + + std::string subprefix; + E(prefix() != parent_prefix(), + F("A policy for %s already exists.") % prefix); + I(prefix().find(parent_prefix() + ".") == 0); + subprefix = prefix().substr(parent_prefix().size()+1); + + std::set policy_heads; + get_branch_heads(policy_policy, false, db, policy_heads, NULL); + E(policy_heads.size() == 1, + F("Parent policy branch has %n heads, should have 1") % policy_heads.size()); + + revision_id policy_old_rev_id(*policy_heads.begin()); + + roster_t policy_old_roster; + db.get_roster(policy_old_rev_id, policy_old_roster); + file_path delegation_dir = file_path_internal("delegations"); + file_path delegation_file = delegation_dir / path_component(subprefix); + E(!policy_old_roster.has_node(delegation_file), + F("A policy for %s already exists.") % prefix); + + cset policy_changes; + + if (!policy_old_roster.has_node(delegation_dir)) + { + policy_changes.dirs_added.insert(delegation_dir); + } + + transaction_guard guard(db); + + cache_user_key(app.opts, app.lua, db, keys); + std::set admin_keys; + admin_keys.insert(keys.signing_key); + + std::string child_uid; + data child_spec; + create_policy_branch(db, keys, app.lua, app.opts, + prefix, admin_keys, child_uid, child_spec); + file_id child_spec_id; + { + file_data child_file_dat(child_spec); + calculate_ident(child_file_dat, child_spec_id); + } + + policy_changes.files_added.insert(std::make_pair(delegation_file, + child_spec_id)); + + revision_t policy_new_revision; + make_revision(policy_old_rev_id, + policy_old_roster, + policy_changes, + policy_new_revision); + + + guard.commit(); } + +CMD(create_branch, "create_branch", "", CMD_REF(policy), + N_("NAME"), + N_("Create a new branch."), + "", + options::opts::none) +{ +} ============================================================ --- project.cc 43edeaf955b2d43ee616a2f075f216b90868ac32 +++ project.cc a8f1d9f178cf47aa2f1e8790b96499ac55d05f65 @@ -6,11 +6,11 @@ #include #include -#include "basic_io.hh" #include "cert.hh" #include "database.hh" #include "file_io.hh" #include "globish.hh" +#include "policy.hh" #include "project.hh" #include "revision.hh" #include "transforms.hh" @@ -25,390 +25,7 @@ using boost::shared_ptr; using std::make_pair; using boost::shared_ptr; -namespace basic_io -{ - namespace syms - { - symbol const branch_uid("branch_uid"); - symbol const committer("committer"); - symbol const revision_id("revision_id"); - } -} -struct branch_policy -{ - branch_name const visible_name; - branch_uid const branch_cert_value; - set const committers; - - branch_policy(branch_name const & name, - branch_uid const & value, - set const & keys) - : visible_name(name), - branch_cert_value(value), - committers(keys) - { } -}; - -class policy_revision; - -class policy_branch -{ - branch_prefix prefix; - branch_uid my_branch_cert_value; - set my_committers; - - database & db; - shared_ptr rev; - void init(data const & spec); - policy_branch(database & db) - : db(db) - { - } -public: - static policy_branch empty_policy(database & db) - { - return policy_branch(db); - } - policy_branch(data const & spec, - branch_prefix const & prefix, - database & db) - : prefix(prefix), db(db) - { - init(spec); - } - policy_branch(revision_id const & rid, - branch_prefix const & prefix, - database & db); - shared_ptr get_policy(); - map branches(); - - shared_ptr - maybe_get_branch_policy(branch_name const & name) - { - map bm = branches(); - map::const_iterator i = bm.find(name); - if (i != bm.end()) - return shared_ptr(new branch_policy(i->second)); - else - return shared_ptr(); - } -}; - -class policy_revision -{ - map branches; - map delegations; -public: - policy_revision(database & db, - revision_id const & rev, - branch_prefix const & prefix) - { - roster_t roster; - db.get_roster(rev, roster); - - file_path branch_dir = file_path_internal("branches"); - file_path delegation_dir = file_path_internal("delegations"); - - if (roster.has_node(branch_dir)) - { - dir_t branch_node = downcast_to_dir_t(roster.get_node(branch_dir)); - for (dir_map::const_iterator i = branch_node->children.begin(); - i != branch_node->children.end(); ++i) - { - branch_name branch; - if (i->first() != "__main__") - { - branch = branch_name(prefix() + "." + i->first()); - } - else - { - branch = branch_name(prefix()); - } - file_id ident = downcast_to_file_t(i->second)->content; - file_data spec; - db.get_file_version(ident, spec); - - branch_uid branch_cert_value; - set committers; - - basic_io::input_source src(spec.inner()(), "branch spec"); - basic_io::tokenizer tok(src); - basic_io::parser pa(tok); - - while (pa.symp()) - { - if (pa.symp(basic_io::syms::branch_uid)) - { - pa.sym(); - string branch; - pa.str(branch); - branch_cert_value = branch_uid(branch); - } - else if (pa.symp(basic_io::syms::committer)) - { - pa.sym(); - string key; - pa.str(key); - committers.insert(rsa_keypair_id(key)); - } - else - { - N(false, - F("Unable to understand branch spec file for %s in revision %s") - % i->first() % rev); - } - } - - branches.insert(make_pair(branch, - branch_policy(branch, - branch_cert_value, - committers))); - } - } - if (roster.has_node(delegation_dir)) - { - dir_t delegation_node = downcast_to_dir_t(roster.get_node(delegation_dir)); - for (dir_map::const_iterator i = delegation_node->children.begin(); - i != delegation_node->children.end(); ++i) - { - branch_prefix subprefix(prefix() + "." + i->first()); - file_id ident = downcast_to_file_t(i->second)->content; - file_data spec; - db.get_file_version(ident, spec); - - delegations.insert(make_pair(subprefix, - policy_branch(spec.inner(), - subprefix, - db))); - } - } - } - map all_branches() - { - typedef map branch_policies; - typedef map policy_branches; - branch_policies out = branches; - for (policy_branches::iterator i = delegations.begin(); - i != delegations.end(); ++i) - { - branch_policies del = i->second.branches(); - for (branch_policies::const_iterator i = del.begin(); - i != del.end(); ++i) - { - out.insert(*i); - } - } - return out; - } -}; - -policy_branch::policy_branch(revision_id const & rid, - branch_prefix const & prefix, - database & db) - : prefix(prefix), db(db) -{ - rev.reset(new policy_revision(db, rid, prefix)); -} - -void -policy_branch::init(data const & spec) -{ - bool seen_revid = false; - bool seen_branchspec = false; - revision_id rev_id; - - basic_io::input_source src(spec(), "policy spec"); - basic_io::tokenizer tok(src); - basic_io::parser pa(tok); - - while (pa.symp()) - { - if(pa.symp(basic_io::syms::branch_uid)) - { - seen_branchspec = true; - pa.sym(); - string branch; - pa.str(branch); - my_branch_cert_value = branch_uid(branch); - } - else if (pa.symp(basic_io::syms::committer)) - { - seen_branchspec = true; - pa.sym(); - string key; - pa.str(key); - my_committers.insert(rsa_keypair_id(key)); - } - else if (pa.symp(basic_io::syms::revision_id)) - { - seen_revid = true; - pa.sym(); - string rid; - pa.hex(rid); - rev_id = revision_id(rid); - } - else - { - N(false, F("Unable to understand policy spec file for %s") % prefix); - } - } - - I(src.lookahead == EOF); - - E(seen_revid || seen_branchspec, - F("Policy spec file for %s seems to be empty") % prefix); - - E(seen_revid != seen_branchspec, - F("Policy spec file for %s contains both a revision id and a branch spec") - % prefix); - - if (!null_id(rev_id)) - { - rev.reset(new policy_revision(db, rev_id, prefix)); - } -} - -namespace -{ - struct not_in_managed_branch : public is_failure - { - database & db; - base64 const & branch_encoded; - set const & trusted_signers; - bool is_trusted(set const & signers, - hexenc const & rid, - cert_name const & name, - cert_value const & value) - { - for (set::const_iterator i = signers.begin(); - i != signers.end(); ++i) - { - set::const_iterator t = trusted_signers.find(*i); - if (t != trusted_signers.end()) - return true; - } - return false; - } - not_in_managed_branch(database & db, - base64 const & branch_encoded, - set const & trusted) - : db(db), branch_encoded(branch_encoded), trusted_signers(trusted) - {} - virtual bool operator()(revision_id const & rid) - { - vector< revision > certs; - db.get_revision_certs(rid, - cert_name(branch_cert_name), - branch_encoded, - certs); - erase_bogus_certs(db, - boost::bind(¬_in_managed_branch::is_trusted, - this, _1, _2, _3, _4), - certs); - return certs.empty(); - } - }; - - struct suspended_in_managed_branch : public is_failure - { - database & db; - base64 const & branch_encoded; - set const & trusted_signers; - bool is_trusted(set const & signers, - hexenc const & rid, - cert_name const & name, - cert_value const & value) - { - for (set::const_iterator i = signers.begin(); - i != signers.end(); ++i) - { - set::const_iterator t = trusted_signers.find(*i); - if (t != trusted_signers.end()) - return true; - } - return false; - } - suspended_in_managed_branch(database & db, - base64 const & branch_encoded, - set const & trusted) - : db(db), branch_encoded(branch_encoded), trusted_signers(trusted) - {} - virtual bool operator()(revision_id const & rid) - { - vector< revision > certs; - db.get_revision_certs(rid, - cert_name(suspend_cert_name), - branch_encoded, - certs); - erase_bogus_certs(db, - boost::bind(&suspended_in_managed_branch::is_trusted, - this, _1, _2, _3, _4), - certs); - return !certs.empty(); - } - }; - - - bool maybe_get_policy_branch_head(branch_uid const & name, - set const & trusted_signers, - database & db, - revision_id & rid) - { - L(FL("getting heads of policy branch %s") % name); - base64 branch_encoded; - encode_base64(cert_value(name()), branch_encoded); - set heads; - - db.get_revisions_with_cert(cert_name(branch_cert_name), - branch_encoded, - heads); - - not_in_managed_branch p(db, branch_encoded, trusted_signers); - erase_ancestors_and_failures(db, heads, p, NULL); - - if (heads.size() != 1) - { - W(F("Policy branch %s has %d heads, should have 1 head.") - % name % heads.size()); - W(F("Some branches may not be available.")); - return false; - } - else - { - rid = *heads.begin(); - return true; - } - } -} - - -shared_ptr policy_branch::get_policy() -{ - if (!rev) - { - revision_id rid; - if (maybe_get_policy_branch_head(my_branch_cert_value, - my_committers, db, rid)) - { - rev.reset(new policy_revision(db, rid, prefix)); - } - } - return rev; -} -map policy_branch::branches() -{ - shared_ptr policy = get_policy(); - if (policy) - { - return policy->all_branches(); - } - else - return map(); -} - -//////////////////////////////////////////////////////////////////////// - class policy_info { public: @@ -448,6 +65,18 @@ project_t::project_t(database & db) : db(db), project_policy(new policy_info(db)) {} +bool +project_t::get_policy_branch_policy_of(branch_name const & name, + branch_policy & policy_branch_policy, + branch_prefix & policy_prefix) +{ + std::string acc; + return project_policy->policy.get_nearest_policy(name, + policy_branch_policy, + policy_prefix, + acc); +} + void project_t::get_branch_list(std::set & names, bool check_heads) @@ -629,66 +258,49 @@ project_t::get_branch_heads(branch_name cache_index(name, ignore_suspend_certs); std::pair > & branch = branch_heads[cache_index]; + if (branch.first.outdated()) { L(FL("getting heads of branch %s") % name); - shared_ptr bp; - if (!project_policy->passthru) - { - bp = project_policy->policy.maybe_get_branch_policy(name); - E(bp, F("Cannot find policy for branch %s.") % name); - } - branch_uid uid; if (project_policy->passthru) - uid = branch_uid(name()); - else - uid = bp->branch_cert_value; + { + base64 branch_encoded; + encode_base64(cert_value(name()), branch_encoded); - base64 branch_encoded; - encode_base64(cert_value(uid()), branch_encoded); + branch.first = db.get_revisions_with_cert(cert_name(branch_cert_name), + branch_encoded, + branch.second); - outdated_indicator stamp; - branch.first = db.get_revisions_with_cert(cert_name(branch_cert_name), - branch_encoded, - branch.second); - - if (project_policy->passthru) - { not_in_branch p(db, branch_encoded); erase_ancestors_and_failures(db, branch.second, p, inverse_graph_cache_ptr); - } - else - { - not_in_managed_branch p(db, branch_encoded, bp->committers); - erase_ancestors_and_failures(db, branch.second, p, - inverse_graph_cache_ptr); - } - if (!ignore_suspend_certs) - { - if (project_policy->passthru) + if (!ignore_suspend_certs) { suspended_in_branch s(db, branch_encoded); std::set::iterator it = branch.second.begin(); while (it != branch.second.end()) - if (s(*it)) - branch.second.erase(it++); - else - it++; + { + if (s(*it)) + branch.second.erase(it++); + else + it++; + } } - else - { - suspended_in_managed_branch s(db, branch_encoded, bp->committers); - std::set::iterator it = branch.second.begin(); - while (it != branch.second.end()) - if (s(*it)) - branch.second.erase(it++); - else - it++; - } } + else + { + shared_ptr bp; + bp = project_policy->policy.maybe_get_branch_policy(name); + E(bp, F("Cannot find policy for branch %s.") % name); + + branch.first = ::get_branch_heads(*bp, ignore_suspend_certs, db, + branch.second, + inverse_graph_cache_ptr); + } + + L(FL("found heads of branch %s (%s heads)") % name % branch.second.size()); ============================================================ --- project.hh 94babe3c0c3533abdced8bd5f297d279719a20d6 +++ project.hh ffe7dc72a2c7bef85019a87ba4f852e2e688c290 @@ -16,6 +16,8 @@ class lua_hooks; class options; class lua_hooks; +class branch_policy; + class tag_t { public: @@ -61,6 +63,10 @@ public: revision_id const & policy_rev, database & db); + bool get_policy_branch_policy_of(branch_name const & name, + branch_policy & policy_branch_policy, + branch_prefix & policy_prefix); + void get_branch_list(std::set & names, bool check_heads = false); void get_branch_list(globish const & glob, std::set & names,