# # # patch "cmd_list.cc" # from [eb27e850b2619698dd201697b4f05dd5b89ed1b6] # to [24fdebca229af92b85d289ad4573a6a42a06897f] # # patch "project.cc" # from [1f3b828df6a7fa1aafa0a180b7215a85d29ebe03] # to [54e9bba700b7fbb701408270624ebaeb1ef7e17d] # # patch "tests/policy-keys/__driver__.lua" # from [f38806d38a58bdd969d993fa016587131c20af9a] # to [da04753f2b7078f4454a0f151b09a05697b2fb89] # ============================================================ --- cmd_list.cc eb27e850b2619698dd201697b4f05dd5b89ed1b6 +++ cmd_list.cc 24fdebca229af92b85d289ad4573a6a42a06897f @@ -84,7 +84,10 @@ namespace { out += hexid(); out += " "; - out += info.official_name(); + if (info.official_name().empty()) + out += "(no name)"; + else + out += info.official_name(); if (info.given_name != info.official_name) { out += " ("; @@ -414,7 +417,8 @@ CMD(keys, "keys", "", CMD_REF(list), "[P { duplicate_aliases.insert(alias); } - seen_aliases.insert(alias); + if (!alias.empty()) + seen_aliases.insert(alias); string rendered_basic = format_key_for_ls_keys(identity); string sort_key = alias + identity.id.inner()(); ============================================================ --- project.cc 1f3b828df6a7fa1aafa0a180b7215a85d29ebe03 +++ project.cc 54e9bba700b7fbb701408270624ebaeb1ef7e17d @@ -255,8 +255,32 @@ public: } }; +class key_lister +{ +public: + typedef std::multimap > name_map; +private: + name_map & names; +public: + key_lister(name_map & n) : names(n) { } + void operator()(shared_ptr pol, branch_name const & prefix, + policies::delegation const & del) + { + if (!pol) + return; + typedef policies::policy::key_map key_map; + key_map const & km = pol->list_keys(); + for (key_map::const_iterator i = km.begin(); i != km.end(); ++i) + { + names.insert(make_pair(i->second, make_pair(prefix, i->first))); + } + } +}; + + + // find the policy governing a particular name class policy_finder { @@ -522,6 +546,54 @@ public: walk_policies(project, policy, child_policies, policy_lister(base, children)); } + bool lookup_key_name(project_t const & project, + key_id const & ident, + branch_name const & where, + key_name & official_name) + { + key_lister::name_map names; + walk_policies(project, policy, child_policies, key_lister(names)); + + typedef key_lister::name_map::const_iterator it; + pair range = names.equal_range(ident); + + bool found = false; + for (it i = range.first; i != range.second; ++i) + { + if (i->second.first.has_prefix(where)) + { + if (found) + { + // because we list keys by ident + W(F("Key %s has multiple names.")); + } + found = true; + branch_name name_as_branch = typecast_vocab(i->second.second); + official_name = typecast_vocab(i->second.first / name_as_branch); + } + } + return found; + } + void find_keys_named(project_t const & project, + key_name const & name, + branch_name const & where, + map & results) + { + key_lister::name_map names; + walk_policies(project, policy, child_policies, key_lister(names)); + + typedef key_lister::name_map::const_iterator it; + for (it i = names.begin(); i != names.end(); ++i) + { + if (i->second.first.has_prefix(where) && i->second.second == name) + { + branch_name name_as_branch = typecast_vocab(i->second.second); + key_name official_name = + typecast_vocab(i->second.first / name_as_branch); + results[official_name] = i->first; + } + } + } }; bool @@ -1308,6 +1380,40 @@ project_t::lookup_key_by_name(key_store key_name const & name, key_id & id) const { + if (!project_policy->passthru) + { + set my_matching_keys; + vector storekeys; + keys->get_key_ids(storekeys); + for (vector::const_iterator i = storekeys.begin(); + i != storekeys.end(); ++i) + { + key_name i_name; + keypair kp; + keys->get_key_pair(*i, i_name, kp); + + if (i_name == name) + my_matching_keys.insert(*i); + } + E(my_matching_keys.size() < 2, origin::user, + F("you have %d keys named '%s'") % + my_matching_keys.size() % name); + if (my_matching_keys.size() == 1) + { + id = *my_matching_keys.begin(); + return; + } + + map results; + project_policy->find_keys_named(*this, name, branch_name(), results); + E(results.size() <= 1, origin::user, + F("there are %d keys named '%s'") % results.size() % name); + E(results.size() > 0, origin::user, + F("there are no keys named '%s'") % name); + id = results.begin()->second; + return; + } + set ks_match_by_local_name; set db_match_by_local_name; set ks_match_by_given_name; @@ -1329,7 +1435,15 @@ project_t::lookup_key_by_name(key_store key_identity_info identity; identity.id = *i; identity.given_name = i_name; - if (lua.hook_get_local_key_name(identity)) + bool found; + if (project_policy->passthru) + found = lua.hook_get_local_key_name(identity); + else + found = project_policy->lookup_key_name(*this, + identity.id, + branch_name(), + identity.official_name); + if (found) { if (identity.official_name == name) ks_match_by_local_name.insert(*i); @@ -1350,7 +1464,15 @@ project_t::lookup_key_by_name(key_store key_identity_info identity; identity.id = *i; identity.given_name = i_name; - if (lua.hook_get_local_key_name(identity)) + bool found; + if (project_policy->passthru) + found = lua.hook_get_local_key_name(identity); + else + found = project_policy->lookup_key_name(*this, + identity.id, + branch_name(), + identity.official_name); + if (found) { if (identity.official_name == name) db_match_by_local_name.insert(*i); @@ -1419,7 +1541,14 @@ project_t::complete_key_identity(key_sto if (!info.id.inner()().empty()) { get_canonical_name_of_key(keys, info.id, info.given_name); - lua.hook_get_local_key_name(info); + + if (project_policy->passthru) + lua.hook_get_local_key_name(info); + else + project_policy->lookup_key_name(*this, + info.id, + branch_name(), + info.official_name); } else if (!info.official_name().empty()) { ============================================================ --- tests/policy-keys/__driver__.lua f38806d38a58bdd969d993fa016587131c20af9a +++ tests/policy-keys/__driver__.lua da04753f2b7078f4454a0f151b09a05697b2fb89 @@ -9,27 +9,42 @@ mtn_setup() -- * local name comes only from policy -- + should this name be prefixed with the policy path? -check(mtn("create_project", "test_project"), 0, false, false) - -check(mtn("setup", "-btest_project.__policy__", "policy_checkout"), 0, false, false) - --- generate key; use in delegation, branch, and branch under delegation check(mtn("genkey", "address@hidden"), 0, false, true, string.rep("address@hidden", 2)) for hash in readfile("stderr"):gmatch("'(" .. string.rep("%x", 40) .. ")'") do my_key = hash end +check(mtn("create_project", "test_project", "-k", "address@hidden"), 0, false, false) + +check(mtn("setup", "-btest_project.__policy__", "policy_checkout"), 0, false, false) + mkdir("policy_checkout/keys") writefile("policy_checkout/keys/my_key", my_key) check(indir("policy_checkout", mtn("add", "keys/my_key", "--no-respect-ignore")), 0, false, false) -check(indir("policy_checkout", mtn("commit", "-m", "add key")), 0, false, false) +check(indir("policy_checkout", + mtn("commit", "-m", "add key", "-k", "address@hidden")), + 0, false, false) + +-- use new key in delegation, branch, and branch under delegation + +check(mtn("ls", "keys"), 0, true) +check(qgrep("test_project.my_key", "stdout")) + +-- TODO: check that keys named in some other (unrelated) policy +-- don't work here unless the full path is given check(mtn("create_subpolicy", "test_project.delegated", - "--no-workspace", "-k", "my_key")) -check(mtn("ls", "keys")) + "--no-workspace", "-k", "my_key"), 0, nil, false) +check(mtn("create_branch", "test_project.somebranch", + "--no-workspace", "-k", "my_key"), 0, nil, false) + +check(mtn("create_branch", "test_project.delegated.otherbranch", + "--no-workspace", "-k", "my_key"), 0, nil, false) + + -- drop private key (dropkey -d:memory:) check(mtn("-d", ":memory:", "--no-workspace", "dropkey", my_key), 0, nil, false)