/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 = []
97
1948.4.16 by John Arbash Meinel
Move the tests into the associated tester, remove redundant tests, some small PEP8 changes
98
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
99
class RevisionSpec(object):
100
    """A parsed revision specification.
101
102
    A revision specification can be an integer, in which case it is
103
    assumed to be a revno (though this will translate negative values
104
    into positive ones); or it can be a string, in which case it is
105
    parsed for something like 'date:' or 'revid:' etc.
106
107
    Revision specs are an UI element, and they have been moved out
108
    of the branch class to leave "back-end" classes unaware of such
109
    details.  Code that gets a revno or rev_id from other code should
110
    not be using revision specs - revnos and revision ids are the
111
    accepted ways to refer to revisions internally.
112
113
    (Equivalent to the old Branch method get_revision_info())
114
    """
115
116
    prefix = None
117
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
118
    def __new__(cls, spec, _internal=False):
119
        if _internal:
120
            return object.__new__(cls, spec, _internal=_internal)
121
122
        symbol_versioning.warn('Creating a RevisionSpec directly has'
123
                               ' 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)
124
                               ' 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
125
                               ' instead.',
126
                               DeprecationWarning, stacklevel=2)
1948.4.33 by John Arbash Meinel
Switch from get_revision_spec() to RevisionSpec.from_string() (as advised by Martin)
127
        return RevisionSpec.from_string(spec)
128
129
    @staticmethod
130
    def from_string(spec):
131
        """Parse a revision spec string into a RevisionSpec object.
132
133
        :param spec: A string specified by the user
134
        :return: A RevisionSpec object that understands how to parse the
135
            supplied notation.
136
        """
137
        if not isinstance(spec, (type(None), basestring)):
138
            raise TypeError('error')
139
140
        if spec is None:
141
            return RevisionSpec(None, _internal=True)
142
143
        assert isinstance(spec, basestring), \
144
            "You should only supply strings not %s" % (type(spec),)
145
146
        for spectype in SPEC_TYPES:
147
            if spec.startswith(spectype.prefix):
148
                trace.mutter('Returning RevisionSpec %s for %s',
149
                             spectype.__name__, spec)
150
                return spectype(spec, _internal=True)
151
        else:
152
            # RevisionSpec_revno is special cased, because it is the only
153
            # one that directly handles plain integers
154
            global _revno_regex
155
            if _revno_regex is None:
156
                _revno_regex = re.compile(r'-?\d+(:.*)?$')
157
            if _revno_regex.match(spec) is not None:
158
                return RevisionSpec_revno(spec, _internal=True)
159
160
            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
161
162
    def __init__(self, spec, _internal=False):
163
        """Create a RevisionSpec referring to the Null revision.
164
165
        :param spec: The original spec supplied by the user
166
        :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)
167
            called directly. Only from RevisionSpec.from_string()
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
168
        """
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
169
        if not _internal:
170
            # XXX: Update this after 0.10 is released
171
            symbol_versioning.warn('Creating a RevisionSpec directly has'
172
                                   ' 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)
173
                                   ' 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
174
                                   ' instead.',
175
                                   DeprecationWarning, stacklevel=2)
176
        self.user_spec = spec
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
177
        if self.prefix and spec.startswith(self.prefix):
178
            spec = spec[len(self.prefix):]
179
        self.spec = spec
180
181
    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
182
        trace.mutter('Returning RevisionSpec._match_on: None')
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
183
        return RevisionInfo(branch, 0, None)
184
185
    def _match_on_and_check(self, branch, revs):
186
        info = self._match_on(branch, revs)
187
        if info:
188
            return info
189
        elif info == (0, None):
190
            # special case - the empty tree
191
            return info
192
        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
193
            raise errors.InvalidRevisionSpec(self.user_spec, branch)
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
194
        else:
