# # # patch "app_state.cc" # from [999fb28f8ca750e3549adfd287b60c715380776a] # to [71ea30d66db2bed19870d893a62d0877da5fa47d] # # patch "options_list.hh" # from [5ee94e644545cd8550638c47113655d8022d78c8] # to [14c08437ac574e16befd4d8df9408368f5bbab55] # # patch "project.cc" # from [5d3ae7981240fe8b8e5ce5807d6f8f213ca13d3f] # to [270d69f5891c8949ca0bd5149d1a2acc6d236b5a] # # patch "project.hh" # from [ff88cd736651c2a719fd9bd077a31baa136b0cd8] # to [c2e794b47c13c23822e7edbf92250e4b5358f532] # # patch "tests/policy-basic/__driver__.lua" # from [a0d76df86e7eba065e24a3edb427bf3d828dbbea] # to [93a00f0043ffc206da000997587303011189c364] # ============================================================ --- app_state.cc 999fb28f8ca750e3549adfd287b60c715380776a +++ app_state.cc 71ea30d66db2bed19870d893a62d0877da5fa47d @@ -55,7 +55,7 @@ app_state::allow_workspace() } lua.load_rcfiles(opts); - projects.initialize(lua); + projects.initialize(lua, opts); } void ============================================================ --- options_list.hh 5ee94e644545cd8550638c47113655d8022d78c8 +++ options_list.hh 14c08437ac574e16befd4d8df9408368f5bbab55 @@ -16,6 +16,20 @@ OPTION(globals, positionals, true, "--", } #endif +typedef std::map policy_revision_arg_map; +GOPT(policy_revisions, "policy-revision", policy_revision_arg_map, , + gettext_noop("address@hidden, use a specific policy revision")) +#ifdef option_bodies +{ + size_t at = arg.find('@'); + if (at == std::string::npos) + throw bad_arg_internal(F("no '@' found").str()); + branch_prefix bp(arg.substr(0, at)); + revision_id rid(arg.substr(at+1)); + policy_revisions.insert(std::make_pair(bp, rid)); +} +#endif + OPT(author, "author", utf8, , gettext_noop("override author for commit")) #ifdef option_bodies { ============================================================ --- project.cc 5d3ae7981240fe8b8e5ce5807d6f8f213ca13d3f +++ project.cc 270d69f5891c8949ca0bd5149d1a2acc6d236b5a @@ -31,6 +31,7 @@ namespace basic_io { symbol const branch_uid("branch_uid"); symbol const committer("committer"); + symbol const revision_id("revision_id"); } } @@ -59,37 +60,16 @@ class policy_branch database & db; shared_ptr rev; - void init(data const & spec) + void init(data const & spec); + policy_branch(database & db) + : db(db) { - 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)) - { - pa.sym(); - string branch; - pa.str(branch); - my_branch_cert_value = branch_uid(branch); - } - else if (pa.symp(basic_io::syms::committer)) - { - pa.sym(); - string key; - pa.str(key); - my_committers.insert(rsa_keypair_id(key)); - } - else - { - N(false, F("Unable to understand policy spec file")); - } - } - - I(src.lookahead == EOF); } public: + static policy_branch empty_policy(database & db) + { + return policy_branch(db); + } policy_branch(data const & spec, branch_prefix const & prefix, database & db) @@ -97,6 +77,9 @@ public: { init(spec); } + policy_branch(revision_id const & rid, + branch_prefix const & prefix, + database & db); shared_ptr get_policy(); map branches(); @@ -220,6 +203,72 @@ public: } }; +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 @@ -371,8 +420,14 @@ public: : policy(spec, prefix, db), passthru(false) { } + policy_info(revision_id const & rev, + branch_prefix const & prefix, + database & db) + : policy(rev, prefix, db), passthru(false) + { + } explicit policy_info(database & db) - : policy(data(""), branch_prefix(""), db), passthru(true) + : policy(policy_branch::empty_policy(db)), passthru(true) { } }; @@ -383,6 +438,12 @@ project_t::project_t(branch_prefix const : db(db), project_policy(new policy_info(project_spec, project_name, db)) {} +project_t::project_t(branch_prefix const & project_name, + revision_id const & policy_rev, + database & db) + : db(db), project_policy(new policy_info(policy_rev, project_name, db)) +{} + project_t::project_t(database & db) : db(db), project_policy(new policy_info(db)) {} @@ -901,18 +962,31 @@ void } void -project_set::initialize(lua_hooks & lua) +project_set::initialize(lua_hooks & lua, options & opts) { map project_definitions; lua.hook_get_projects(project_definitions); for (map::const_iterator i = project_definitions.begin(); i != project_definitions.end(); ++i) { - projects.insert(make_pair(branch_prefix(i->first), - project_t(branch_prefix(i->first), - i->second, - db))); + if (opts.policy_revisions.find(branch_prefix(i->first)) + == opts.policy_revisions.end()) + { + projects.insert(make_pair(branch_prefix(i->first), + project_t(branch_prefix(i->first), + i->second, + db))); + } } + for (map::const_iterator + i = opts.policy_revisions.begin(); + i != opts.policy_revisions.end(); ++i) + { + projects.insert(make_pair(i->first, + project_t(i->first, + i->second, + db))); + } if (projects.empty()) { projects.insert(std::make_pair("", project_t(db))); ============================================================ --- project.hh ff88cd736651c2a719fd9bd077a31baa136b0cd8 +++ project.hh c2e794b47c13c23822e7edbf92250e4b5358f532 @@ -53,6 +53,9 @@ public: project_t(branch_prefix const & project_name, data const & project_spec, database & db); + project_t(branch_prefix const & project_name, + revision_id const & policy_rev, + database & db); explicit project_t(database & db); void get_branch_list(std::set & names, @@ -129,7 +132,7 @@ public: public: explicit project_set(database & db); - void initialize(lua_hooks & lua); + void initialize(lua_hooks & lua, options & opts); // Get a named project. project_t & get_project(branch_prefix const & name); ============================================================ --- tests/policy-basic/__driver__.lua a0d76df86e7eba065e24a3edb427bf3d828dbbea +++ tests/policy-basic/__driver__.lua 93a00f0043ffc206da000997587303011189c364 @@ -34,3 +34,19 @@ check(mtn("merge", "--branch=test_projec -- Can't do stuff now, because the policy branch has two heads. check(mtn("heads", "--branch=test_project.__policy__"), 1, false, false) check(mtn("merge", "--branch=test_project.__policy__"), 1, false, false) + +-- check that we can recover from this +check(mtn("merge", "--branch=test_project.__policy__", + "--policy-revision=test_project@" .. base), 0, false, false) + +check(mtn("up"), 0, false, false) + +check(base ~= base_revision()) + +-- check that we can delegate using a revision id +mkdir("delegations") +addfile("delegations/tp", "revision_id [" .. base .. "]"); +check(mtn("ci", "-mx", "--branch=test_project.__policy__"), 0, false, false) + +check(mtn("heads", "--branch=test_project.tp.__policy__"), 0, true, false) +check(qgrep(base_revision(), "stdout"), 0, false, false)