/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
1
# Copyright (C) 2005 Canonical Ltd
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
2
#
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
7
#
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
12
#
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
1948.4.1 by John Arbash Meinel
Update number parsers to raise InvalidRevisionSpec. Update revno: itself so it supports negative numbers
18
import bisect
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
19
import datetime
20
import re
1948.4.1 by John Arbash Meinel
Update number parsers to raise InvalidRevisionSpec. Update revno: itself so it supports negative numbers
21
22
from bzrlib import (
23
    errors,
1948.4.18 by John Arbash Meinel
Update branch: spec and tests
24
    revision,
1948.4.27 by John Arbash Meinel
Deprecate calling RevisionSpec directly, and instead use a helper function. Also merge the old RevisionSpec_int class into RevisionSpec_revno
25
    symbol_versioning,
26
    trace,
1948.4.1 by John Arbash Meinel
Update number parsers to raise InvalidRevisionSpec. Update revno: itself so it supports negative numbers
27
    )
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
28
1948.4.16 by John Arbash Meinel
Move the tests into the associated tester, remove redundant tests, some small PEP8 changes
29
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
30
_marker = []
31
1948.4.16 by John Arbash Meinel
Move the tests into the associated tester, remove redundant tests, some small PEP8 changes
32
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
33
class RevisionInfo(object):
34
    """The results of applying a revision specification to a branch.
35
36
    An instance has two useful attributes: revno, and rev_id.
37
38
    They can also be accessed as spec[0] and spec[1] respectively,
39
    so that you can write code like:
40
    revno, rev_id = RevisionSpec(branch, spec)
41
    although this is probably going to be deprecated later.
42
43
    This class exists mostly to be the return value of a RevisionSpec,
44
    so that you can access the member you're interested in (number or id)
45
    or treat the result as a tuple.
46
    """
47
48
    def __init__(self, branch, revno, rev_id=_marker):
49
        self.branch = branch
50
        self.revno = revno
51
        if rev_id is _marker:
52
            # allow caller to be lazy
53
            if self.revno is None:
54
                self.rev_id = None
55
            else:
56
                self.rev_id = branch.get_rev_id(self.revno)
57
        else:
58
            self.rev_id = rev_id
59
60
    def __nonzero__(self):
61
        # first the easy ones...
62
        if self.rev_id is None:
63
            return False
64
        if self.revno is not None:
65
            return True
66
        # TODO: otherwise, it should depend on how I was built -
67
        # if it's in_history(branch), then check revision_history(),
68
        # if it's in_store(branch), do the check below
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
69
        return self.branch.repository.has_revision(self.rev_id)
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
70
71
    def __len__(self):
72
        return 2
73
74
    def __getitem__(self, index):
75
        if index == 0: return self.revno
76
        if index == 1: return self.rev_id
77
        raise IndexError(index)
78
79
    def get(self):
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
80
        return self.branch.repository.get_revision(self.rev_id)
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
81
82
    def __eq__(self, other):
83
        if type(other) not in (tuple, list, type(self)):
84
            return False
85
        if type(other) is type(self) and self.branch is not other.branch:
86
            return False
87
        return tuple(self) == tuple(other)
88
89
    def __repr__(self):
90
        return '<bzrlib.revisionspec.RevisionInfo object %s, %s for %r>' % (
91
            self.revno, self.rev_id, self.branch)
92
1948.4.16 by John Arbash Meinel
Move the tests into the associated tester, remove redundant tests, some small PEP8 changes
93
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
94
# classes in this list should have a "prefix" attribute, against which
95
# string specs are matched
96
SPEC_TYPES = []
1948.4.35 by John Arbash Meinel
Move the _revno_regex to a more logical location
97
_revno_regex = None
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
98
1948.4.16 by John Arbash Meinel
Move the tests into the associated tester, remove redundant tests, some small PEP8 changes
99
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
100
class RevisionSpec(object):
101
    """A parsed revision specification.
102
103
    A revision specification can be an integer, in which case it is
104
    assumed to be a revno (though this will translate negative values
105
    into positive ones); or it can be a string, in which case it is
106
    parsed for something like 'date:' or 'revid:' etc.
107
108
    Revision specs are an UI element, and they have been moved out
109
    of the branch class to leave "back-end" classes unaware of such
110
    details.  Code that gets a revno or rev_id from other code should
111
    not be using revision specs - revnos and revision ids are the
112
    accepted ways to refer to revisions internally.
113
114
    (Equivalent to the old Branch method get_revision_info())
115
    """