1948.4.2 by John Arbash Meinel
Update _match_on_and_check to raise the right error
195
            raise errors.InvalidRevisionSpec(self.spec, branch)
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
196
197
    def in_history(self, branch):
1732.3.1 by Matthieu Moy
Implementation of -r revno:N:/path/to/branch
198
        if branch:
199
            revs = branch.revision_history()
200
        else:
201
            revs = None
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
202
        return self._match_on_and_check(branch, revs)
203
1432 by Robert Collins
branch: namespace
204
        # FIXME: in_history is somewhat broken,
205
        # it will return non-history revisions in many
206
        # circumstances. The expected facility is that
207
        # in_history only returns revision-history revs,
208
        # in_store returns any rev. RBC 20051010
209
    # aliases for now, when we fix the core logic, then they
210
    # will do what you expect.
211
    in_store = in_history
212
    in_branch = in_store
213
        
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
214
    def __repr__(self):
215
        # 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/
216
        return '<%s %s>' % (self.__class__.__name__,
217
                              self.user_spec)
1881.1.1 by Matthieu Moy
Fixed and tested "bzr diff" outside a working tree.
218
    
1881.1.4 by Matthieu Moy
needs_tree -> needs_branch
219
    def needs_branch(self):
220
        """Whether this revision spec needs a branch.
221
1711.2.99 by John Arbash Meinel
minor typo fix
222
        Set this to False the branch argument of _match_on is not used.
223
        """
1881.1.1 by Matthieu Moy
Fixed and tested "bzr diff" outside a working tree.
224
        return True
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
225
1948.4.22 by John Arbash Meinel
Refactor common code from integer revno handlers
226
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
227
_revno_regex = None
228
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
229
# private API
230
231
232
class RevisionSpec_revno(RevisionSpec):
233
    prefix = 'revno:'
234
235
    def _match_on(self, branch, revs):
