# # add_file "tests/t_heads_of_certs.at" # # patch "ChangeLog" # from [18d49951f0df2a781f2ceafd29a120354915574c] # to [7dc77508deaefb79b419ce4dc589473108cc93de] # # patch "automate.cc" # from [7492b76019ac6578ecc8e1fec67025cff1ffbc39] # to [75c816d6cf3f9eed414b97e0042a6e5c288d8cb1] # # patch "commands.cc" # from [302aac08e63acc1f48aa29adbbdeeff58b1c782f] # to [346cf7133214c507802ca85f90bb21199ea16125] # # patch "selectors.cc" # from [af2e5813aba3cdf936fbcbb31dbb05ddf3690ccc] # to [d0a7bf9c23c599de5785fbd9b65112bd09a0649d] # # patch "selectors.hh" # from [54ed172da5c3a3c4721152012d831f51e693cab9] # to [035142d5ca28095e65c7fd231ff8c86c043cb96a] # # patch "tests/t_heads_of_certs.at" # from [] # to [2b52c4b5acdc54ec1a7e65bf308ae9f80fe00890] # # patch "testsuite.at" # from [0053f6d5ae281707c89693dbf4e0c6b3c4a8b61c] # to [dfef0f1ec4da1158f3c5ee928dc68abdf1db2dc2] # =============================================== --- ChangeLog 18d49951f0df2a781f2ceafd29a120354915574c +++ ChangeLog 7dc77508deaefb79b419ce4dc589473108cc93de @@ -1,3 +1,17 @@ +2005-07-18 Richard Levitte + + * selectors.cc (decode_selectors): If we're at the beginning of + the composite selector string, parse h: if it's there. Takes a + couple of new arguments, to return a flag saying only the heads + of the selection should be used, and an input flag saying if the + current selector is the first or not. + (complete_selectors, parse_selector): Adjust. + * commands.cc (complete): Use the new "heads only" selector. + * automate.cc (automate_select): Dito. + + * tests/t_heads_of_certs.at: New test. + * testsuite.at: Use it. + 2005-07-17 Nathaniel Smith * configure.ac, win32/monotone.iss, monotone.spec: =============================================== --- automate.cc 7492b76019ac6578ecc8e1fec67025cff1ffbc39 +++ automate.cc 75c816d6cf3f9eed414b97e0042a6e5c288d8cb1 @@ -494,15 +494,29 @@ if (args.size() != 1) throw usage(help_name); + bool get_heads = false; std::vector > - sels(selectors::parse_selector(args[0](), app)); + sels(selectors::parse_selector(args[0](), get_heads, app)); // we jam through an "empty" selection on sel_ident type - std::set completions; + std::set completions; selectors::selector_type ty = selectors::sel_ident; - selectors::complete_selector("", sels, ty, completions, app); + { + bool dummy_get_heads = false; + std::set completion_strings; + selectors::complete_selector("", sels, ty, dummy_get_heads, + completion_strings, app, true); + for (std::set::const_iterator i = completion_strings.begin(); + i != completion_strings.end(); ++i) + completions.insert(revision_id(*i)); + } - for (std::set::const_iterator i = completions.begin(); + if (get_heads && completions.size() > 1) + { + erase_ancestors(completions, app); + } + + for (std::set::const_iterator i = completions.begin(); i != completions.end(); ++i) output << *i << std::endl; } =============================================== --- commands.cc 302aac08e63acc1f48aa29adbbdeeff58b1c782f +++ commands.cc 346cf7133214c507802ca85f90bb21199ea16125 @@ -429,28 +429,42 @@ return; } + bool get_heads = false; vector > - sels(selectors::parse_selector(str, app)); + sels(selectors::parse_selector(str, get_heads, app)); P(F("expanding selection '%s'\n") % str); // we jam through an "empty" selection on sel_ident type - set completions; + set completions; selectors::selector_type ty = selectors::sel_ident; - selectors::complete_selector("", sels, ty, completions, app); + { + bool dummy_get_heads = false; + std::set completion_strings; + selectors::complete_selector("", sels, ty, dummy_get_heads, + completion_strings, app, true); + for (std::set::const_iterator i = completion_strings.begin(); + i != completion_strings.end(); ++i) + completions.insert(revision_id(*i)); + } N(completions.size() != 0, F("no match for selection '%s'") % str); + + if (get_heads && completions.size() > 1) + { + erase_ancestors(completions, app); + } if (completions.size() > 1) { string err = (F("selection '%s' has multiple ambiguous expansions: \n") % str).str(); - for (set::const_iterator i = completions.begin(); + for (set::const_iterator i = completions.begin(); i != completions.end(); ++i) - err += (describe_revision(app, revision_id(*i)) + "\n"); + err += (describe_revision(app, *i) + "\n"); N(completions.size() == 1, boost::format(err)); } - completion = revision_id(*(completions.begin())); - P(F("expanded to '%s'\n") % completion); + completion = *(completions.begin()); + P(F("expanded to '%s'\n") % completion); } static void =============================================== --- selectors.cc af2e5813aba3cdf936fbcbb31dbb05ddf3690ccc +++ selectors.cc d0a7bf9c23c599de5785fbd9b65112bd09a0649d @@ -15,13 +15,24 @@ static void decode_selector(std::string const & orig_sel, selector_type & type, + bool & get_heads, std::string & sel, - app_state & app) + app_state & app, + bool first_selector) { sel = orig_sel; L(F("decoding selector '%s'\n") % sel); + if (first_selector) + { + if (sel[0] == 'h' && sel[1] == ':') + { + get_heads = true; + sel.erase(0,2); + } + } + std::string tmp; if (sel.size() < 2 || sel[1] != ':') { @@ -70,12 +81,12 @@ } sel.erase(0,2); - /* a selector date-related should be validated */ + /* a selector date-related should be validated */ if (sel_date==type || sel_later==type || sel_earlier==type) { N (app.lua.hook_expand_date(sel, tmp), - F ("selector '%s' is not a valid date\n") % sel); - + F ("selector '%s' is not a valid date\n") % sel); + if (tmp.size()<8 && (sel_later==type || sel_earlier==type)) tmp += "-01T00:00:00"; else if (tmp.size()<11 && (sel_later==type || sel_earlier==type)) @@ -94,16 +105,19 @@ complete_selector(std::string const & orig_sel, std::vector > const & limit, selector_type & type, + bool & get_heads, std::set & completions, - app_state & app) + app_state & app, + bool first_selector) { std::string sel; - decode_selector(orig_sel, type, sel, app); + decode_selector(orig_sel, type, get_heads, sel, app, first_selector); app.db.complete(type, sel, limit, completions); } std::vector > parse_selector(std::string const & str, + bool & get_heads, app_state & app) { std::vector > sels; @@ -124,14 +138,16 @@ std::vector selector_strings; copy(tokens.begin(), tokens.end(), back_inserter(selector_strings)); + bool first = true; for (std::vector::const_iterator i = selector_strings.begin(); i != selector_strings.end(); ++i) { std::string sel; selector_type type = sel_unknown; - decode_selector(*i, type, sel, app); + decode_selector(*i, type, get_heads, sel, app, first); sels.push_back(std::make_pair(type, sel)); + first = false; } } =============================================== --- selectors.hh 54ed172da5c3a3c4721152012d831f51e693cab9 +++ selectors.hh 035142d5ca28095e65c7fd231ff8c86c043cb96a @@ -35,10 +35,13 @@ complete_selector(std::string const & orig_sel, std::vector > const & limit, selector_type & type, + bool & get_heads, std::set & completions, - app_state & app); + app_state & app, + bool first_selector); std::vector > parse_selector(std::string const & str, + bool & get_heads, app_state & app); }; // namespace selectors =============================================== --- tests/t_heads_of_certs.at +++ tests/t_heads_of_certs.at 2b52c4b5acdc54ec1a7e65bf308ae9f80fe00890 @@ -0,0 +1,31 @@ +AT_SETUP([selecting arbitrary certs]) +MONOTONE_SETUP + +ADD_FILE(testfile, [this is just a file +]) +COMMIT(testbranch) +FIRST=`BASE_REVISION` + +AT_DATA(testfile, [Now, this is a different file +]) +COMMIT(testbranch) +SECOND=`BASE_REVISION` + +AT_DATA(testfile, [And we change it a third time +]) +COMMIT(testbranch) +THIRD=`BASE_REVISION` + +AT_CHECK(MONOTONE cert $FIRST testcert 'value=with=equal=signs') +AT_CHECK(MONOTONE cert $SECOND testcert 'value') + +# Check that a log with no h: fails... +AT_CHECK(MONOTONE log --revision 'c:testcert', [1], [ignore], [stderr]) +AT_CHECK(grep 'has multiple ambiguous expansions' stderr, [0], [ignore]) + +# Check that a log with h: succeeds... +AT_CHECK(MONOTONE log --revision='h:c:testcert', [], [stdout], [ignore]) +# Note that if the third revision is in the log, something else is wrong... +AT_CHECK(grep $THIRD stdout, [1], [ignore], [ignore]) + +AT_CLEANUP =============================================== --- testsuite.at 0053f6d5ae281707c89693dbf4e0c6b3c4a8b61c +++ testsuite.at dfef0f1ec4da1158f3c5ee928dc68abdf1db2dc2 @@ -674,3 +674,4 @@ m4_include(tests/t_restricted_diff_unchanged.at) m4_include(tests/t_selector_globbing.at) m4_include(tests/t_diff_external.at) +m4_include(tests/t_heads_of_certs.at)