116
117
    prefix = None
118
1948.4.27 by John Arbash Meinel
Deprecate calling RevisionSpec directly, and instead use a helper function. Also merge the old RevisionSpec_int class into RevisionSpec_revno
119
    def __new__(cls, spec, _internal=False):
120
        if _internal:
121
            return object.__new__(cls, spec, _internal=_internal)
122
123
        symbol_versioning.warn('Creating a RevisionSpec directly has'
124
                               ' been deprecated in version 0.11. Use'
1948.4.33 by John Arbash Meinel
Switch from get_revision_spec() to RevisionSpec.from_string() (as advised by Martin)
125
                               ' RevisionSpec.from_string()'
1948.4.27 by John Arbash Meinel
Deprecate calling RevisionSpec directly, and instead use a helper function. Also merge the old RevisionSpec_int class into RevisionSpec_revno
126
                               ' instead.',
127
                               DeprecationWarning, stacklevel=2)
1948.4.33 by John Arbash Meinel
Switch from get_revision_spec() to RevisionSpec.from_string() (as advised by Martin)
128
        return RevisionSpec.from_string(spec)
129
130
    @staticmethod
131
    def from_string(spec):
132
        """Parse a revision spec string into a RevisionSpec object.
133
134
        :param spec: A string specified by the user
135
        :return: A RevisionSpec object that understands how to parse the
136
            supplied notation.
137
        """
138
        if not isinstance(spec, (type(None), basestring)):
139
            raise TypeError('error')
140
141
        if spec is None:
142
            return RevisionSpec(None, _internal=True)
143
144
        assert isinstance(spec, basestring), \
145
            "You should only supply strings not %s" % (type(spec),)
146
147
        for spectype in SPEC_TYPES:
148
            if spec.startswith(spectype.prefix):
149
                trace.mutter('Returning RevisionSpec %s for %s',
150
                             spectype.__name__, spec)
151
                return spectype(spec, _internal=True)
152
        else:
153
            # RevisionSpec_revno is special cased, because it is the only
154
            # one that directly handles plain integers
155
            global _revno_regex
156
            if _revno_regex is None:
157
                _revno_regex = re.compile(r'-?\d+(:.*)?$')
158
            if _revno_regex.match(spec) is not None:
159
                return RevisionSpec_revno(spec, _internal=True)
160
161
            raise errors.NoSuchRevisionSpec(spec)
1948.4.27 by John Arbash Meinel
Deprecate calling RevisionSpec directly, and instead use a helper function. Also merge the old RevisionSpec_int class into RevisionSpec_revno
162
163
    def __init__(self, spec, _internal=False):
164
        """Create a RevisionSpec referring to the Null revision.
165
166
        :param spec: The original spec supplied by the user
167
        :param _internal: Used to ensure that RevisionSpec is not being
1948.4.33 by John Arbash Meinel
Switch from get_revision_spec() to RevisionSpec.from_string() (as advised by Martin)
168
            called directly. Only from RevisionSpec.from_string()
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
169
        """
1948.4.27 by John Arbash Meinel
Deprecate calling RevisionSpec directly, and instead use a helper function. Also merge the old RevisionSpec_int class into RevisionSpec_revno
170
        if not _internal:
171
            # XXX: Update this after 0.10 is released
172
            symbol_versioning.warn('Creating a RevisionSpec directly has'
173
                                   ' been deprecated in version 0.11. Use'
1948.4.33 by John Arbash Meinel
Switch from get_revision_spec() to RevisionSpec.from_string() (as advised by Martin)
174
                                   ' RevisionSpec.from_string()'
1948.4.27 by John Arbash Meinel
Deprecate calling RevisionSpec directly, and instead use a helper function. Also merge the old RevisionSpec_int class into RevisionSpec_revno
175
                                   ' instead.',
176
                                   DeprecationWarning, stacklevel=2)
177
        self.user_spec = spec
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
178
        if self.prefix and spec.startswith(self.prefix):
179
            spec = spec[len(self.prefix):]
