#
#
# add_file "cmd_policy.cc"
# content [e3e698c544f61dc2ab58549e7264c0d896d56f29]
#
# patch "Makefile.am"
# from [fbd8a4f969f93fad2158db91ca84782b0665f7f8]
# to [316032f4d02341483858c5941473bdf59405c6ae]
#
# patch "project.cc"
# from [56f1dc381dc621eb41d1d45414f65102667b0742]
# to [a87d6e320fea8da287442b9af2d999e34ff1e030]
#
============================================================
--- cmd_policy.cc e3e698c544f61dc2ab58549e7264c0d896d56f29
+++ cmd_policy.cc e3e698c544f61dc2ab58549e7264c0d896d56f29
@@ -0,0 +1,180 @@
+// Copyright 2008 Timothy Brownawell
+//
+// This file is made available under the GNU GPL v2 or later.
+
+#include "base.hh"
+
+#include "app_state.hh"
+#include "basic_io.hh"
+#include "botan/botan.h"
+#include "cmd.hh"
+#include "dates.hh"
+#include "file_io.hh"
+#include "revision.hh"
+#include "roster.hh"
+#include "transforms.hh"
+
+CMD_GROUP(policy, "policy", "", CMD_REF(__root__),
+ N_("Commands that deal with policy branches."),
+ "");
+
+namespace basic_io
+{
+ namespace syms
+ {
+ symbol const branch_uid("branch_uid");
+ symbol const committer("committer");
+ }
+}
+
+namespace {
+ std::string
+ generate_uid()
+ {
+ // FIXME: I'm sure there's a better way to do this.
+ std::string when = date_t::now().as_iso_8601_extended();
+ char buf[20];
+ Botan::Global_RNG::randomize(reinterpret_cast(buf), 20);
+ return when + "--" + encode_hexenc(std::string(buf, 20));
+ }
+
+ void
+ write_branch_policy(data & dat,
+ std::string const & branch_uid,
+ std::set const & committers)
+ {
+ basic_io::printer printer;
+ basic_io::stanza st;
+ st.push_str_pair(basic_io::syms::branch_uid, branch_uid);
+ for (std::set::const_iterator i = committers.begin();
+ i != committers.end(); ++i)
+ {
+ st.push_str_pair(basic_io::syms::committer, (*i)());
+ }
+ printer.print_stanza(st);
+ dat = data(printer.buf);
+ }
+ void
+ write_branch_policy(data & dat,
+ std::string const & branch_uid,
+ rsa_keypair_id const & committer)
+ {
+ std::set committers;
+ committers.insert(committer);
+ write_branch_policy(dat, branch_uid, committers);
+ }
+
+ // Generate a revision with a single file, branches/__policy__,
+ // and put it in a new branch which is referenced by that file.
+ void
+ create_policy_branch(database & db, key_store & keys,
+ lua_hooks & lua, options & opts,
+ branch_prefix const & policy_name,
+ std::set const & administrators,
+ std::string & policy_uid, data & spec)
+ {
+ rsa_keypair_id key;
+ get_user_key(key, keys, db);
+
+ policy_uid = generate_uid();
+ transaction_guard guard(db);
+
+
+ // spec file
+ file_id spec_id;
+ write_branch_policy(spec, policy_uid, administrators);
+ file_data spec_data(spec);
+ calculate_ident(spec_data, spec_id);
+
+ cset cs;
+ cs.dirs_added.insert(file_path_internal(""));
+ cs.dirs_added.insert(file_path_internal("branches"));
+ cs.files_added.insert(std::make_pair(file_path_internal("branches/__policy__"),
+ spec_id));
+ roster_t old_roster;
+ revision_t rev;
+ make_revision(revision_id(), old_roster, cs, rev);
+ revision_id rev_id;
+ calculate_ident(rev, rev_id);
+ revision_data rdat;
+ write_revision(rev, rdat);
+
+
+ // write to the db
+ if (!db.file_version_exists(spec_id))
+ {
+ db.put_file(spec_id, spec_data);
+ }
+ db.put_revision(rev_id, rdat);
+
+
+ // add certs
+ // Do not use project_t::put_standard_certs here, we don't want the
+ // branch name to be translated!
+ date_t date;
+ if (opts.date_given)
+ date = opts.date;
+ else
+ date = date_t::now();
+
+ std::string author = opts.author();
+ if (author.empty())
+ {
+ if (!lua.hook_get_author(branch_name(policy_name() + ".__policy__"),
+ key, author))
+ author = key();
+ }
+ utf8 changelog(N_("Create new policy branch."));
+
+ cert_revision_in_branch(rev_id, branch_uid(policy_uid), db, keys);
+ cert_revision_changelog(rev_id, changelog, db, keys);
+ cert_revision_date_time(rev_id, date, db, keys);
+ cert_revision_author(rev_id, author, db, keys);
+
+
+ guard.commit();
+ P(F("Created new policy branch with id '%s'") % policy_uid);
+ }
+}
+
+CMD(create_project, "create_project", "", CMD_REF(policy),
+ N_("NAME"),
+ N_("Bootstrap creation of a new project."),
+ N_(""),
+ options::opts::none)
+{
+ N(args.size() == 1,
+ F("Wrong argument count."));
+ std::string project_name = idx(args, 0)();
+ system_path project_dir = app.opts.conf_dir / "projects";
+ system_path project_file = project_dir / path_component(project_name);
+
+ require_path_is_directory(app.opts.conf_dir,
+ F("Cannot find configuration directory."),
+ F("Configuration directory is a file."));
+ require_path_is_nonexistent(project_file,
+ F("You already have a project with that name."));
+ mkdir_p(project_dir);
+
+ rsa_keypair_id key;
+ get_user_key(key, app.keys, app.db);
+ std::set admin_keys;
+ admin_keys.insert(key);
+
+ std::string policy_uid;
+ data policy_spec;
+ create_policy_branch(app.db, app.keys, app.lua, app.opts,
+ branch_prefix(project_name), admin_keys,
+ policy_uid, policy_spec);
+
+ write_data(project_file, policy_spec, project_dir);
+ P(F("Wrote project spec to %s") % project_file);
+}
+
+CMD(create_subpolicy, "create_subpolicy", "", CMD_REF(policy),
+ N_("NAME"),
+ N_("Create a policy for a new subtree of an existing project."),
+ "",
+ options::opts::none)
+{
+}
============================================================
--- Makefile.am fbd8a4f969f93fad2158db91ca84782b0665f7f8
+++ Makefile.am 316032f4d02341483858c5941473bdf59405c6ae
@@ -1,10 +1,10 @@ CMD_SOURCES = \
AUTOMAKE_OPTIONS=subdir-objects 1.7.1
ACLOCAL_AMFLAGS = -I m4
CMD_SOURCES = \
cmd.hh cmd_netsync.cc cmd_list.cc cmd_packet.cc cmd_key_cert.cc \
cmd_merging.cc cmd_db.cc cmd_diff_log.cc cmd_ws_commit.cc \
- cmd_othervcs.cc cmd_automate.cc cmd_files.cc
+ cmd_othervcs.cc cmd_automate.cc cmd_files.cc cmd_policy.cc
SANITY_CORE_SOURCES = \
sanity.cc sanity.hh quick_alloc.hh vector.hh base.hh \
============================================================
--- project.cc 56f1dc381dc621eb41d1d45414f65102667b0742
+++ project.cc a87d6e320fea8da287442b9af2d999e34ff1e030
@@ -30,8 +30,6 @@ namespace basic_io
{
symbol const branch_uid("branch_uid");
symbol const committer("committer");
- symbol const policy("policy_branch_id");
- symbol const administrator("administrator");
}
}
@@ -68,14 +66,14 @@ class policy_branch
while (pa.symp())
{
- if(pa.symp(basic_io::syms::policy))
+ if(pa.symp(basic_io::syms::branch_uid))
{
pa.sym();
string branch;
pa.str(branch);
my_branch_cert_value = branch_uid(branch);
}
- else if (pa.symp(basic_io::syms::administrator))
+ else if (pa.symp(basic_io::syms::committer))
{
pa.sym();
string key;
@@ -251,9 +249,10 @@ namespace
}
};
- revision_id policy_branch_head(branch_uid const & name,
- set const & trusted_signers,
- database & db)
+ 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;
@@ -267,11 +266,18 @@ namespace
not_in_policy_branch p(db, branch_encoded, trusted_signers);
erase_ancestors_and_failures(heads, p, db, NULL);
- E(heads.size() == 1,
- F("policy branch %s has %d heads, should have 1 head")
- % name % heads.size());
-
- return *heads.begin();
+ 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;
+ }
}
}
@@ -281,15 +287,23 @@ shared_ptr policy_branc
if (!rev)
{
revision_id rid;
- rid = policy_branch_head(my_branch_cert_value, my_committers, db);
- rev.reset(new policy_revision(db, rid, prefix));
+ 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();
- return policy->all_branches();
+ if (policy)
+ {
+ return policy->all_branches();
+ }
+ else
+ return map();
}
////////////////////////////////////////////////////////////////////////