236
        """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
237
        loc = self.spec.find(':')
238
        if loc == -1:
239
            revno_spec = self.spec
240
            branch_spec = None
241
        else:
242
            revno_spec = self.spec[:loc]
243
            branch_spec = self.spec[loc+1:]
244
245
        if revno_spec == '':
1948.4.6 by John Arbash Meinel
A small bugfix, and more tests for revno:
246
            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
247
                raise errors.InvalidRevisionSpec(self.user_spec,
1948.4.5 by John Arbash Meinel
Fix tests for negative entries, and add tests for revno:
248
                        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
249
            revno = None
250
        else:
251
            try:
252
                revno = int(revno_spec)
253
            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
254
                raise errors.InvalidRevisionSpec(self.user_spec,
1948.4.5 by John Arbash Meinel
Fix tests for negative entries, and add tests for revno:
255
                                                 branch, e)
1948.4.1 by John Arbash Meinel
Update number parsers to raise InvalidRevisionSpec. Update revno: itself so it supports negative numbers
256
1948.4.6 by John Arbash Meinel
A small bugfix, and more tests for revno:
257
        if branch_spec:
1948.4.1 by John Arbash Meinel
Update number parsers to raise InvalidRevisionSpec. Update revno: itself so it supports negative numbers
258
            from bzrlib.branch import Branch
259
            branch = Branch.open(branch_spec)
1948.4.22 by John Arbash Meinel
Refactor common code from integer revno handlers
260
            # Need to use a new revision history
261
            # because we are using a specific branch
262
            revs = branch.revision_history()
263
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
264
        if revno < 0:
265
            if (-revno) >= len(revs):
266
                revno = 1
267
            else:
268
                revno = len(revs) + revno + 1
269
        try:
270
            revision_id = branch.get_rev_id(revno, revs)
271
        except errors.NoSuchRevision:
272
            raise errors.InvalidRevisionSpec(self.user_spec, branch)
273
        return RevisionInfo(branch, revno, revision_id)
1881.1.1 by Matthieu Moy
Fixed and tested "bzr diff" outside a working tree.
274
        
1881.1.4 by Matthieu Moy
needs_tree -> needs_branch
275
    def needs_branch(self):
1881.1.1 by Matthieu Moy
Fixed and tested "bzr diff" outside a working tree.
276
        return self.spec.find(':') == -1
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
277
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
278
# Old compatibility 
279
RevisionSpec_int = RevisionSpec_revno
280
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
281
SPEC_TYPES.append(RevisionSpec_revno)
282
283
284
class RevisionSpec_revid(RevisionSpec):
285
    prefix = 'revid:'
286
287
    def _match_on(self, branch, revs):
288
        try:
1948.4.2 by John Arbash Meinel
Update _match_on_and_check to raise the right error
289
            revno = revs.index(self.spec) + 1
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
290
        except ValueError:
1948.4.2 by John Arbash Meinel
Update _match_on_and_check to raise the right error
291
            revno = None
292
        return RevisionInfo(branch, revno, self.spec)
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
293
294
SPEC_TYPES.append(RevisionSpec_revid)
295
296
297
class RevisionSpec_last(RevisionSpec):
1185.1.39 by Robert Collins
Robey Pointers before: namespace to clear up usage of dates in revision parameters
298
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
299
    prefix = 'last:'
300
301
    def _match_on(self, branch, revs):
1948.4.9 by John Arbash Meinel
Cleanup and test last:
302
        if self.spec == '':
303
            if not revs:
1948.4.26 by John Arbash Meinel
Get rid of direct imports of exceptions
304
                raise errors.NoCommits(branch)
1948.4.9 by John Arbash Meinel
Cleanup and test last:
305
            return RevisionInfo(branch, len(revs), revs[-1])
306
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
307
        try:
308
            offset = int(self.spec)
1948.4.9 by John Arbash Meinel
Cleanup and test last:
309
        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
310
            raise errors.InvalidRevisionSpec(self.user_spec, branch, e)
1948.4.9 by John Arbash Meinel
Cleanup and test last:
311
312
        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
313
            raise errors.InvalidRevisionSpec(self.user_spec, branch,
1948.4.9 by John Arbash Meinel
Cleanup and test last:
314
                                             'you must supply a positive value')
315
        revno = len(revs) - offset + 1
316
        try:
317
            revision_id = branch.get_rev_id(revno, revs)
318
        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
319
            raise errors.InvalidRevisionSpec(self.user_spec, branch)
1948.4.9 by John Arbash Meinel
Cleanup and test last:
320
        return RevisionInfo(branch, revno, revision_id)
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
321
322
SPEC_TYPES.append(RevisionSpec_last)
323
324
1185.1.39 by Robert Collins
Robey Pointers before: namespace to clear up usage of dates in revision parameters
325
class RevisionSpec_before(RevisionSpec):
326
327
    prefix = 'before:'
328
    
329
    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)
330
        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
331
        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
332
            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
333
                                         'cannot go before the null: revision')
334
        if r.revno is None:
335
            # We need to use the repository history here
336
            rev = branch.repository.get_revision(r.rev_id)
337
            if not rev.parent_ids:
338
                revno = 0
339
                revision_id = None
340
            else:
341
                revision_id = rev.parent_ids[0]
342
                try:
343
                    revno = revs.index(revision_id) + 1
344
                except ValueError:
345
                    revno = None
346
        else:
347
            revno = r.revno - 1
348
            try:
349
                revision_id = branch.get_rev_id(revno, revs)
1948.4.26 by John Arbash Meinel
Get rid of direct imports of exceptions
350
            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
351
                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
352
                                                 branch)
353
        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
354
355
SPEC_TYPES.append(RevisionSpec_before)
356
357
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
358
class RevisionSpec_tag(RevisionSpec):
359
    prefix = 'tag:'
360
361
    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
362
        raise errors.InvalidRevisionSpec(self.user_spec, branch,
1948.4.11 by John Arbash Meinel
Update and test the tag: spec
363
                                         'tag: namespace registered,'
364
                                         ' but not implemented')
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
365
366
SPEC_TYPES.append(RevisionSpec_tag)
367
368
1948.4.12 by John Arbash Meinel
Some tests for the date: spec
369
class _RevListToTimestamps(object):
370
    """This takes a list of revisions, and allows you to bisect by date"""
371
372
    __slots__ = ['revs', 'branch']
373
1688.2.2 by Guillaume Pinot
Binary search for 'date:' revision.
374
    def __init__(self, revs, branch):
375
        self.revs = revs
376
        self.branch = branch
1948.4.12 by John Arbash Meinel
Some tests for the date: spec
377
1688.2.2 by Guillaume Pinot
Binary search for 'date:' revision.
378
    def __getitem__(self, index):
1948.4.12 by John Arbash Meinel
Some tests for the date: spec
379
        """Get the date of the index'd item"""