180
        self.spec = spec
181
182
    def _match_on(self, branch, revs):
1948.4.27 by John Arbash Meinel
Deprecate calling RevisionSpec directly, and instead use a helper function. Also merge the old RevisionSpec_int class into RevisionSpec_revno
183
        trace.mutter('Returning RevisionSpec._match_on: None')
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
184
        return RevisionInfo(branch, 0, None)
185
186
    def _match_on_and_check(self, branch, revs):
187
        info = self._match_on(branch, revs)
188
        if info:
189
            return info
190
        elif info == (0, None):
191
            # special case - the empty tree
192
            return info
193
        elif self.prefix:
1948.4.27 by John Arbash Meinel
Deprecate calling RevisionSpec directly, and instead use a helper function. Also merge the old RevisionSpec_int class into RevisionSpec_revno
194
            raise errors.InvalidRevisionSpec(self.user_spec, branch)
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
195
        else:
1948.4.2 by John Arbash Meinel
Update _match_on_and_check to raise the right error
196
            raise errors.InvalidRevisionSpec(self.spec, branch)
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
197
198
    def in_history(self, branch):
1732.3.1 by Matthieu Moy
Implementation of -r revno:N:/path/to/branch
199
        if branch:
200
            revs = branch.revision_history()
201
        else:
202
            revs = None
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
203
        return self._match_on_and_check(branch, revs)
204
1432 by Robert Collins
branch: namespace
205
        # FIXME: in_history is somewhat broken,
206
        # it will return non-history revisions in many
207
        # circumstances. The expected facility is that
208
        # in_history only returns revision-history revs,
209
        # in_store returns any rev. RBC 20051010
210
    # aliases for now, when we fix the core logic, then they
211
    # will do what you expect.
212
    in_store = in_history
213
    in_branch = in_store
214
        
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
215
    def __repr__(self):
216
        # this is mostly for helping with testing
1948.4.32 by John Arbash Meinel
Clean up __repr__, as well as add tests that we can handle -r12:branch/
217
        return '<%s %s>' % (self.__class__.__name__,
218
                              self.user_spec)
1881.1.1 by Matthieu Moy
Fixed and tested "bzr diff" outside a working tree.
219
    
1881.1.4 by Matthieu Moy
needs_tree -> needs_branch
220
    def needs_branch(self):
221
        """Whether this revision spec needs a branch.
222
1711.2.99 by John Arbash Meinel
minor typo fix
223
        Set this to False the branch argument of _match_on is not used.
224
        """
1881.1.1 by Matthieu Moy
Fixed and tested "bzr diff" outside a working tree.
225
        return True
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
226
1907.4.1 by Matthieu Moy
Fixed merge to work nicely with -r revno:N:path
227
    def get_branch(self):
228
        """When the revision specifier contains a branch location, return it.
229
        
230
        Otherwise, return None.
231
        """
232
        return None
233
1907.4.9 by Matthieu Moy
missing newline
234
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
235
# private API
236
237
class RevisionSpec_revno(RevisionSpec):
2023.1.1 by ghigo
add topics help
238
    """Selects a revision using a number.
239
240
    Use an integer to specify a revision in the history of the branch.
241
    Optionally a branch can be specified. The 'revno:' prefix is optional.
242
    A negative number will count from the end of the branch (-1 is the
243
    last revision, -2 the previous one). If the negative number is larger
244
    than the branch's history, the first revision is returned.
245
    examples:
246
      revno:1                   -> return the first revision
247
      revno:3:/path/to/branch   -> return the 3rd revision of
248
                                   the branch '/path/to/branch'
249
      revno:-1                  -> The last revision in a branch.
250
      -2:http://other/branch    -> The second to last revision in the
251
                                   remote branch.
252
      -1000000                  -> Most likely the first revision, unless
253
                                   your history is very long.
254
    """
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
255
    prefix = 'revno:'
256
257
    def _match_on(self, branch, revs):
258
        """Lookup a revision by revision number"""
1948.4.1 by John Arbash Meinel
Update number parsers to raise InvalidRevisionSpec. Update revno: itself so it supports negative numbers
259
        loc = self.spec.find(':')
260
        if loc == -1:
261
            revno_spec = self.spec
262
            branch_spec = None
263
        else:
