#
#
# 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