Merge lp:~fullermd/bzr/revspec-dwim into lp:bzr
- revspec-dwim
- Merge into bzr.dev
Status: | Merged |
---|---|
Approved by: | John A Meinel |
Approved revision: | no longer in the source branch. |
Merged at revision: | not available |
Proposed branch: | lp:~fullermd/bzr/revspec-dwim |
Merge into: | lp:bzr |
Diff against target: |
396 lines 6 files modified
NEWS (+4/-0) bzrlib/help_topics/__init__.py (+10/-4) bzrlib/option.py (+14/-18) bzrlib/revisionspec.py (+80/-21) bzrlib/tests/test_revisionspec.py (+43/-18) doc/en/user-guide/specifying_revisions.txt (+10/-4) |
To merge this branch: | bzr merge lp:~fullermd/bzr/revspec-dwim |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
John A Meinel | Approve | ||
Ian Clatworthy | Needs Information | ||
Vincent Ladeuil | Approve | ||
Robert Collins | Pending | ||
Review via email: mp+13801@code.launchpad.net |
This proposal supersedes a proposal from 2009-10-10.
Commit message
Description of the change
Matthew Fuller (fullermd) wrote : Posted in a previous version of this proposal | # |
Ian Clatworthy (ian-clatworthy) wrote : Posted in a previous version of this proposal | # |
I agree in principle with this and the code looks ok to me. There are 2 main concerns I have:
1. If something looks like a revno and isn't, I'd prefer that we raised an error in that case rather than continuing to look. The main issue here is tags like x.y.z I guess. I'd prefer we err'ed on the side of safety. It's not a big deal for projects to use a more explicit tag (like release-x.y.z) or for the user to type tag:x.y.z if they choose not to.
2. The time to look up a revision-id needs discussion. I'd prefer if it was done last. (If that's a performance issue, I'd prefer it was done immediately after revno but before the other specifiers.)
Ian Clatworthy (ian-clatworthy) wrote : Posted in a previous version of this proposal | # |
After discussing this on IRC with a few people, I'm ok to proceed with this as is. Matthew has pinged the list just in case others have strong opinions. We ought to give that a day or two to see what feedback, if any, there is.
Robert Collins (lifeless) wrote : Posted in a previous version of this proposal | # |
review needs-fixing
(however thats said now :()
This manually reproduces the registry of revspecs. Lets not do that,
instead query it dynamically.
If an ordering is needed, see the transport registry which has some
sorting done to it.
-Rob
Matthew Fuller (fullermd) wrote : Posted in a previous version of this proposal | # |
On Thu, Oct 15, 2009 at 05:33:12AM -0000 I heard the voice of
Robert Collins, and lo! it spake thus:
>
> This manually reproduces the registry of revspecs. Lets not do that,
> instead query it dynamically.
>
> If an ordering is needed, see the transport registry which has some
> sorting done to it.
I disagree.
Leaving aside the very large practical difficulties in doing it out of
the registry (and there are several), I consider it the wrong
approach. This isn't RevisionSpec_
RevisionSpec_dwim. An important part of a non-screwyou DWIM system is
carefully limiting to scope, and precisely defining the order within
that.
In this case, the dwim tries just half (rounded) of the revspecs we
have, because trying the rest makes no sense at all (e.g., if we don't
match it somewhere else, trying to match it to 'before:' would be
nonsensical, and in the bizarre case it actually DID something, it's
sure to be Wrong).
--
Matthew Fuller
<email address hidden>
Robert Collins (lifeless) wrote : Posted in a previous version of this proposal | # |
I disagree with your disagreement :)
specifically, git:, hg:, svn:, and thread: specs are added by plugins
and desirable to search too.
You can add this as a future enchancement if you like, but I think the
code will be smaller and more compact if you go straight to this.
-Rob
Matthew Fuller (fullermd) wrote : Posted in a previous version of this proposal | # |
> specifically, git:, hg:, svn:, and thread: specs are added by
> plugins and desirable to search too.
OK, so it sounds like there're actually two separate issues being a
little conflated here:
1) Make the DWIM use a registry instead of hand-written code.
I'm not necessarily opposed to that; certainly IWBNI plugins could
register their own specs DWIM should try. But I don't think I'll
be doing it (certainly not anytime soon; $freetime--). And it's
not quite as easy as it sounds, since we have to keep track of
which exceptions each class raises for 'no, I didn't find this' (as
opposed to 'crap, something went wrong').
Also, instantiating the RevSpec_* classes _doesn't_ determine
whether the given value points at anything, it only sets up the
object to lazily search later. We reach inside them in the _dwim
class to evaluate on the spot (when _dwim is lazily searched) to
find out whether the value means anything to that spectype.
So it's not just as simple as "do this then this then this";
encoding that in a registry will take more knowledge of what you
can do with python than I have. As it is, the body of the dwim
_match_on() is about 40 lines (and with my characteristic heavy use
of whitespace and commenting, so the actual code is probably under
25), and explicit about the complications and what's going on.
2) Have that registry be the same as the revspec_registry registry
that the prefix:'s are searched in.
This I would be against, because 'prefixes we recognize' and
'things we want to DWIM' are rather different, and cramming all of
the above info, plus ordering, plus info on which specs we even
DWIM at all, into that registry is a giant mess of making one thing
do two almost-
conceptually arguing against in the previous message, not so much
(1) above.
--
Matthew Fuller
<email address hidden>
Matthew Fuller (fullermd) wrote : | # |
> fullermd has proposed merging lp:~fullermd/bzr/revspec-dwim into lp:bzr.
This is an update of the previous submissions, with changes from vila
to add a registry of revspecs to try instead of my hardcoded list.
Vincent Ladeuil (vila) wrote : | # |
I think Robert's concerns are addressed now in the most simple implementation I could think of.
All we need is a list of revspecs to be tried in a given order (said otherwise,
a revspec is part of the DWIM and when it is, it's tried after some others).
Note that a revspec is needed to implement DWIM and that this revspec is not registered
since the registry requires a prefix.
If w want to add svn:, git: or thread: revisionspec.
will suffice.
There are alternatives, but I'd like more use cases before addressing them and I'd like
us to *experiment* with the DWIM proposal, as, with all the respect I have for Matthew,
DWIM always need to be tweaked:
- we may want to define _dwim_match_on to replace the dwim_catchable_
- we may want to chain revspec classes instead of defining a list (with the idea
that if you want to add a revspec in the chain you know after or before which revspec
you want to be tried)
That could be done in another submission.
John A Meinel (jameinel) wrote : | # |
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
fullermd wrote:
> fullermd has proposed merging lp:~fullermd/bzr/revspec-dwim into lp:bzr.
>
> Requested reviews:
> Ian Clatworthy (ian-clatworthy)
> Robert Collins (lifeless)
>
>
I probably wouldn't put 'date' into the dwim behavior, mostly because
our date support is pretty poor. Otherwise this seems fine to me.
(Not voting since you explicitly requested reviews from others, and I
don't want to knock it out of their lists.)
John
=:->
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (Cygwin)
Comment: Using GnuPG with Mozilla - http://
iEYEARECAAYFAkr
3ckAniRkE4oC6N6
=uB7T
-----END PGP SIGNATURE-----
Matthew Fuller (fullermd) wrote : | # |
> I probably wouldn't put 'date' into the dwim behavior, mostly
> because our date support is pretty poor. Otherwise this seems fine
> to me.
I had it in there because (a) I kinda put in everything that made
sense, and (b) I often do things like "bzr log -rdate:today.." to
check up on "what have I done today", so saving half the keystrokes of
that end of the revspec...
> (Not voting since you explicitly requested reviews from others, and
> I don't want to knock it out of their lists.)
I didn't specifically. LP did it for me; probably because they had
comments on the previous MP.
Ian Clatworthy (ian-clatworthy) wrote : | # |
IIRC, I thought the consensus was that if something looks like a revno and isn't, it ought to fail rather than fall through to DWIM? This doesn't do that.
A minor typo as well in revisionspec.py: "expectation" should be "exception".
Robert Collins (lifeless) wrote : | # |
On Tue, 2009-10-27 at 06:42 +0000, Ian Clatworthy wrote:
> Review: Needs Information
> IIRC, I thought the consensus was that if something looks like a revno and isn't, it ought to fail rather than fall through to DWIM? This doesn't do that.
That sounds undesirable to me. What if I have a tag 2.0.0 ?
Rob
John A Meinel (jameinel) wrote : | # |
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Robert Collins wrote:
> On Tue, 2009-10-27 at 06:42 +0000, Ian Clatworthy wrote:
>> Review: Needs Information
>> IIRC, I thought the consensus was that if something looks like a revno and isn't, it ought to fail rather than fall through to DWIM? This doesn't do that.
>
> That sounds undesirable to me. What if I have a tag 2.0.0 ?
>
> Rob
IIRC there was *not* a consensus. And in the interest of "he who writes
the code gets to decide" I think we can merge this as is. If we find the
DWIM not what we want, we can tweak it later.
John
=:->
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (Cygwin)
Comment: Using GnuPG with Mozilla - http://
iEYEARECAAYFAkr
L+UAoLr1BCCZ/
=BqLR
-----END PGP SIGNATURE-----
John A Meinel (jameinel) : | # |
Ian Clatworthy (ian-clatworthy) wrote : | # |
John A Meinel wrote:
> IIRC there was *not* a consensus. And in the interest of "he who writes
> the code gets to decide" I think we can merge this as is. If we find the
> DWIM not what we want, we can tweak it later.
That's fine with me.
Ian C.
Preview Diff
1 | === modified file 'NEWS' |
2 | --- NEWS 2009-10-22 08:49:42 +0000 |
3 | +++ NEWS 2009-10-22 19:20:37 +0000 |
4 | @@ -233,6 +233,10 @@ |
5 | Improvements |
6 | ************ |
7 | |
8 | +* Revision specifiers can now be given in a more DWIM form, without |
9 | + needing explicit prefixes for specifiers like tags or revision id's. |
10 | + See ``bzr help revisionspec`` for full details. (Matthew Fuller) |
11 | + |
12 | * Bazaar gives a warning before exiting, and writes into ``.bzr.log``, if |
13 | compiled extensions can't be loaded. This typically indicates a |
14 | packaging or installation problem. In this case Bazaar will keep |
15 | |
16 | === modified file 'bzrlib/help_topics/__init__.py' |
17 | --- bzrlib/help_topics/__init__.py 2009-10-13 20:15:45 +0000 |
18 | +++ bzrlib/help_topics/__init__.py 2009-10-22 19:20:37 +0000 |
19 | @@ -152,10 +152,16 @@ |
20 | out.append( |
21 | """Revision Identifiers |
22 | |
23 | -A revision identifier refers to a specific state of a branch's history. It can |
24 | -be a revision number, or a keyword followed by ':' and often other |
25 | -parameters. Some examples of identifiers are '3', 'last:1', 'before:yesterday' |
26 | -and 'submit:'. |
27 | +A revision identifier refers to a specific state of a branch's history. It |
28 | +can be expressed in several ways. It can begin with a keyword to |
29 | +unambiguously specify a given lookup type; some examples are 'last:1', |
30 | +'before:yesterday' and 'submit:'. |
31 | + |
32 | +Alternately, it can be given without a keyword, in which case it will be |
33 | +checked as a revision number, a tag, a revision id, a date specification, or a |
34 | +branch specification, in that order. For example, 'date:today' could be |
35 | +written as simply 'today', though if you have a tag called 'today' that will |
36 | +be found first. |
37 | |
38 | If 'REV1' and 'REV2' are revision identifiers, then 'REV1..REV2' denotes a |
39 | revision range. Examples: '3647..3649', 'date:yesterday..-1' and |
40 | |
41 | === modified file 'bzrlib/option.py' |
42 | --- bzrlib/option.py 2009-04-03 20:05:25 +0000 |
43 | +++ bzrlib/option.py 2009-10-22 19:20:37 +0000 |
44 | @@ -40,25 +40,25 @@ |
45 | each revision specifier supplied. |
46 | |
47 | >>> _parse_revision_str('234') |
48 | - [<RevisionSpec_revno 234>] |
49 | + [<RevisionSpec_dwim 234>] |
50 | >>> _parse_revision_str('234..567') |
51 | - [<RevisionSpec_revno 234>, <RevisionSpec_revno 567>] |
52 | + [<RevisionSpec_dwim 234>, <RevisionSpec_dwim 567>] |
53 | >>> _parse_revision_str('..') |
54 | [<RevisionSpec None>, <RevisionSpec None>] |
55 | >>> _parse_revision_str('..234') |
56 | - [<RevisionSpec None>, <RevisionSpec_revno 234>] |
57 | + [<RevisionSpec None>, <RevisionSpec_dwim 234>] |
58 | >>> _parse_revision_str('234..') |
59 | - [<RevisionSpec_revno 234>, <RevisionSpec None>] |
60 | + [<RevisionSpec_dwim 234>, <RevisionSpec None>] |
61 | >>> _parse_revision_str('234..456..789') # Maybe this should be an error |
62 | - [<RevisionSpec_revno 234>, <RevisionSpec_revno 456>, <RevisionSpec_revno 789>] |
63 | + [<RevisionSpec_dwim 234>, <RevisionSpec_dwim 456>, <RevisionSpec_dwim 789>] |
64 | >>> _parse_revision_str('234....789') #Error ? |
65 | - [<RevisionSpec_revno 234>, <RevisionSpec None>, <RevisionSpec_revno 789>] |
66 | + [<RevisionSpec_dwim 234>, <RevisionSpec None>, <RevisionSpec_dwim 789>] |
67 | >>> _parse_revision_str('revid:test@other.com-234234') |
68 | [<RevisionSpec_revid revid:test@other.com-234234>] |
69 | >>> _parse_revision_str('revid:test@other.com-234234..revid:test@other.com-234235') |
70 | [<RevisionSpec_revid revid:test@other.com-234234>, <RevisionSpec_revid revid:test@other.com-234235>] |
71 | >>> _parse_revision_str('revid:test@other.com-234234..23') |
72 | - [<RevisionSpec_revid revid:test@other.com-234234>, <RevisionSpec_revno 23>] |
73 | + [<RevisionSpec_revid revid:test@other.com-234234>, <RevisionSpec_dwim 23>] |
74 | >>> _parse_revision_str('date:2005-04-12') |
75 | [<RevisionSpec_date date:2005-04-12>] |
76 | >>> _parse_revision_str('date:2005-04-12 12:24:33') |
77 | @@ -68,27 +68,23 @@ |
78 | >>> _parse_revision_str('date:2005-04-12,12:24:33') |
79 | [<RevisionSpec_date date:2005-04-12,12:24:33>] |
80 | >>> _parse_revision_str('-5..23') |
81 | - [<RevisionSpec_revno -5>, <RevisionSpec_revno 23>] |
82 | + [<RevisionSpec_dwim -5>, <RevisionSpec_dwim 23>] |
83 | >>> _parse_revision_str('-5') |
84 | - [<RevisionSpec_revno -5>] |
85 | + [<RevisionSpec_dwim -5>] |
86 | >>> _parse_revision_str('123a') |
87 | - Traceback (most recent call last): |
88 | - ... |
89 | - NoSuchRevisionSpec: No namespace registered for string: '123a' |
90 | + [<RevisionSpec_dwim 123a>] |
91 | >>> _parse_revision_str('abc') |
92 | - Traceback (most recent call last): |
93 | - ... |
94 | - NoSuchRevisionSpec: No namespace registered for string: 'abc' |
95 | + [<RevisionSpec_dwim abc>] |
96 | >>> _parse_revision_str('branch:../branch2') |
97 | [<RevisionSpec_branch branch:../branch2>] |
98 | >>> _parse_revision_str('branch:../../branch2') |
99 | [<RevisionSpec_branch branch:../../branch2>] |
100 | >>> _parse_revision_str('branch:../../branch2..23') |
101 | - [<RevisionSpec_branch branch:../../branch2>, <RevisionSpec_revno 23>] |
102 | + [<RevisionSpec_branch branch:../../branch2>, <RevisionSpec_dwim 23>] |
103 | >>> _parse_revision_str('branch:..\\\\branch2') |
104 | [<RevisionSpec_branch branch:..\\branch2>] |
105 | >>> _parse_revision_str('branch:..\\\\..\\\\branch2..23') |
106 | - [<RevisionSpec_branch branch:..\\..\\branch2>, <RevisionSpec_revno 23>] |
107 | + [<RevisionSpec_branch branch:..\\..\\branch2>, <RevisionSpec_dwim 23>] |
108 | """ |
109 | # TODO: Maybe move this into revisionspec.py |
110 | revs = [] |
111 | @@ -104,7 +100,7 @@ |
112 | parent of the revision. |
113 | |
114 | >>> _parse_change_str('123') |
115 | - (<RevisionSpec_before before:123>, <RevisionSpec_revno 123>) |
116 | + (<RevisionSpec_before before:123>, <RevisionSpec_dwim 123>) |
117 | >>> _parse_change_str('123..124') |
118 | Traceback (most recent call last): |
119 | ... |
120 | |
121 | === modified file 'bzrlib/revisionspec.py' |
122 | --- bzrlib/revisionspec.py 2009-07-25 08:26:42 +0000 |
123 | +++ bzrlib/revisionspec.py 2009-10-22 19:20:37 +0000 |
124 | @@ -113,8 +113,6 @@ |
125 | return RevisionInfo(branch, revno, revision_id) |
126 | |
127 | |
128 | -# classes in this list should have a "prefix" attribute, against which |
129 | -# string specs are matched |
130 | _revno_regex = None |
131 | |
132 | |
133 | @@ -123,10 +121,10 @@ |
134 | |
135 | help_txt = """A parsed revision specification. |
136 | |
137 | - A revision specification can be an integer, in which case it is |
138 | - assumed to be a revno (though this will translate negative values |
139 | - into positive ones); or it can be a string, in which case it is |
140 | - parsed for something like 'date:' or 'revid:' etc. |
141 | + A revision specification is a string, which may be unambiguous about |
142 | + what it represents by giving a prefix like 'date:' or 'revid:' etc, |
143 | + or it may have no prefix, in which case it's tried against several |
144 | + specifier types in sequence to determine what the user meant. |
145 | |
146 | Revision specs are an UI element, and they have been moved out |
147 | of the branch class to leave "back-end" classes unaware of such |
148 | @@ -139,6 +137,14 @@ |
149 | |
150 | prefix = None |
151 | wants_revision_history = True |
152 | + dwim_catchable_exceptions = (errors.InvalidRevisionSpec,) |
153 | + """Expections that RevisionSpec_dwim._match_on will catch. |
154 | + |
155 | + If the revspec is part of dwim_revspecs, it may be tried with an invalid |
156 | + revspec and raise some exception. The exceptions mentioned here will not be |
157 | + reported to the user but simply ignored without stopping the dwim |
158 | + processing. |
159 | + """ |
160 | |
161 | @staticmethod |
162 | def from_string(spec): |
163 | @@ -165,17 +171,9 @@ |
164 | trace.mutter('Returning RevisionSpec %s for %s', |
165 | spectype.__name__, spec) |
166 | return spectype(spec, _internal=True) |
167 | - # RevisionSpec_revno is special cased, because it is the only |
168 | - # one that directly handles plain integers |
169 | - # TODO: This should not be special cased rather it should be |
170 | - # a method invocation on spectype.canparse() |
171 | - global _revno_regex |
172 | - if _revno_regex is None: |
173 | - _revno_regex = re.compile(r'^(?:(\d+(\.\d+)*)|-\d+)(:.*)?$') |
174 | - if _revno_regex.match(spec) is not None: |
175 | - return RevisionSpec_revno(spec, _internal=True) |
176 | - |
177 | - raise errors.NoSuchRevisionSpec(spec) |
178 | + # Otherwise treat it as a DWIM, build the RevisionSpec object and |
179 | + # wait for _match_on to be called. |
180 | + return RevisionSpec_dwim(spec, _internal=True) |
181 | |
182 | def __init__(self, spec, _internal=False): |
183 | """Create a RevisionSpec referring to the Null revision. |
184 | @@ -290,16 +288,62 @@ |
185 | |
186 | # private API |
187 | |
188 | +class RevisionSpec_dwim(RevisionSpec): |
189 | + """Provides a DWIMish revision specifier lookup. |
190 | + |
191 | + Note that this does not go in the revspec_registry because by definition |
192 | + there is no prefix to identify it. It's solely called from |
193 | + RevisionSpec.from_string() because the DWIMification happen when _match_on |
194 | + is called so the string describing the revision is kept here until needed. |
195 | + """ |
196 | + |
197 | + help_txt = None |
198 | + # We don't need to build the revision history ourself, that's delegated to |
199 | + # each revspec we try. |
200 | + wants_revision_history = False |
201 | + |
202 | + def _try_spectype(self, rstype, branch): |
203 | + rs = rstype(self.spec, _internal=True) |
204 | + # Hit in_history to find out if it exists, or we need to try the |
205 | + # next type. |
206 | + return rs.in_history(branch) |
207 | + |
208 | + def _match_on(self, branch, revs): |
209 | + """Run the lookup and see what we can get.""" |
210 | + |
211 | + # First, see if it's a revno |
212 | + global _revno_regex |
213 | + if _revno_regex is None: |
214 | + _revno_regex = re.compile(r'^(?:(\d+(\.\d+)*)|-\d+)(:.*)?$') |
215 | + if _revno_regex.match(self.spec) is not None: |
216 | + try: |
217 | + return self._try_spectype(RevisionSpec_revno, branch) |
218 | + except RevisionSpec_revno.dwim_catchable_exceptions: |
219 | + pass |
220 | + |
221 | + # Next see what has been registered |
222 | + for rs_class in dwim_revspecs: |
223 | + try: |
224 | + return self._try_spectype(rs_class, branch) |
225 | + except rs_class.dwim_catchable_exceptions: |
226 | + pass |
227 | + |
228 | + # Well, I dunno what it is. Note that we don't try to keep track of the |
229 | + # first of last exception raised during the DWIM tries as none seems |
230 | + # really relevant. |
231 | + raise errors.InvalidRevisionSpec(self.spec, branch) |
232 | + |
233 | + |
234 | class RevisionSpec_revno(RevisionSpec): |
235 | """Selects a revision using a number.""" |
236 | |
237 | help_txt = """Selects a revision using a number. |
238 | |
239 | Use an integer to specify a revision in the history of the branch. |
240 | - Optionally a branch can be specified. The 'revno:' prefix is optional. |
241 | - A negative number will count from the end of the branch (-1 is the |
242 | - last revision, -2 the previous one). If the negative number is larger |
243 | - than the branch's history, the first revision is returned. |
244 | + Optionally a branch can be specified. A negative number will count |
245 | + from the end of the branch (-1 is the last revision, -2 the previous |
246 | + one). If the negative number is larger than the branch's history, the |
247 | + first revision is returned. |
248 | Examples:: |
249 | |
250 | revno:1 -> return the first revision of this branch |
251 | @@ -561,6 +605,7 @@ |
252 | """ |
253 | |
254 | prefix = 'tag:' |
255 | + dwim_catchable_exceptions = (errors.NoSuchTag, errors.TagsNotSupported) |
256 | |
257 | def _match_on(self, branch, revs): |
258 | # Can raise tags not supported, NoSuchTag, etc |
259 | @@ -760,6 +805,7 @@ |
260 | branch:/path/to/branch |
261 | """ |
262 | prefix = 'branch:' |
263 | + dwim_catchable_exceptions = (errors.NotBranchError,) |
264 | |
265 | def _match_on(self, branch, revs): |
266 | from bzrlib.branch import Branch |
267 | @@ -838,6 +884,17 @@ |
268 | self._get_submit_location(context_branch)) |
269 | |
270 | |
271 | +# The order in which we want to DWIM a revision spec without any prefix. |
272 | +# revno is always tried first and isn't listed here, this is used by |
273 | +# RevisionSpec_dwim._match_on |
274 | +dwim_revspecs = [ |
275 | + RevisionSpec_tag, # Let's try for a tag |
276 | + RevisionSpec_revid, # Maybe it's a revid? |
277 | + RevisionSpec_date, # Perhaps a date? |
278 | + RevisionSpec_branch, # OK, last try, maybe it's a branch |
279 | + ] |
280 | + |
281 | + |
282 | revspec_registry = registry.Registry() |
283 | def _register_revspec(revspec): |
284 | revspec_registry.register(revspec.prefix, revspec) |
285 | @@ -852,5 +909,7 @@ |
286 | _register_revspec(RevisionSpec_branch) |
287 | _register_revspec(RevisionSpec_submit) |
288 | |
289 | +# classes in this list should have a "prefix" attribute, against which |
290 | +# string specs are matched |
291 | SPEC_TYPES = symbol_versioning.deprecated_list( |
292 | symbol_versioning.deprecated_in((1, 12, 0)), "SPEC_TYPES", []) |
293 | |
294 | === modified file 'bzrlib/tests/test_revisionspec.py' |
295 | --- bzrlib/tests/test_revisionspec.py 2009-03-23 14:59:43 +0000 |
296 | +++ bzrlib/tests/test_revisionspec.py 2009-10-22 19:20:37 +0000 |
297 | @@ -146,24 +146,49 @@ |
298 | def test_object(self): |
299 | self.assertRaises(TypeError, RevisionSpec.from_string, object()) |
300 | |
301 | - def test_unregistered_spec(self): |
302 | - self.assertRaises(errors.NoSuchRevisionSpec, |
303 | - RevisionSpec.from_string, 'foo') |
304 | - self.assertRaises(errors.NoSuchRevisionSpec, |
305 | - RevisionSpec.from_string, '123a') |
306 | - |
307 | - |
308 | - |
309 | -class TestRevnoFromString(TestCase): |
310 | - |
311 | - def test_from_string_dotted_decimal(self): |
312 | - self.assertRaises(errors.NoSuchRevisionSpec, RevisionSpec.from_string, '-1.1') |
313 | - self.assertRaises(errors.NoSuchRevisionSpec, RevisionSpec.from_string, '.1') |
314 | - self.assertRaises(errors.NoSuchRevisionSpec, RevisionSpec.from_string, '1..1') |
315 | - self.assertRaises(errors.NoSuchRevisionSpec, RevisionSpec.from_string, '1.2..1') |
316 | - self.assertRaises(errors.NoSuchRevisionSpec, RevisionSpec.from_string, '1.') |
317 | - self.assertIsInstance(RevisionSpec.from_string('1.1'), RevisionSpec_revno) |
318 | - self.assertIsInstance(RevisionSpec.from_string('1.1.3'), RevisionSpec_revno) |
319 | + |
320 | +class TestRevisionSpec_dwim(TestRevisionSpec): |
321 | + |
322 | + # Don't need to test revno's explicitly since TRS_revno already |
323 | + # covers that well for us |
324 | + def test_dwim_spec_revno(self): |
325 | + self.assertInHistoryIs(2, 'r2', '2') |
326 | + self.assertAsRevisionId('alt_r2', '1.1.1') |
327 | + |
328 | + def test_dwim_spec_revid(self): |
329 | + self.assertInHistoryIs(2, 'r2', 'r2') |
330 | + |
331 | + def test_dwim_spec_tag(self): |
332 | + self.tree.branch.tags.set_tag('footag', 'r1') |
333 | + self.assertAsRevisionId('r1', 'footag') |
334 | + self.tree.branch.tags.delete_tag('footag') |
335 | + self.assertRaises(errors.InvalidRevisionSpec, |
336 | + self.get_in_history, 'footag') |
337 | + |
338 | + def test_dwim_spec_tag_that_looks_like_revno(self): |
339 | + # Test that we slip past revno with things that look like revnos, |
340 | + # but aren't. Tags are convenient for testing this since we can |
341 | + # make them look however we want. |
342 | + self.tree.branch.tags.set_tag('3', 'r2') |
343 | + self.assertAsRevisionId('r2', '3') |
344 | + self.build_tree(['tree/b']) |
345 | + self.tree.add(['b']) |
346 | + self.tree.commit('b', rev_id='r3') |
347 | + self.assertAsRevisionId('r3', '3') |
348 | + |
349 | + def test_dwim_spec_date(self): |
350 | + self.assertAsRevisionId('r1', 'today') |
351 | + |
352 | + def test_dwim_spec_branch(self): |
353 | + self.assertInHistoryIs(None, 'alt_r2', 'tree2') |
354 | + |
355 | + def test_dwim_spec_nonexistent(self): |
356 | + self.assertInvalid('somethingrandom', invalid_as_revision_id=False) |
357 | + self.assertInvalid('-1.1', invalid_as_revision_id=False) |
358 | + self.assertInvalid('.1', invalid_as_revision_id=False) |
359 | + self.assertInvalid('1..1', invalid_as_revision_id=False) |
360 | + self.assertInvalid('1.2..1', invalid_as_revision_id=False) |
361 | + self.assertInvalid('1.', invalid_as_revision_id=False) |
362 | |
363 | |
364 | class TestRevisionSpec_revno(TestRevisionSpec): |
365 | |
366 | === modified file 'doc/en/user-guide/specifying_revisions.txt' |
367 | --- doc/en/user-guide/specifying_revisions.txt 2009-04-04 02:57:47 +0000 |
368 | +++ doc/en/user-guide/specifying_revisions.txt 2009-10-22 19:20:37 +0000 |
369 | @@ -36,17 +36,23 @@ |
370 | +----------------------+------------------------------------+ |
371 | | *number* | revision number | |
372 | +----------------------+------------------------------------+ |
373 | - | **revno**:*number* | positive revision number | |
374 | + | **revno**:*number* | revision number | |
375 | +----------------------+------------------------------------+ |
376 | | **last**:*number* | negative revision number | |
377 | +----------------------+------------------------------------+ |
378 | + | *guid* | globally unique revision id | |
379 | + +----------------------+------------------------------------+ |
380 | | **revid**:*guid* | globally unique revision id | |
381 | +----------------------+------------------------------------+ |
382 | | **before**:*rev* | leftmost parent of ''rev'' | |
383 | +----------------------+------------------------------------+ |
384 | - | **date**:*value* | first entry after a given date | |
385 | - +----------------------+------------------------------------+ |
386 | - | **tag**:*value* | revision matching a given tag | |
387 | + | *date-value* | first entry after a given date | |
388 | + +----------------------+------------------------------------+ |
389 | + | **date**:*date-value*| first entry after a given date | |
390 | + +----------------------+------------------------------------+ |
391 | + | *tag-name* | revision matching a given tag | |
392 | + +----------------------+------------------------------------+ |
393 | + | **tag**:*tag-name* | revision matching a given tag | |
394 | +----------------------+------------------------------------+ |
395 | | **ancestor**:*path* | last merged revision from a branch | |
396 | +----------------------+------------------------------------+ |
This allows unqualified revspecs to be tried as revnos, tags, revids, dates, or branches (respectively) rather than being assumed to be revnos.