264
            revno_spec = self.spec[:loc]
265
            branch_spec = self.spec[loc+1:]
266
267
        if revno_spec == '':
1948.4.6 by John Arbash Meinel
A small bugfix, and more tests for revno:
268
            if not branch_spec:
1948.4.27 by John Arbash Meinel
Deprecate calling RevisionSpec directly, and instead use a helper function. Also merge the old RevisionSpec_int class into RevisionSpec_revno
269
                raise errors.InvalidRevisionSpec(self.user_spec,
1948.4.5 by John Arbash Meinel
Fix tests for negative entries, and add tests for revno:
270
                        branch, 'cannot have an empty revno and no branch')
1948.4.1 by John Arbash Meinel
Update number parsers to raise InvalidRevisionSpec. Update revno: itself so it supports negative numbers
271
            revno = None
272
        else:
273
            try:
274
                revno = int(revno_spec)
275
            except ValueError, e:
1948.4.27 by John Arbash Meinel
Deprecate calling RevisionSpec directly, and instead use a helper function. Also merge the old RevisionSpec_int class into RevisionSpec_revno
276
                raise errors.InvalidRevisionSpec(self.user_spec,
1948.4.5 by John Arbash Meinel
Fix tests for negative entries, and add tests for revno:
277
                                                 branch, e)
1948.4.1 by John Arbash Meinel
Update number parsers to raise InvalidRevisionSpec. Update revno: itself so it supports negative numbers
278
1948.4.6 by John Arbash Meinel
A small bugfix, and more tests for revno:
279
        if branch_spec:
1948.4.1 by John Arbash Meinel
Update number parsers to raise InvalidRevisionSpec. Update revno: itself so it supports negative numbers
280
            from bzrlib.branch import Branch
281
            branch = Branch.open(branch_spec)
1948.4.22 by John Arbash Meinel
Refactor common code from integer revno handlers
282
            # Need to use a new revision history
283
            # because we are using a specific branch
284
            revs = branch.revision_history()
285
1948.4.27 by John Arbash Meinel
Deprecate calling RevisionSpec directly, and instead use a helper function. Also merge the old RevisionSpec_int class into RevisionSpec_revno
286
        if revno < 0:
287
            if (-revno) >= len(revs):
288
                revno = 1
289
            else:
290
                revno = len(revs) + revno + 1
291
        try:
292
            revision_id = branch.get_rev_id(revno, revs)
293
        except errors.NoSuchRevision:
294
            raise errors.InvalidRevisionSpec(self.user_spec, branch)
295
        return RevisionInfo(branch, revno, revision_id)
1881.1.1 by Matthieu Moy
Fixed and tested "bzr diff" outside a working tree.
296
        
1881.1.4 by Matthieu Moy
needs_tree -> needs_branch
297
    def needs_branch(self):
1881.1.1 by Matthieu Moy
Fixed and tested "bzr diff" outside a working tree.
298
        return self.spec.find(':') == -1
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
299
1907.4.1 by Matthieu Moy
Fixed merge to work nicely with -r revno:N:path
300
    def get_branch(self):
301
        if self.spec.find(':') == -1:
302
            return None
303
        else:
304
            return self.spec[self.spec.find(':')+1:]
305
1948.4.27 by John Arbash Meinel
Deprecate calling RevisionSpec directly, and instead use a helper function. Also merge the old RevisionSpec_int class into RevisionSpec_revno
306
# Old compatibility 
307
RevisionSpec_int = RevisionSpec_revno
308
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
309
SPEC_TYPES.append(RevisionSpec_revno)
310
311
312
class RevisionSpec_revid(RevisionSpec):
2023.1.1 by ghigo
add topics help
313
    """Selects a revision using the revision id.
314
315
    Supply a specific revision id, that can be used to specify any
316
    revision id in the ancestry of the branch. 
317
    Including merges, and pending merges.
318
    examples:
319
      revid:aaaa@bbbb-123456789 -> Select revision 'aaa@bbb-123456789'
320
    """    
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
321
    prefix = 'revid:'
322
323
    def _match_on(self, branch, revs):
324
        try:
1948.4.2 by John Arbash Meinel
Update _match_on_and_check to raise the right error
325
            revno = revs.index(self.spec) + 1
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
326
        except ValueError:
