# # # patch "cmd_policy.cc" # from [590363a44896e8e6a84ce26b96e40dbdacafc072] # to [94aaef4c6d5bffa4bdad8683a327fe6307324350] # # patch "policies/editable_policy.cc" # from [4b51aa214719e1fb198d510ed59b7ce0ba149727] # to [3fb66a38bd9a95f45328f4f1cd21477691901825] # # patch "policies/editable_policy.hh" # from [d05ff58508caf9bb0bc87ffd14061839359fa08b] # to [0912f223df29917545e07711078413526735cbe6] # # patch "policies/policy.cc" # from [0e66bf7e1fcf734fdb534a15c1de094d2a463b93] # to [955c1314f33a8223a13fedfcdcc123b18b36fe38] # # patch "policies/policy.hh" # from [7cd5e6122758b0b1daf9cd2470154d87ae4ccf8b] # to [39b9f928af538c226e68e330e8a137abca2df16b] # # patch "policies/policy_branch.cc" # from [d7ae6973b3a68fe37eb5faca4174f705e336692b] # to [7d4f1e12cfd4790e8c65a6f47fc99cf883f1ec6a] # # patch "policies/policy_branch.hh" # from [d9b4d6a763de19864950b3ede9b4c29c19f121ec] # to [7be6faa4845ed692714c3af3ee1b0a44f341c402] # # patch "project.cc" # from [d117abfb5529ddd56bee8c288e2a846299d7f736] # to [32b0904af4c80522a15f14526dc7631c36f9981b] # # patch "project.hh" # from [17810c296afb72c1a8de0ac154e147c3418aa4f5] # to [2375749bafc6d8f9adcf56b4f46470f84e9193d7] # ============================================================ --- cmd_policy.cc 590363a44896e8e6a84ce26b96e40dbdacafc072 +++ cmd_policy.cc 94aaef4c6d5bffa4bdad8683a327fe6307324350 @@ -101,7 +101,9 @@ CMD(create_subpolicy, "create_subpolicy" 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); - policies::policy_branch parent_branch(gov.back().delegation.get_branch_spec()); + policies::policy_branch parent_branch(project, + gov.back().policy, + gov.back().delegation.get_branch_spec()); policies::editable_policy parent(**parent_branch.begin()); @@ -140,7 +142,9 @@ CMD(create_branch, "create_branch", "", F("Cannot find policy over '%s'") % branch); E(gov.back().delegation.is_branch_type(), origin::user, F("cannot edit '%s', it is delegated to a specific revision") % branch); - policies::policy_branch parent(gov.back().delegation.get_branch_spec()); + policies::policy_branch parent(project, + gov.back().policy, + gov.back().delegation.get_branch_spec()); policies::editable_policy ppol(**parent.begin()); std::set admin_keys; { ============================================================ --- policies/editable_policy.cc 4b51aa214719e1fb198d510ed59b7ce0ba149727 +++ policies/editable_policy.cc 3fb66a38bd9a95f45328f4f1cd21477691901825 @@ -12,10 +12,21 @@ namespace policies { #include "editable_policy.hh" namespace policies { + editable_policy::editable_policy() { } editable_policy::editable_policy(policy const & p) : policy(p) { } + void editable_policy::set_key(key_name const & name, + key_id const & value) + { + keys[name] = value; + } + void editable_policy::remove_key(key_name const & name) + { + keys.erase(name); + } + void editable_policy::set_branch(std::string const & name, branch const & value) { ============================================================ --- policies/editable_policy.hh d05ff58508caf9bb0bc87ffd14061839359fa08b +++ policies/editable_policy.hh 0912f223df29917545e07711078413526735cbe6 @@ -17,10 +17,11 @@ namespace policies { class editable_policy : public policy { public: + editable_policy(); explicit editable_policy(policy const & p); - //void set_key_name(key_id const & ident, key_name const & name); - //void remove_key(key_id const & ident); + void set_key(key_name const & name, key_id const & ident); + void remove_key(key_name const & name); void set_branch(std::string const & name, branch const & value); void remove_branch(std::string const & name); ============================================================ --- policies/policy.cc 0e66bf7e1fcf734fdb534a15c1de094d2a463b93 +++ policies/policy.cc 955c1314f33a8223a13fedfcdcc123b18b36fe38 @@ -31,10 +31,8 @@ namespace policies { for (key_map::const_iterator k = keys.begin(); k != keys.end(); ++k) { - key_id test; - key_hash_code(k->second.first, k->second.second, test); - if (ident == test) - return key_name(k->first, origin::internal); + if (ident == k->second) + return k->first; } shared_ptr p = parent.lock(); if (p) @@ -45,12 +43,10 @@ namespace policies { key_id policy::get_key_id(key_name const & ident) const { - key_map::const_iterator k = keys.find(ident()); + key_map::const_iterator k = keys.find(ident); if (k != keys.end()) { - key_id out; - key_hash_code(k->second.first, k->second.second, out); - return out; + return k->second; } shared_ptr p = parent.lock(); if (p) ============================================================ --- policies/policy.hh 7cd5e6122758b0b1daf9cd2470154d87ae4ccf8b +++ policies/policy.hh 39b9f928af538c226e68e330e8a137abca2df16b @@ -25,7 +25,7 @@ namespace policies { { public: typedef std::map del_map; - typedef std::map > key_map; + typedef std::map key_map; protected: std::map branches; del_map delegations; @@ -43,6 +43,7 @@ namespace policies { // keys // a key could have several names, should // there be an invariant against that? + // should this really be the full key_name, or just the final suffix? key_name get_key_name(key_id const & ident) const; key_id get_key_id(key_name const & ident) const; ============================================================ --- policies/policy_branch.cc d7ae6973b3a68fe37eb5faca4174f705e336692b +++ policies/policy_branch.cc 7d4f1e12cfd4790e8c65a6f47fc99cf883f1ec6a @@ -11,11 +11,141 @@ #include "base.hh" #include "policies/policy_branch.hh" +#include "database.hh" +#include "lexical_cast.hh" +#include "policies/editable_policy.hh" +#include "project.hh" +#include "roster.hh" +#include "transforms.hh" +#include "vocab_cast.hh" + +using std::pair; +using std::string; + +namespace { + class item_lister + { + database & db; + dir_map::const_iterator i, end; + bool badbit; + public: + typedef pair value_type; + private: + value_type value; + public: + item_lister(roster_t const & ros, + file_path const & dir_name, + database & db) + : db(db), badbit(false) + { + node_t n = ros.get_node(dir_name); + if (!is_dir_t(n)) + { + badbit = true; + return; + } + dir_t dir = downcast_to_dir_t(n); + i = dir->children.begin(); + while (i != end && !is_file_t(i->second)) + { + ++i; + } + end = dir->children.end(); + if ((bool)*this) + { + get(value.first, value.second); + } + } + bool bad() const { return badbit; } + operator bool() const + { + return !badbit && i != end; + } + item_lister const & operator++() + { + I(i != end); + do { + ++i; + } while (i != end && !is_file_t(i->second)); + get(value.first, value.second); + return *this; + } + void get(string & name, data & contents) const + { + name = i->first(); + file_t f = downcast_to_file_t(i->second); + file_data fdat; + db.get_file_version(f->content, fdat); + contents = fdat.inner(); + } + value_type const & operator*() const + { + return value; + } + value_type const * operator->() const + { + return &value; + } + }; + typedef policies::policy_branch::policy_ptr policy_ptr; + policy_ptr policy_from_revision(project_t & project, + revision_id const & rev) + { + roster_t the_roster; + project.db.get_roster(rev, the_roster); + policies::editable_policy pol; + + for (item_lister i(the_roster, + file_path_internal("branches"), + project.db); + i; ++i) + { + policies::branch b; + b.deserialize(i->second()); + pol.set_branch(i->first, b); + } + + for (item_lister i(the_roster, + file_path_internal("delegations"), + project.db); + i; ++i) + { + policies::delegation d; + d.deserialize(i->second()); + pol.set_delegation(i->first, d); + } + + for (item_lister i(the_roster, + file_path_internal("tags"), + project.db); + i; ++i) + { + string s = boost::lexical_cast(i->second); + revision_id rid = decode_hexenc_as(s, origin::internal); + pol.set_tag(i->first, rid); + } + + for (item_lister i(the_roster, + file_path_internal("keys"), + project.db); + i; ++i) + { + string s = boost::lexical_cast(i->second); + key_id id = decode_hexenc_as(s, origin::internal); + pol.set_key(key_name(i->first, origin::internal), id); + } + + return policy_ptr(new policies::policy(pol)); + } +} + namespace policies { - policy_branch::policy_branch(branch const & b) - : spec(b) + policy_branch::policy_branch(project_t & project, + policy_branch::policy_ptr parent_policy, + branch const & b) + : spec_owner(parent_policy), spec(b) { - reload(); + reload(project); } branch const & policy_branch::get_spec() const { @@ -30,6 +160,38 @@ namespace policies { { return policies.end(); } + + void policy_branch::reload(project_t & project) + { + policies.clear(); + std::set heads; + std::set keys; + std::set const & key_names = spec.get_signers(); + for (std::set::const_iterator i = key_names.begin(); + i != key_names.end(); ++i) + { + id ident; + if (try_decode_hexenc((*i)(), ident)) + { + keys.insert(key_id(ident)); + } + else + { + key_name name = typecast_vocab(*i); + keys.insert(spec_owner->get_key_id(name)); + } + } + project.get_branch_heads(spec.get_uid(), + keys, + heads, + false); + + for (std::set::const_iterator i = heads.begin(); + i != heads.end(); ++i) + { + policies.insert(policy_from_revision(project, *i)); + } + } } ============================================================ --- policies/policy_branch.hh d9b4d6a763de19864950b3ede9b4c29c19f121ec +++ policies/policy_branch.hh 7be6faa4845ed692714c3af3ee1b0a44f341c402 @@ -17,19 +17,25 @@ #include "policies/delegation.hh" #include "policies/policy.hh" +class project_t; + namespace policies { class policy_branch { public: - typedef std::set > policy_set; + typedef boost::shared_ptr policy_ptr; + typedef std::set policy_set; private: + policy_ptr spec_owner; branch spec; policy_set policies; - void reload(); + void reload(project_t & project); public: typedef policy_set::const_iterator iterator; - policy_branch(branch const & b); + policy_branch(project_t & project, + policy_ptr parent_policy, + branch const & b); //policy_branch(delegation const & d); branch const & get_spec() const; ============================================================ --- project.cc d117abfb5529ddd56bee8c288e2a846299d7f736 +++ project.cc 32b0904af4c80522a15f14526dc7631c36f9981b @@ -46,6 +46,34 @@ using policies::policy; using policies::branch; using policies::policy; +branch_heads_key::branch_heads_key(branch_uid const & uid, + bool ignore_suspends, + std::set const & keys, + bool have_signers) + : uid(uid), + ignore_suspends(ignore_suspends), + keys(keys), + have_signers(have_signers) +{ } +bool operator<(branch_heads_key const & a, + branch_heads_key const & b) +{ + if (a.uid < b.uid) + return true; + else if (b.uid < a.uid) + return false; + else if (a.ignore_suspends < b.ignore_suspends) + return true; + else if (b.ignore_suspends < a.ignore_suspends) + return false; + else if (a.have_signers < b.have_signers) + return true; + else if (b.have_signers < a.have_signers) + return false; + else + return a.keys < b.keys; +} + struct policy_key { weak_ptr parent; @@ -629,67 +657,100 @@ namespace return !certs.empty(); } }; + + void do_get_branch_heads(pair > & branch, + project_t & project, + branch_uid const & uid, + set const * const signers, + bool ignore_suspend_certs, + multimap * inverse_graph_cache_ptr) + { + if (!branch.first.outdated()) + return; + + L(FL("getting heads of branch %s") % uid); + + branch.first = project.db.get_revisions_with_cert(cert_name(branch_cert_name), + typecast_vocab(uid), + branch.second); + + shared_ptr p; + if (!signers) + p.reset(new not_in_branch(project, uid)); + else + p.reset(new not_in_branch(project, uid, *signers)); + + erase_ancestors_and_failures(project.db, branch.second, *p, + inverse_graph_cache_ptr); + + if (!ignore_suspend_certs) + { + shared_ptr s; + if (!signers) + s.reset(new suspended_in_branch(project, uid)); + else + s.reset(new suspended_in_branch(project, uid, *signers)); + set::iterator it = branch.second.begin(); + while (it != branch.second.end()) + { + if ((*s)(*it)) + branch.second.erase(it++); + else + it++; + } + } + + L(FL("found heads of branch %s (%s heads)") + % uid % branch.second.size()); + } } void -project_t::get_branch_heads(branch_name const & name, - set & heads, +project_t::get_branch_heads(branch_uid const & uid, + std::set const & signers, + std::set & heads, bool ignore_suspend_certs, - multimap * inverse_graph_cache_ptr) + std::multimap *inverse_graph_cache_ptr) { - pair - cache_index(name, ignore_suspend_certs); + branch_heads_key cache_index(uid, ignore_suspend_certs, signers, true); + pair > & branch = branch_heads[cache_index]; - if (branch.first.outdated()) - { - L(FL("getting heads of branch %s") % name); + do_get_branch_heads(branch, *this, uid, &signers, + ignore_suspend_certs, + inverse_graph_cache_ptr); - branch_uid uid; - set signers; - if (project_policy->passthru) - uid = typecast_vocab(name); - else - { - project_policy->lookup_branch(name, uid, signers); - } + heads = branch.second; +} - branch.first = db.get_revisions_with_cert(cert_name(branch_cert_name), - typecast_vocab(uid), - branch.second); - shared_ptr p; - if (project_policy->passthru) - p.reset(new not_in_branch(*this, uid)); - else - p.reset(new not_in_branch(*this, uid, signers)); +void +project_t::get_branch_heads(branch_name const & name, + set & heads, + bool ignore_suspend_certs, + multimap * inverse_graph_cache_ptr) +{ + branch_uid uid; + set signers; + set *sign_ptr = 0; + if (project_policy->passthru) + uid = typecast_vocab(name); + else + { + project_policy->lookup_branch(name, uid, signers); + sign_ptr = &signers; + } - erase_ancestors_and_failures(db, branch.second, *p, - inverse_graph_cache_ptr); + branch_heads_key cache_index(uid, ignore_suspend_certs, signers, sign_ptr); - if (!ignore_suspend_certs) - { - shared_ptr s; - if (project_policy->passthru) - s.reset(new suspended_in_branch(*this, uid)); - else - s.reset(new suspended_in_branch(*this, uid, signers)); - set::iterator it = branch.second.begin(); - while (it != branch.second.end()) - { - if ((*s)(*it)) - branch.second.erase(it++); - else - it++; - } - } + pair > & + branch = branch_heads[cache_index]; + do_get_branch_heads(branch, *this, uid, sign_ptr, + ignore_suspend_certs, + inverse_graph_cache_ptr); - - L(FL("found heads of branch %s (%s heads)") - % name % branch.second.size()); - } heads = branch.second; } @@ -914,7 +975,9 @@ project_t::put_tag(key_store & keys, F("Cannot find policy for tag '%s'") % name); E(info.back().delegation.is_branch_type(), origin::user, F("Cannot edit '%s', it is delegated to a specific revision") % name); - policies::policy_branch br(info.back().delegation.get_branch_spec()); + policies::policy_branch br(*this, + info.back().policy, + info.back().delegation.get_branch_spec()); I(br.begin() != br.end()); policies::editable_policy ep(**br.begin()); ============================================================ --- project.hh 17810c296afb72c1a8de0ac154e147c3418aa4f5 +++ project.hh 2375749bafc6d8f9adcf56b4f46470f84e9193d7 @@ -18,6 +18,7 @@ //#include "editable_policy.hh" #include "outdated_indicator.hh" #include "policies/delegation.hh" +#include "vector.hh" #include "vocab.hh" class arg_type; @@ -88,6 +89,21 @@ typedef std::vector p typedef std::vector policy_chain; +class branch_heads_key +{ +public: + branch_uid uid; + bool ignore_suspends; + std::set keys; + bool have_signers; + branch_heads_key(branch_uid const & uid, + bool ignore_suspends, + std::set const & keys, + bool have_signers); +}; +bool operator<(branch_heads_key const & a, + branch_heads_key const & b); + class project_t { // In the hypothetical future situation where one monotone process is @@ -101,7 +117,7 @@ private: private: boost::shared_ptr project_policy; - std::map, + std::map > > branch_heads; std::set branches; @@ -132,6 +148,14 @@ public: branch_uid translate_branch(branch_name const & branch); branch_name translate_branch(branch_uid const & branch); + // internal for policy stuff + void get_branch_heads(branch_uid const & uid, + std::set const & signers, + std::set & heads, + bool ignore_suspend_certs, + std::multimap *inverse_graph_cache_ptr = NULL); + + void get_branch_heads(branch_name const & name, std::set & heads, bool ignore_suspend_certs,