1688.2.2 by Guillaume Pinot
Binary search for 'date:' revision.
380
        r = self.branch.repository.get_revision(self.revs[index])
381
        # TODO: Handle timezone.
382
        return datetime.datetime.fromtimestamp(r.timestamp)
1948.4.12 by John Arbash Meinel
Some tests for the date: spec
383
1688.2.2 by Guillaume Pinot
Binary search for 'date:' revision.
384
    def __len__(self):
385
        return len(self.revs)
386
387
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
388
class RevisionSpec_date(RevisionSpec):
389
    prefix = 'date:'
390
    _date_re = re.compile(
391
            r'(?P<date>(?P<year>\d\d\d\d)-(?P<month>\d\d)-(?P<day>\d\d))?'
392
            r'(,|T)?\s*'
393
            r'(?P<time>(?P<hour>\d\d):(?P<minute>\d\d)(:(?P<second>\d\d))?)?'
394
        )
395
396
    def _match_on(self, branch, revs):
397
        """
398
        Spec for date revisions:
399
          date:value
400
          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
401
          matches the first entry after a given date (either at midnight or
402
          at a specified time).
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
403
404
          So the proper way of saying 'give me all entries for today' is:
1711.2.90 by John Arbash Meinel
Fix the docstring of RevisionSpec_date (bug #31276)
405
              -r date:yesterday..date:today
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
406
        """
1185.1.39 by Robert Collins
Robey Pointers before: namespace to clear up usage of dates in revision parameters
407
        today = datetime.datetime.fromordinal(datetime.date.today().toordinal())
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
408
        if self.spec.lower() == 'yesterday':
409
            dt = today - datetime.timedelta(days=1)
410
        elif self.spec.lower() == 'today':
411
            dt = today
412
        elif self.spec.lower() == 'tomorrow':
413
            dt = today + datetime.timedelta(days=1)
414
        else:
415
            m = self._date_re.match(self.spec)
416
            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
417
                raise errors.InvalidRevisionSpec(self.user_spec,
1948.4.12 by John Arbash Meinel
Some tests for the date: spec
418
                                                 branch, 'invalid date')
419
420
            try:
421
                if m.group('date'):
422
                    year = int(m.group('year'))
423
                    month = int(m.group('month'))
424
                    day = int(m.group('day'))
425
                else:
426
                    year = today.year
427
                    month = today.month
428
                    day = today.day
429
430
                if m.group('time'):
431
                    hour = int(m.group('hour'))
432
                    minute = int(m.group('minute'))
433
                    if m.group('second'):
434
                        second = int(m.group('second'))
435
                    else:
436
                        second = 0
437
                else:
438
                    hour, minute, second = 0,0,0
439
            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
440
                raise errors.InvalidRevisionSpec(self.user_spec,
1948.4.12 by John Arbash Meinel
Some tests for the date: spec
441
                                                 branch, 'invalid date')
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
442
443
            dt = datetime.datetime(year=year, month=month, day=day,
444
                    hour=hour, minute=minute, second=second)