1948.4.2 by John Arbash Meinel
Update _match_on_and_check to raise the right error
327
            revno = None
328
        return RevisionInfo(branch, revno, self.spec)
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
329
330
SPEC_TYPES.append(RevisionSpec_revid)
331
332
333
class RevisionSpec_last(RevisionSpec):
2023.1.1 by ghigo
add topics help
334
    """Selects the nth revision from the end.
335
336
    Supply a positive number to get the nth revision from the end.
337
    This is the same as suppling negative numbers to the 'revno:' spec.
338
    examples:
339
      last:1        -> return the last revision
340
      last:3        -> return the revision 2 before the end.
341
    """    
1185.1.39 by Robert Collins
Robey Pointers before: namespace to clear up usage of dates in revision parameters
342
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
343
    prefix = 'last:'
344
345
    def _match_on(self, branch, revs):
1948.4.9 by John Arbash Meinel
Cleanup and test last:
346
        if self.spec == '':
347
            if not revs:
1948.4.26 by John Arbash Meinel
Get rid of direct imports of exceptions
348
                raise errors.NoCommits(branch)
1948.4.9 by John Arbash Meinel
Cleanup and test last:
349
            return RevisionInfo(branch, len(revs), revs[-1])
350
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
351
        try:
352
            offset = int(self.spec)
1948.4.9 by John Arbash Meinel
Cleanup and test last:
353
        except ValueError, e:
1948.4.27 by John Arbash Meinel
Deprecate calling RevisionSpec directly, and instead use a helper function. Also merge the old RevisionSpec_int class into RevisionSpec_revno
354
            raise errors.InvalidRevisionSpec(self.user_spec, branch, e)
1948.4.9 by John Arbash Meinel
Cleanup and test last:
355
356
        if offset <= 0:
1948.4.27 by John Arbash Meinel
Deprecate calling RevisionSpec directly, and instead use a helper function. Also merge the old RevisionSpec_int class into RevisionSpec_revno
357
            raise errors.InvalidRevisionSpec(self.user_spec, branch,
1948.4.9 by John Arbash Meinel
Cleanup and test last:
358
                                             'you must supply a positive value')
359
        revno = len(revs) - offset + 1
360
        try:
361
            revision_id = branch.get_rev_id(revno, revs)
362
        except errors.NoSuchRevision:
1948.4.27 by John Arbash Meinel
Deprecate calling RevisionSpec directly, and instead use a helper function. Also merge the old RevisionSpec_int class into RevisionSpec_revno
363
            raise errors.InvalidRevisionSpec(self.user_spec, branch)
1948.4.9 by John Arbash Meinel
Cleanup and test last:
364
        return RevisionInfo(branch, revno, revision_id)
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
365
366
SPEC_TYPES.append(RevisionSpec_last)
367
368
1185.1.39 by Robert Collins
Robey Pointers before: namespace to clear up usage of dates in revision parameters
369
class RevisionSpec_before(RevisionSpec):
2023.1.1 by ghigo
add topics help
370
    """Selects the parent of the revision specified.
371
372
    Supply any revision spec to return the parent of that revision.
373
    It is an error to request the parent of the null revision (before:0).
374
    This is mostly useful when inspecting revisions that are not in the
375
    revision history of a branch.
376
377
    examples:
378
      before:1913    -> Return the parent of revno 1913 (revno 1912)
379
      before:revid:aaaa@bbbb-1234567890  -> return the parent of revision
380
                                            aaa@bbb-1234567890
381
      bzr diff -r before:revid:aaaa..revid:aaaa
382
            -> Find the changes between revision 'aaaa' and its parent.
383
               (what changes did 'aaaa' introduce)
384
    """
1185.1.39 by Robert Collins
Robey Pointers before: namespace to clear up usage of dates in revision parameters
385
386
    prefix = 'before:'
387
    
388
    def _match_on(self, branch, revs):
1948.4.33 by John Arbash Meinel
Switch from get_revision_spec() to RevisionSpec.from_string() (as advised by Martin)
389
        r = RevisionSpec.from_string(self.spec)._match_on(branch, revs)
1948.4.13 by John Arbash Meinel
Going before:0 is an error, and if you are on another history, use the leftmost parent
390
        if r.revno == 0:
