# # # add_file "editable_policy.cc" # content [3545edd983f18f4c77385297b4d3dd504e54534d] # # add_file "editable_policy.hh" # content [a49c2cc57a5404f185f07bee9146ad39cc9c7e6e] # # patch "Makefile.am" # from [472a60f240fed973f568dacdc2e021ab308fb5d3] # to [e34653be6ef8567dce94969bcd2485ab6f5e53b4] # # patch "cmd_policy.cc" # from [68eafd64425fd1b26a6a1b03d1aebd9d83c9d4c5] # to [bd8d8bddfa2e6fa840bafe44732b4cf00e7c440b] # # patch "project.cc" # from [f71cf08b34243e21b67ae02934736c7dd9612150] # to [319b71ee6f05f67d52deb90870b6753f3ca07442] # # patch "project.hh" # from [3f2cb4af25501bef9d91c87b4318b9ac3e5be11a] # to [fa7c27b6f3d64d5d47985123ec5ea2bc66cf4184] # ============================================================ --- editable_policy.cc 3545edd983f18f4c77385297b4d3dd504e54534d +++ editable_policy.cc 3545edd983f18f4c77385297b4d3dd504e54534d @@ -0,0 +1,609 @@ +// Copyright 2008 Timothy Brownawell +// +// This program is made available under the GNU GPL version 2.0 or +// greater. See the accompanying file COPYING for details. + +#include "base.hh" +#include "editable_policy.hh" + +#include +#include +#include + +#include +#include + +#include "basic_io.hh" +#include "botan/botan.h" +#include "database.hh" +#include "key_store.hh" +#include "outdated_indicator.hh" +#include "paths.hh" +#include "policy.hh" +#include "revision.hh" +#include "roster.hh" +#include "transforms.hh" + +using std::string; +using std::set; +using std::map; +using std::make_pair; +using std::vector; + +using boost::shared_ptr; + +using boost::multi_index::multi_index_container; +using boost::multi_index::indexed_by; +using boost::multi_index::ordered_non_unique; +using boost::multi_index::tag; +using boost::multi_index::member; + + +namespace basic_io +{ + namespace syms + { + symbol const branch_uid("branch_uid"); + symbol const committer("committer"); + symbol const revision_id("revision_id"); + } +} + +namespace { + branch_uid + 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 branch_uid(when + "--" + encode_hexenc(std::string(buf, 20))); + } + + template + struct thing_info + { + typedef Value item_type; + string old_name; + string new_name; + //Value old_value; + shared_ptr new_value; + }; + + //struct original {}; + struct current {}; + + template + struct thing_holder + { + typedef thing_info info_type; + typedef multi_index_container< + info_type, + indexed_by< + ordered_non_unique< + tag, + member + >/*, + ordered_non_unique< + tag, + member + >*/ + > + > container; + class rename + { + string new_name; + public: + rename(string const & nn) : new_name(nn) {} + void operator()(info_type & it) { it.new_name = new_name; } + }; + //typedef typename container::template index::type by_original; + typedef typename container::template index::type by_current; + }; + typedef thing_holder tag_holder; + typedef thing_holder branch_holder; + typedef thing_holder delegation_holder; +} + +class editable_policy_impl +{ +public: + database & db; + editable_policy_impl(database & db) + : db(db) + {} + + revision_id old_rev_id; + roster_t old_roster; + + map files; + revision_data new_revision; + + tag_holder::container tags; + branch_holder::container branches; + delegation_holder::container delegations; +}; + +editable_policy::editable_policy(database & db, + set const & admins) + : impl(new editable_policy_impl(db)), uid(generate_uid()) +{ + branch_holder::info_type self; + self.new_name = "__policy__"; + self.new_value.reset(new branch()); + self.new_value->uid = uid; + self.new_value->committers = admins; + impl->branches.insert(self); +} + +namespace { + template void + load_itemtype(T & cont, + roster_t const & ros, + file_path const & dir_name, + database & db) + { + if (!ros.has_node(dir_name)) + return; + node_t n = ros.get_node(dir_name); + if (!is_dir_t(n)) + return; + dir_t dir = downcast_to_dir_t(n); + for (dir_map::const_iterator i = dir->children.begin(); + i != dir->children.end(); ++i) + { + if (!is_file_t(i->second)) + continue; + file_t item = downcast_to_file_t(i->second); + file_data fdat; + db.get_file_version(item->content, fdat); + typename T::value_type info; + info.old_name = i->first(); + info.new_name = i->first(); + info.new_value.reset(new typename T::value_type::item_type()); + info.new_value->read(fdat.inner()); + } + } + void + load_policy(shared_ptr impl) + { + load_itemtype(impl->tags, + impl->old_roster, + file_path_internal("tags"), + impl->db); + load_itemtype(impl->branches, + impl->old_roster, + file_path_internal("branches"), + impl->db); + load_itemtype(impl->delegations, + impl->old_roster, + file_path_internal("delegations"), + impl->db); + } +} + +editable_policy::editable_policy(database & db, + revision_id const & rev) + : impl(new editable_policy_impl(db)) +{ + vector > certs; + impl->db.get_revision_certs(rev, branch_cert_name, certs); + erase_bogus_certs(db, certs); + if (certs.size() == 1) + { + uid = branch_uid(idx(certs,0).inner().value()); + } + + impl->old_rev_id = rev; + impl->db.get_roster(rev, impl->old_roster); + load_policy(impl); +} + +editable_policy::editable_policy(database & db, + branch_policy const & policy_policy) + : impl(new editable_policy_impl(db)) +{ + uid = policy_policy.branch_cert_value; + set heads; + get_branch_heads(policy_policy, false, db, heads, NULL); + E(heads.size() == 1, + F("Policy branch %s does not have exactly 1 head") + % policy_policy.branch_cert_value); + impl->old_rev_id = *heads.begin(); + impl->db.get_roster(impl->old_rev_id, impl->old_roster); + load_policy(impl); +} + + +void +editable_policy::tag::write(data & dat) +{ + basic_io::printer printer; + basic_io::stanza st; + hexenc enc; + encode_hexenc(rev.inner(), enc); + st.push_hex_pair(basic_io::syms::revision_id, enc); + printer.print_stanza(st); + dat = data(printer.buf); +} + +void +editable_policy::tag::read(data const & dat) +{ + basic_io::input_source src(dat(), "tag"); + basic_io::tokenizer tok(src); + basic_io::parser pa(tok); + while (pa.symp()) + { + if (pa.symp(basic_io::syms::revision_id)) + { + pa.sym(); + string rid; + pa.hex(rid); + rev = revision_id(decode_hexenc(rid)); + } + else + { + E(false, F("bad tag spec")); + } + } + I(src.lookahead == EOF); +} + +void +editable_policy::branch::write(data & dat) +{ + basic_io::printer printer; + basic_io::stanza st; + st.push_str_pair(basic_io::syms::branch_uid, 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 +editable_policy::branch::read(data const & dat) +{ + basic_io::input_source src(dat(), "policy 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); + uid = 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 + { + E(false, F("Unable to understand delegation")); + } + } +} + +void +editable_policy::delegation::write(data & dat) +{ + basic_io::printer printer; + basic_io::stanza st; + + // must have only one or the other + I(uid().empty() != null_id(rev)); + if (null_id(rev)) + { + st.push_str_pair(basic_io::syms::branch_uid, uid()); + for (std::set::const_iterator i = committers.begin(); + i != committers.end(); ++i) + { + st.push_str_pair(basic_io::syms::committer, (*i)()); + } + } + else + { + hexenc enc; + encode_hexenc(rev.inner(), enc); + st.push_hex_pair(basic_io::syms::revision_id, enc); + } + + printer.print_stanza(st); + dat = data(printer.buf); +} + +void +editable_policy::delegation::read(data const & dat) +{ + bool seen_revid = false; + bool seen_branchspec = false; + + basic_io::input_source src(dat(), "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); + uid = branch_uid(branch); + } + else if (pa.symp(basic_io::syms::committer)) + { + seen_branchspec = true; + pa.sym(); + string key; + pa.str(key); + 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 = revision_id(decode_hexenc(rid)); + } + else + { + E(false, F("Unable to understand delegation")); + } + } + + I(src.lookahead == EOF); + + E(seen_revid || seen_branchspec, + F("Delegation file seems to be empty")); + + E(seen_revid != seen_branchspec, + F("Delegation file contains both a revision id and a branch spec")); +} + +namespace { + template + void extract_changes(T const & cont, + roster_t const & old_roster, + cset & changes, + map & files, + string const & name) + { + file_path dir = file_path_internal(name); + bool have_dir = old_roster.has_node(dir); + for (typename T::const_iterator i = cont.begin(); + i != cont.end(); ++i) + { + file_path old_path; + if (!i->old_name.empty()) + old_path = dir / path_component(i->old_name); + file_path new_path; + if (!i->new_name.empty()) + { + new_path = dir / path_component(i->new_name); + if (!have_dir) + { + have_dir = true; + changes.dirs_added.insert(dir); + } + } + file_data new_fdat; + file_id new_fid; + file_id old_fid; + if (!i->new_name.empty()) + { + if (!i->old_name.empty()) + { + node_t n = old_roster.get_node(old_path); + file_t f = downcast_to_file_t(n); + old_fid = f->content; + } + data dat; + i->new_value->write(dat); + new_fdat = file_data(dat); + calculate_ident(new_fdat, new_fid); + files.insert(make_pair(new_fid, new_fdat)); + } + + if (i->new_name.empty()) + changes.nodes_deleted.insert(old_path); + else if (i->old_name.empty()) + changes.files_added.insert(make_pair(new_path, new_fid)); + else + { + if (i->old_name != i->new_name) + changes.nodes_renamed.insert(make_pair(old_path, new_path)); + if (new_fid != old_fid) + changes.deltas_applied.insert(make_pair(new_path, + make_pair(old_fid, + new_fid))); + } + } + } +} + +revision_id +editable_policy::calculate_id() +{ + impl->files.clear(); + cset changes; + if (!impl->old_roster.has_root()) + changes.dirs_added.insert(file_path_internal("")); + + extract_changes(impl->tags, impl->old_roster, + changes, impl->files, "tags"); + extract_changes(impl->branches, impl->old_roster, + changes, impl->files, "branches"); + extract_changes(impl->delegations, impl->old_roster, + changes, impl->files, "delegations"); + + revision_t rev; + make_revision(impl->old_rev_id, impl->old_roster, + changes, rev); + write_revision(rev, impl->new_revision); + revision_id rid; + calculate_ident(impl->new_revision, rid); + return rid; +} + +revision_id +editable_policy::commit(key_store & keys, + lua_hooks & lua, + utf8 const & changelog, + string author) +{ + revision_id new_id = calculate_id(); + transaction_guard guard(impl->db); + + for (map::const_iterator i = impl->files.begin(); + i != impl->files.end(); ++i) + { + if (!impl->db.file_version_exists(i->first)) + impl->db.put_file(i->first, i->second);//FIXME + } + impl->db.put_revision(new_id, impl->new_revision); + + if (author.empty()) + author = keys.signing_key(); + cert_revision_date_time(impl->db, keys, new_id, date_t::now()); + cert_revision_changelog(impl->db, keys, new_id, changelog); + cert_revision_author(impl->db, keys, new_id, author); + cert_revision_in_branch(impl->db, keys, new_id, uid); + + guard.commit(); + return new_id; +} + +void +editable_policy::get_spec(data & dat) +{ + shared_ptr spec = get_branch("__policy__"); + spec->write(dat); +} + + +void +editable_policy::remove_delegation(string const & name) +{ + delegation_holder::by_current::iterator i = impl->delegations.find(name); + if (i != impl->delegations.end()) + impl->delegations.erase(i); +} + +void +editable_policy::remove_branch(string const & name) +{ + branch_holder::by_current::iterator i = impl->branches.find(name); + if (i != impl->branches.end()) + impl->branches.erase(i); +} + +void +editable_policy::remove_tag(string const & name) +{ + tag_holder::by_current::iterator i = impl->tags.find(name); + if (i != impl->tags.end()) + impl->tags.erase(i); +} + + +void +editable_policy::rename_delegation(string const & from, + string const & to) +{ + delegation_holder::by_current::iterator i = impl->delegations.find(from); + if (i != impl->delegations.end()) + { + if (impl->delegations.find(to) != impl->delegations.end()) + { + impl->delegations.modify(i, delegation_holder::rename(to)); + } + } +} + +void +editable_policy::rename_branch(string const & from, + string const & to) +{ + branch_holder::by_current::iterator i = impl->branches.find(from); + if (i != impl->branches.end()) + { + if (impl->branches.find(to) != impl->branches.end()) + { + impl->branches.modify(i, branch_holder::rename(to)); + } + } +} + +void +editable_policy::rename_tag(string const & from, + string const & to) +{ + tag_holder::by_current::iterator i = impl->tags.find(from); + if (i != impl->tags.end()) + { + if (impl->tags.find(to) != impl->tags.end()) + { + impl->tags.modify(i, tag_holder::rename(to)); + } + } +} + + +shared_ptr +editable_policy::get_delegation(string const & name, bool create) +{ + delegation_holder::by_current::iterator i = impl->delegations.find(name); + if (i != impl->delegations.end()) + return i->new_value; + if (!create) + return shared_ptr(); + delegation_holder::info_type item; + item.new_name = name; + item.new_value.reset(new delegation()); + impl->delegations.insert(item); + return item.new_value; +} + +shared_ptr +editable_policy::get_branch(string const & name, bool create) +{ + branch_holder::by_current::iterator i = impl->branches.find(name); + if (i != impl->branches.end()) + return i->new_value; + if (!create) + return shared_ptr(); + branch_holder::info_type item; + item.new_name = name; + item.new_value.reset(new branch()); + impl->branches.insert(item); + return item.new_value; +} + +shared_ptr +editable_policy::get_tag(string const & name, bool create) +{ + tag_holder::by_current::iterator i = impl->tags.find(name); + if (i != impl->tags.end()) + return i->new_value; + if (!create) + return shared_ptr(); + tag_holder::info_type item; + item.new_name = name; + item.new_value.reset(new tag()); + impl->tags.insert(item); + return item.new_value; +} ============================================================ --- editable_policy.hh a49c2cc57a5404f185f07bee9146ad39cc9c7e6e +++ editable_policy.hh a49c2cc57a5404f185f07bee9146ad39cc9c7e6e @@ -0,0 +1,92 @@ +#ifndef __EDITABLE_POLICY_HH__ +#define __EDITABLE_POLICY_HH__ + +// Copyright 2008 Timothy Brownawell +// +// This program is made available under the GNU GPL version 2.0 or +// greater. See the accompanying file COPYING for details. + +// This files defines higher-level editing operations on +// policy-branch revisions. + +#include +#include + +#include "vocab.hh" + +class branch_policy; +class database; +class key_store; +class lua_hooks; + +class editable_policy_impl; +class editable_policy +{ + boost::shared_ptr impl; +public: + branch_uid uid; + + class tag + { + public: + revision_id rev; + void write(data & dat); + void read(data const & dat); + }; + class branch + { + public: + branch_uid uid; + std::set committers; + void write(data & dat); + void read(data const & dat); + }; + class delegation + { + public: + revision_id rev; + branch_uid uid; + std::set committers; + void write(data & dat); + void read(data const & dat); + }; + + // Create a new policy. + editable_policy(database & db, + std::set const & admins); + // Edit an existing policy. If the existing policy is not in + // exactly one branch, you will have to populate the uid field + // before calling commit(). + editable_policy(database & db, revision_id const & rev); + // Edit an existing policy branch. This will fail if the branch + // doesn't have exactly one head. + editable_policy(database & db, branch_policy const & policy_policy); + + revision_id commit(key_store & keys, + lua_hooks & lua, + utf8 const & changelog, + std::string author = ""); + revision_id calculate_id(); + void get_spec(data & dat); + + + void remove_delegation(std::string const & name); + void remove_branch(std::string const & name); + void remove_tag(std::string const & name); + + void rename_delegation(std::string const & from, std::string const & to); + void rename_branch(std::string const & from, std::string const & to); + void rename_tag(std::string const & from, std::string const & to); + + + boost::shared_ptr + get_delegation(std::string const & name, bool create = false); + + boost::shared_ptr + get_branch(std::string const & name, bool create = false); + + boost::shared_ptr + get_tag(std::string const & name, bool create = false); +}; + +#endif ============================================================ --- Makefile.am 472a60f240fed973f568dacdc2e021ab308fb5d3 +++ Makefile.am e34653be6ef8567dce94969bcd2485ab6f5e53b4 @@ -35,6 +35,7 @@ MOST_SOURCES = \ work.cc work_migration.cc work.hh \ cert.cc cert.hh \ policy.cc policy.hh \ + editable_policy.cc editable_policy.hh \ project.cc project.hh \ outdated_indicator.cc outdated_indicator.hh \ database.cc database.hh \ ============================================================ --- cmd_policy.cc 68eafd64425fd1b26a6a1b03d1aebd9d83c9d4c5 +++ cmd_policy.cc bd8d8bddfa2e6fa840bafe44732b4cf00e7c440b @@ -11,6 +11,7 @@ #include "botan/botan.h" #include "cmd.hh" #include "dates.hh" +#include "editable_policy.hh" #include "file_io.hh" #include "keys.hh" #include "key_store.hh" @@ -24,124 +25,9 @@ CMD_GROUP(policy, "policy", "", CMD_REF( N_("Commands that deal with policy branches."), ""); -namespace basic_io -{ - namespace syms - { - symbol const branch_uid("branch_uid"); - symbol const committer("committer"); - } -} +using boost::shared_ptr; +using std::string; -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) - { - cache_user_key(opts, lua, db, keys); - - 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__"), - keys.signing_key, author)) - author = keys.signing_key(); - } - utf8 changelog(N_("Create new policy branch.")); - - cert_revision_in_branch(db, keys, rev_id, branch_uid(policy_uid)); - cert_revision_changelog(db, keys, rev_id, changelog); - cert_revision_date_time(db, keys, rev_id, date); - cert_revision_author(db, keys, rev_id, author); - - - 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."), @@ -171,9 +57,9 @@ CMD(create_project, "create_project", "" std::string policy_uid; data policy_spec; - create_policy_branch(db, keys, app.lua, app.opts, - branch_prefix(project_name), admin_keys, - policy_uid, policy_spec); + editable_policy ep(db, admin_keys); + ep.get_branch("__policy__")->write(policy_spec); + ep.commit(keys, app.lua, utf8(N_("Create new policy branch"))); write_data(project_file, policy_spec, project_dir); P(F("Wrote project spec to %s") % project_file); @@ -206,92 +92,22 @@ CMD(create_subpolicy, "create_subpolicy" 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 the new policy branch. - 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); - // Delegate to it in the parent policy branch. - policy_changes.files_added.insert(std::make_pair(delegation_file, - child_spec_id)); + editable_policy parent(db, policy_policy); + editable_policy child(db, admin_keys); + shared_ptr + del = parent.get_delegation(subprefix, true); + del->uid = child.uid; + del->committers = admin_keys; - revision_t policy_new_revision; - make_revision(policy_old_rev_id, - policy_old_roster, - policy_changes, - policy_new_revision); - - { - revision_id rev_id; - calculate_ident(policy_new_revision, rev_id); - revision_data rdat; - write_revision(policy_new_revision, rdat); - - - // write to the db - if (!db.file_version_exists(child_spec_id)) - { - db.put_file(child_spec_id, child_file_dat); - } - 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 (app.opts.date_given) - date = app.opts.date; - else - date = date_t::now(); - - std::string author = app.opts.author(); - if (author.empty()) - { - if (!app.lua.hook_get_author(branch_name(prefix() + ".__policy__"), - keys.signing_key, author)) - author = keys.signing_key(); - } - utf8 changelog(N_("Create new policy branch.")); - - cert_revision_in_branch(db, keys, rev_id, - branch_uid(policy_policy.branch_cert_value)); - cert_revision_changelog(db, keys, rev_id, changelog); - cert_revision_date_time(db, keys, rev_id, date); - cert_revision_author(db, keys, rev_id, author); - } - + transaction_guard guard(db); + child.commit(keys, app.lua, utf8(N_("Create new policy branch"))); + parent.commit(keys, app.lua, utf8(N_("Add new delegation"))); + guard.commit(); } @@ -322,83 +138,19 @@ CMD(create_branch, "create_branch", "", if (relative_name.empty()) relative_name = "__main__"; - - std::set policy_heads; - get_branch_heads(parent_policy, false, db, policy_heads, NULL); - N(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 branch_dir = file_path_internal("branches"); - file_path branch_file = branch_dir / path_component(relative_name); - N(!policy_old_roster.has_node(branch_file), - F("A branch %s already exists under policy %s") - % relative_name % parent_prefix); - - cset policy_changes; - if (!policy_old_roster.has_node(branch_dir)) - { - policy_changes.dirs_added.insert(branch_dir); - } - cache_user_key(app.opts, app.lua, db, keys); std::set admin_keys; admin_keys.insert(keys.signing_key); - std::string branch_uid = generate_uid(); - data branch_spec; - write_branch_policy(branch_spec, branch_uid, admin_keys); + editable_policy parent(db, parent_policy); + shared_ptr + br = parent.get_branch(relative_name); + N(!br, F("A branch %s already exists under policy %s") + % relative_name % parent_prefix); + br = parent.get_branch(relative_name, true); - file_id branch_spec_id; - file_data branch_spec_dat(branch_spec); - calculate_ident(branch_spec_dat, branch_spec_id); - - policy_changes.files_added.insert(std::make_pair(branch_file, branch_spec_id)); - - revision_t policy_new_revision; - make_revision(policy_old_rev_id, - policy_old_roster, - policy_changes, - policy_new_revision); - - revision_id rev_id; - calculate_ident(policy_new_revision, rev_id); - revision_data rdat; - write_revision(policy_new_revision, rdat); - - - transaction_guard guard(db); - - if (!db.file_version_exists(branch_spec_id)) - db.put_file(branch_spec_id, branch_spec_dat); - db.put_revision(rev_id, rdat); - - // project_t::put_standard_certs would translate the branch name, - // which wouldn't work - date_t date; - if (app.opts.date_given) - date = app.opts.date; - else - date = date_t::now(); - - std::string author = app.opts.author(); - if (author.empty()) - { - if (!app.lua.hook_get_author(branch_name(parent_prefix() + ".__policy"), - keys.signing_key, author)) - author = keys.signing_key(); - } - utf8 changelog(N_("Declare new branch.")); - - cert_revision_in_branch(db, keys, rev_id, - parent_policy.branch_cert_value); - cert_revision_changelog(db, keys, rev_id, changelog); - cert_revision_date_time(db, keys, rev_id, date); - cert_revision_author(db, keys, rev_id, author); - - guard.commit(); + parent.commit(keys, app.lua, utf8(N_("Declare new branch"))); } CMD_FWD_DECL(list); ============================================================ --- project.cc f71cf08b34243e21b67ae02934736c7dd9612150 +++ project.cc 319b71ee6f05f67d52deb90870b6753f3ca07442 @@ -543,16 +543,22 @@ project_t::get_tags(set & tags) outdated_indicator project_t::get_tags(set & tags) { - std::vector > certs; - outdated_indicator i = db.get_revision_certs(tag_cert_name, certs); - erase_bogus_certs(db, certs); - tags.clear(); - for (std::vector >::const_iterator i = certs.begin(); - i != certs.end(); ++i) - tags.insert(tag_t(revision_id(i->inner().ident), - utf8(i->inner().value()), i->inner().key)); + if (project_policy->passthru) + { + std::vector > certs; + outdated_indicator i = db.get_revision_certs(tag_cert_name, certs); + erase_bogus_certs(db, certs); + tags.clear(); + for (std::vector >::const_iterator i = certs.begin(); + i != certs.end(); ++i) + tags.insert(tag_t(revision_id(i->inner().ident), + utf8(i->inner().value()), i->inner().key)); - return i; + return i; + } + else + { + } } void @@ -560,7 +566,11 @@ project_t::put_tag(key_store & keys, revision_id const & id, string const & name) { - cert_revision_tag(db, keys, id, name); + if (project_policy->passthru) + cert_revision_tag(db, keys, id, name); + else + { + } } ============================================================ --- project.hh 3f2cb4af25501bef9d91c87b4318b9ac3e5be11a +++ project.hh fa7c27b6f3d64d5d47985123ec5ea2bc66cf4184 @@ -24,7 +24,9 @@ public: revision_id const ident; utf8 const name; rsa_keypair_id const key; - tag_t(revision_id const & ident, utf8 const & name, rsa_keypair_id const & key); + tag_t(revision_id const & ident, + utf8 const & name, + rsa_keypair_id const & key); }; bool operator < (tag_t const & a, tag_t const & b); @@ -81,14 +83,18 @@ public: branch_uid translate_branch(branch_name const & branch); branch_name translate_branch(branch_uid const & branch); - void get_branch_heads(branch_name const & name, std::set & heads, + void get_branch_heads(branch_name const & name, + std::set & heads, bool ignore_suspend_certs, std::multimap *inverse_graph_cache_ptr = NULL); outdated_indicator get_tags(std::set & tags); - void put_tag(key_store & keys, revision_id const & id, std::string const & name); + void put_tag(key_store & keys, + revision_id const & id, + std::string const & name); - bool revision_is_in_branch(revision_id const & id, branch_name const & branch); + bool revision_is_in_branch(revision_id const & id, + branch_name const & branch); void put_revision_in_branch(key_store & keys, revision_id const & id, branch_name const & branch);