1704.2.27 by Martin Pool
Run bisection search for revision date with lock held. (Robert Widhopf-Frenk)
445
        branch.lock_read()
446
        try:
1948.4.12 by John Arbash Meinel
Some tests for the date: spec
447
            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)
448
        finally:
449
            branch.unlock()
1688.2.2 by Guillaume Pinot
Binary search for 'date:' revision.
450
        if rev == len(revs):
451
            return RevisionInfo(branch, None)
452
        else:
453
            return RevisionInfo(branch, rev + 1)
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
454
455
SPEC_TYPES.append(RevisionSpec_date)
456
457
458
class RevisionSpec_ancestor(RevisionSpec):
459
    prefix = 'ancestor:'
460
461
    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
462
        from bzrlib.branch import Branch
1948.4.18 by John Arbash Meinel
Update branch: spec and tests
463
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
464
        trace.mutter('matching ancestor: on: %s, %s', self.spec, branch)
1948.4.17 by John Arbash Meinel
Update tests for ancestor: spec
465
        other_branch = Branch.open(self.spec)
1390 by Robert Collins
pair programming worx... merge integration and weave
466
        revision_a = branch.last_revision()
467
        revision_b = other_branch.last_revision()
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
468
        for r, b in ((revision_a, branch), (revision_b, other_branch)):
1948.4.18 by John Arbash Meinel
Update branch: spec and tests
469
            if r in (None, revision.NULL_REVISION):
1948.4.26 by John Arbash Meinel
Get rid of direct imports of exceptions
470
                raise errors.NoCommits(b)
1948.4.18 by John Arbash Meinel
Update branch: spec and tests
471
        revision_source = revision.MultipleRevisionSources(
472
                branch.repository, other_branch.repository)
473
        rev_id = revision.common_ancestor(revision_a, revision_b,
474
                                          revision_source)
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
475
        try:
476
            revno = branch.revision_id_to_revno(rev_id)
1948.4.26 by John Arbash Meinel
Get rid of direct imports of exceptions
477
        except errors.NoSuchRevision:
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
478
            revno = None
479
        return RevisionInfo(branch, revno, rev_id)
480
        
481
SPEC_TYPES.append(RevisionSpec_ancestor)
1432 by Robert Collins
branch: namespace
482
1948.4.16 by John Arbash Meinel
Move the tests into the associated tester, remove redundant tests, some small PEP8 changes
483
1432 by Robert Collins
branch: namespace
484
class RevisionSpec_branch(RevisionSpec):
485
    """A branch: revision specifier.
486
487
    This takes the path to a branch and returns its tip revision id.
488
    """
489
    prefix = 'branch:'
490
491
    def _match_on(self, branch, revs):
1948.4.18 by John Arbash Meinel
Update branch: spec and tests
492
        from bzrlib.branch import Branch
493
        other_branch = Branch.open(self.spec)
1432 by Robert Collins
branch: namespace
494
        revision_b = other_branch.last_revision()
1948.4.18 by John Arbash Meinel
Update branch: spec and tests
495
        if revision_b in (None, revision.NULL_REVISION):
1948.4.26 by John Arbash Meinel
Get rid of direct imports of exceptions
496
            raise errors.NoCommits(other_branch)
1432 by Robert Collins
branch: namespace
497
        # 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.
498
        branch.fetch(other_branch, revision_b)
1432 by Robert Collins
branch: namespace
499
        try:
500
            revno = branch.revision_id_to_revno(revision_b)
1948.4.26 by John Arbash Meinel
Get rid of direct imports of exceptions
501
        except errors.NoSuchRevision:
1432 by Robert Collins
branch: namespace
502
            revno = None
503
        return RevisionInfo(branch, revno, revision_b)
504
        
505
SPEC_TYPES.append(RevisionSpec_branch)