1948.4.27 by John Arbash Meinel
Deprecate calling RevisionSpec directly, and instead use a helper function. Also merge the old RevisionSpec_int class into RevisionSpec_revno
391
            raise errors.InvalidRevisionSpec(self.user_spec, branch,
1948.4.13 by John Arbash Meinel
Going before:0 is an error, and if you are on another history, use the leftmost parent
392
                                         'cannot go before the null: revision')
393
        if r.revno is None:
394
            # We need to use the repository history here
395
            rev = branch.repository.get_revision(r.rev_id)
396
            if not rev.parent_ids:
397
                revno = 0
398
                revision_id = None
399
            else:
400
                revision_id = rev.parent_ids[0]
401
                try:
402
                    revno = revs.index(revision_id) + 1
403
                except ValueError:
404
                    revno = None
405
        else:
406
            revno = r.revno - 1
407
            try:
408
                revision_id = branch.get_rev_id(revno, revs)
1948.4.26 by John Arbash Meinel
Get rid of direct imports of exceptions
409
            except errors.NoSuchRevision:
1948.4.27 by John Arbash Meinel
Deprecate calling RevisionSpec directly, and instead use a helper function. Also merge the old RevisionSpec_int class into RevisionSpec_revno
410
                raise errors.InvalidRevisionSpec(self.user_spec,
1948.4.13 by John Arbash Meinel
Going before:0 is an error, and if you are on another history, use the leftmost parent
411
                                                 branch)
412
        return RevisionInfo(branch, revno, revision_id)
1185.1.39 by Robert Collins
Robey Pointers before: namespace to clear up usage of dates in revision parameters
413
414
SPEC_TYPES.append(RevisionSpec_before)
415
416
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
417
class RevisionSpec_tag(RevisionSpec):
2023.1.1 by ghigo
add topics help
418
    """To be implemented."""
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
419
    prefix = 'tag:'
420
421
    def _match_on(self, branch, revs):
1948.4.27 by John Arbash Meinel
Deprecate calling RevisionSpec directly, and instead use a helper function. Also merge the old RevisionSpec_int class into RevisionSpec_revno
422
        raise errors.InvalidRevisionSpec(self.user_spec, branch,
1948.4.11 by John Arbash Meinel
Update and test the tag: spec
423
                                         'tag: namespace registered,'
424
                                         ' but not implemented')
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
425
426
SPEC_TYPES.append(RevisionSpec_tag)
427
428
1948.4.12 by John Arbash Meinel
Some tests for the date: spec
429
class _RevListToTimestamps(object):
430
    """This takes a list of revisions, and allows you to bisect by date"""
431
432
    __slots__ = ['revs', 'branch']
433
1688.2.2 by Guillaume Pinot
Binary search for 'date:' revision.
434
    def __init__(self, revs, branch):
435
        self.revs = revs
436
        self.branch = branch
1948.4.12 by John Arbash Meinel
Some tests for the date: spec
437
1688.2.2 by Guillaume Pinot
Binary search for 'date:' revision.
438
    def __getitem__(self, index):
1948.4.12 by John Arbash Meinel
Some tests for the date: spec
439
        """Get the date of the index'd item"""
1688.2.2 by Guillaume Pinot
Binary search for 'date:' revision.
440
        r = self.branch.repository.get_revision(self.revs[index])
441
        # TODO: Handle timezone.
442
        return datetime.datetime.fromtimestamp(r.timestamp)
1948.4.12 by John Arbash Meinel
Some tests for the date: spec
443
1688.2.2 by Guillaume Pinot
Binary search for 'date:' revision.
444
    def __len__(self):
445
        return len(self.revs)
446
447
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
448
class RevisionSpec_date(RevisionSpec):
2023.1.1 by ghigo
add topics help
449
    """Selects a revision on the basis of a datestamp.
450
451
    Supply a datestamp to select the first revision that matches the date.
452
    Date can be 'yesterday', 'today', 'tomorrow' or a YYYY-MM-DD string.
453
    Matches the first entry after a given date (either at midnight or
454
    at a specified time).
455
456
    One way to display all the changes since yesterday would be:
457
        bzr log -r date:yesterday..-1
458
459
    examples:
460
      date:yesterday            -> select the first revision since yesterday
461
      date:2006-08-14,17:10:14  -> select the first revision after
462
                                   August 14th, 2006 at 5:10pm.
463
    """    
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
464
    prefix = 'date:'
465
    _date_re = re.compile(
466
            r'(?P<date>(?P<year>\d\d\d\d)-(?P<month>\d\d)-(?P<day>\d\d))?'
467
            r'(,|T)?\s*'
468
            r'(?P<time>(?P<hour>\d\d):(?P<minute>\d\d)(:(?P<second>\d\d))?)?'
469
        )
470
471
    def _match_on(self, branch, revs):
2023.1.1 by ghigo
add topics help
472
        """Spec for date revisions:
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
473
          date:value
474
          value can be 'yesterday', 'today', 'tomorrow' or a YYYY-MM-DD string.
1185.1.39 by Robert Collins
Robey Pointers before: namespace to clear up usage of dates in revision parameters
475
          matches the first entry after a given date (either at midnight or
476
          at a specified time).
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
477
        """
2070.4.3 by John Arbash Meinel
code and doc cleanup
478
        #  XXX: This doesn't actually work
479
        #  So the proper way of saying 'give me all entries for today' is:
480
        #      -r date:yesterday..date:today
1185.1.39 by Robert Collins
Robey Pointers before: namespace to clear up usage of dates in revision parameters
481
        today = datetime.datetime.fromordinal(datetime.date.today().toordinal())
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
482
        if self.spec.lower() == 'yesterday':
483
            dt = today - datetime.timedelta(days=1)
484
        elif self.spec.lower() == 'today':
485
            dt = today
486
        elif self.spec.lower() == 'tomorrow':
487
            dt = today + datetime.timedelta(days=1)
488
        else:
489
            m = self._date_re.match(self.spec)
490
            if not m or (not m.group('date') and not m.group('time')):
1948.4.27 by John Arbash Meinel
Deprecate calling RevisionSpec directly, and instead use a helper function. Also merge the old RevisionSpec_int class into RevisionSpec_revno
491
                raise errors.InvalidRevisionSpec(self.user_spec,
1948.4.12 by John Arbash Meinel
Some tests for the date: spec
492
                                                 branch, 'invalid date')
493
494
            try:
495
                if m.group('date'):
496
                    year = int(m.group('year'))
497
                    month = int(m.group('month'))
498
                    day = int(m.group('day'))
499
                else:
500
                    year = today.year
501
                    month = today.month
502
                    day = today.day
503
504
                if m.group('time'):
505
                    hour = int(m.group('hour'))
506
                    minute = int(m.group('minute'))
507
                    if m.group('second'):
508
                        second = int(m.group('second'))
509
                    else:
510
                        second = 0
511
                else:
512
                    hour, minute, second = 0,0,0
513
            except ValueError:
1948.4.27 by John Arbash Meinel
Deprecate calling RevisionSpec directly, and instead use a helper function. Also merge the old RevisionSpec_int class into RevisionSpec_revno
514
                raise errors.InvalidRevisionSpec(self.user_spec,
1948.4.12 by John Arbash Meinel
Some tests for the date: spec
515
                                                 branch, 'invalid date')
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
516
517
            dt = datetime.datetime(year=year, month=month, day=day,
518
                    hour=hour, minute=minute, second=second)
1704.2.27 by Martin Pool
Run bisection search for revision date with lock held. (Robert Widhopf-Frenk)
519
        branch.lock_read()
520
        try:
1948.4.12 by John Arbash Meinel
Some tests for the date: spec
521
            rev = bisect.bisect(_RevListToTimestamps(revs, branch), dt)
1704.2.27 by Martin Pool
Run bisection search for revision date with lock held. (Robert Widhopf-Frenk)
522
        finally:
523
            branch.unlock()
1688.2.2 by Guillaume Pinot
Binary search for 'date:' revision.
524
        if rev == len(revs):
525
            return RevisionInfo(branch, None)
526
        else:
527
            return RevisionInfo(branch, rev + 1)
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
528
529
SPEC_TYPES.append(RevisionSpec_date)
530
531
532
class RevisionSpec_ancestor(RevisionSpec):
2023.1.1 by ghigo
add topics help
533
    """Selects a common ancestor with a second branch.
534
535
    Supply the path to a branch to select the common ancestor.
536
537
    The common ancestor is the last revision that existed in both
538
    branches. Usually this is the branch point, but it could also be
539
    a revision that was merged.
540
541
    This is frequently used with 'diff' to return all of the changes
542
    that your branch introduces, while excluding the changes that you
543
    have not merged from the remote branch.
544
545
    examples:
546
      ancestor:/path/to/branch
547
      bzr diff -r ancestor:../../mainline/branch
548
    """
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
549
    prefix = 'ancestor:'
550
551
    def _match_on(self, branch, revs):
1948.4.16 by John Arbash Meinel
Move the tests into the associated tester, remove redundant tests, some small PEP8 changes
552
        from bzrlib.branch import Branch
1948.4.18 by John Arbash Meinel
Update branch: spec and tests
553
1948.4.27 by John Arbash Meinel
Deprecate calling RevisionSpec directly, and instead use a helper function. Also merge the old RevisionSpec_int class into RevisionSpec_revno
554
        trace.mutter('matching ancestor: on: %s, %s', self.spec, branch)
1948.4.17 by John Arbash Meinel
Update tests for ancestor: spec
555
        other_branch = Branch.open(self.spec)
1390 by Robert Collins
pair programming worx... merge integration and weave
556
        revision_a = branch.last_revision()
557
        revision_b = other_branch.last_revision()
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
558
        for r, b in ((revision_a, branch), (revision_b, other_branch)):
1948.4.18 by John Arbash Meinel
Update branch: spec and tests
559
            if r in (None, revision.NULL_REVISION):
1948.4.26 by John Arbash Meinel
Get rid of direct imports of exceptions
560
                raise errors.NoCommits(b)
1948.4.18 by John Arbash Meinel
Update branch: spec and tests
561
        revision_source = revision.MultipleRevisionSources(
562
                branch.repository, other_branch.repository)
563
        rev_id = revision.common_ancestor(revision_a, revision_b,
564
                                          revision_source)
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
565
        try:
566
            revno = branch.revision_id_to_revno(rev_id)
1948.4.26 by John Arbash Meinel
Get rid of direct imports of exceptions
567
        except errors.NoSuchRevision:
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
568
            revno = None
569
        return RevisionInfo(branch, revno, rev_id)
570
        
571
SPEC_TYPES.append(RevisionSpec_ancestor)
1432 by Robert Collins
branch: namespace
572
1948.4.16 by John Arbash Meinel
Move the tests into the associated tester, remove redundant tests, some small PEP8 changes
573
1432 by Robert Collins
branch: namespace
574
class RevisionSpec_branch(RevisionSpec):
2023.1.1 by ghigo
add topics help
575
    """Selects the last revision of a specified branch.
576
577
    Supply the path to a branch to select its last revision.
578
579
    examples:
580
      branch:/path/to/branch
1432 by Robert Collins
branch: namespace
581
    """
582
    prefix = 'branch:'
583
584
    def _match_on(self, branch, revs):
1948.4.18 by John Arbash Meinel
Update branch: spec and tests
585
        from bzrlib.branch import Branch
586
        other_branch = Branch.open(self.spec)
1432 by Robert Collins
branch: namespace
587
        revision_b = other_branch.last_revision()
1948.4.18 by John Arbash Meinel
Update branch: spec and tests
588
        if revision_b in (None, revision.NULL_REVISION):
1948.4.26 by John Arbash Meinel
Get rid of direct imports of exceptions
589
            raise errors.NoCommits(other_branch)
1432 by Robert Collins
branch: namespace
590
        # pull in the remote revisions so we can diff
1534.1.31 by Robert Collins
Deprecated fetch.fetch and fetch.greedy_fetch for branch.fetch, and move the Repository.fetch internals to InterRepo and InterWeaveRepo.
591
        branch.fetch(other_branch, revision_b)
1432 by Robert Collins
branch: namespace
592
        try:
593
            revno = branch.revision_id_to_revno(revision_b)
1948.4.26 by John Arbash Meinel
Get rid of direct imports of exceptions
594
        except errors.NoSuchRevision:
1432 by Robert Collins
branch: namespace
595
            revno = None
596
        return RevisionInfo(branch, revno, revision_b)
597
        
598
SPEC_TYPES.append(RevisionSpec_branch)