~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/revisionspec.py

  • Committer: Vincent Ladeuil
  • Date: 2009-06-22 12:52:39 UTC
  • mto: (4471.1.1 integration)
  • mto: This revision was merged to the branch mainline in revision 4472.
  • Revision ID: v.ladeuil+lp@free.fr-20090622125239-kabo9smxt9c3vnir
Use a consistent scheme for naming pyrex source files.

Show diffs side-by-side

added added

removed removed

Lines of Context:
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
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
 
 
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
16
 
 
17
 
 
18
import re
 
19
 
 
20
from bzrlib.lazy_import import lazy_import
 
21
lazy_import(globals(), """
18
22
import bisect
19
23
import datetime
20
 
import re
 
24
""")
21
25
 
22
26
from bzrlib import (
23
27
    errors,
24
28
    osutils,
 
29
    registry,
25
30
    revision,
26
31
    symbol_versioning,
27
32
    trace,
28
 
    tsort,
29
33
    )
30
34
 
31
35
 
111
115
 
112
116
# classes in this list should have a "prefix" attribute, against which
113
117
# string specs are matched
114
 
SPEC_TYPES = []
115
118
_revno_regex = None
116
119
 
117
120
 
135
138
    """
136
139
 
137
140
    prefix = None
138
 
 
139
 
    def __new__(cls, spec, _internal=False):
140
 
        if _internal:
141
 
            return object.__new__(cls, spec, _internal=_internal)
142
 
 
143
 
        symbol_versioning.warn('Creating a RevisionSpec directly has'
144
 
                               ' been deprecated in version 0.11. Use'
145
 
                               ' RevisionSpec.from_string()'
146
 
                               ' instead.',
147
 
                               DeprecationWarning, stacklevel=2)
148
 
        return RevisionSpec.from_string(spec)
 
141
    wants_revision_history = True
149
142
 
150
143
    @staticmethod
151
144
    def from_string(spec):
160
153
 
161
154
        if spec is None:
162
155
            return RevisionSpec(None, _internal=True)
163
 
        for spectype in SPEC_TYPES:
164
 
            if spec.startswith(spectype.prefix):
 
156
        match = revspec_registry.get_prefix(spec)
 
157
        if match is not None:
 
158
            spectype, specsuffix = match
 
159
            trace.mutter('Returning RevisionSpec %s for %s',
 
160
                         spectype.__name__, spec)
 
161
            return spectype(spec, _internal=True)
 
162
        else:
 
163
            for spectype in SPEC_TYPES:
165
164
                trace.mutter('Returning RevisionSpec %s for %s',
166
165
                             spectype.__name__, spec)
167
 
                return spectype(spec, _internal=True)
168
 
        else:
 
166
                if spec.startswith(spectype.prefix):
 
167
                    return spectype(spec, _internal=True)
169
168
            # RevisionSpec_revno is special cased, because it is the only
170
169
            # one that directly handles plain integers
171
170
            # TODO: This should not be special cased rather it should be
215
214
 
216
215
    def in_history(self, branch):
217
216
        if branch:
218
 
            revs = branch.revision_history()
 
217
            if self.wants_revision_history:
 
218
                revs = branch.revision_history()
 
219
            else:
 
220
                revs = None
219
221
        else:
220
222
            # this should never trigger.
221
223
            # TODO: make it a deprecated code path. RBC 20060928
248
250
        """
249
251
        return self.in_history(context_branch).rev_id
250
252
 
 
253
    def as_tree(self, context_branch):
 
254
        """Return the tree object for this revisions spec.
 
255
 
 
256
        Some revision specs require a context_branch to be able to determine
 
257
        the revision id and access the repository. Not all specs will make
 
258
        use of it.
 
259
        """
 
260
        return self._as_tree(context_branch)
 
261
 
 
262
    def _as_tree(self, context_branch):
 
263
        """Implementation of as_tree().
 
264
 
 
265
        Classes should override this function to provide appropriate
 
266
        functionality. The default is to just call '.as_revision_id()'
 
267
        and get the revision tree from context_branch's repository.
 
268
        """
 
269
        revision_id = self.as_revision_id(context_branch)
 
270
        return context_branch.repository.revision_tree(revision_id)
 
271
 
251
272
    def __repr__(self):
252
273
        # this is mostly for helping with testing
253
274
        return '<%s %s>' % (self.__class__.__name__,
254
275
                              self.user_spec)
255
 
    
 
276
 
256
277
    def needs_branch(self):
257
278
        """Whether this revision spec needs a branch.
258
279
 
262
283
 
263
284
    def get_branch(self):
264
285
        """When the revision specifier contains a branch location, return it.
265
 
        
 
286
 
266
287
        Otherwise, return None.
267
288
        """
268
289
        return None
282
303
    than the branch's history, the first revision is returned.
283
304
    Examples::
284
305
 
285
 
      revno:1                   -> return the first revision
 
306
      revno:1                   -> return the first revision of this branch
286
307
      revno:3:/path/to/branch   -> return the 3rd revision of
287
308
                                   the branch '/path/to/branch'
288
309
      revno:-1                  -> The last revision in a branch.
292
313
                                   your history is very long.
293
314
    """
294
315
    prefix = 'revno:'
 
316
    wants_revision_history = False
295
317
 
296
318
    def _match_on(self, branch, revs):
297
319
        """Lookup a revision by revision number"""
318
340
                dotted = False
319
341
            except ValueError:
320
342
                # dotted decimal. This arguably should not be here
321
 
                # but the from_string method is a little primitive 
 
343
                # but the from_string method is a little primitive
322
344
                # right now - RBC 20060928
323
345
                try:
324
346
                    match_revno = tuple((int(number) for number in revno_spec.split('.')))
336
358
            revs_or_none = None
337
359
 
338
360
        if dotted:
339
 
            branch.lock_read()
340
361
            try:
341
 
                revision_id_to_revno = branch.get_revision_id_to_revno_map()
342
 
                revisions = [revision_id for revision_id, revno
343
 
                             in revision_id_to_revno.iteritems()
344
 
                             if revno == match_revno]
345
 
            finally:
346
 
                branch.unlock()
347
 
            if len(revisions) != 1:
348
 
                return branch, None, None
 
362
                revision_id = branch.dotted_revno_to_revision_id(match_revno,
 
363
                    _cache_reverse=True)
 
364
            except errors.NoSuchRevision:
 
365
                raise errors.InvalidRevisionSpec(self.user_spec, branch)
349
366
            else:
350
367
                # there is no traditional 'revno' for dotted-decimal revnos.
351
368
                # so for  API compatability we return None.
352
 
                return branch, None, revisions[0]
 
369
                return branch, None, revision_id
353
370
        else:
354
371
            last_revno, last_revision_id = branch.last_revision_info()
355
372
            if revno < 0:
379
396
        else:
380
397
            return self.spec[self.spec.find(':')+1:]
381
398
 
382
 
# Old compatibility 
 
399
# Old compatibility
383
400
RevisionSpec_int = RevisionSpec_revno
384
401
 
385
 
SPEC_TYPES.append(RevisionSpec_revno)
386
402
 
387
403
 
388
404
class RevisionSpec_revid(RevisionSpec):
391
407
    help_txt = """Selects a revision using the revision id.
392
408
 
393
409
    Supply a specific revision id, that can be used to specify any
394
 
    revision id in the ancestry of the branch. 
 
410
    revision id in the ancestry of the branch.
395
411
    Including merges, and pending merges.
396
412
    Examples::
397
413
 
410
426
    def _as_revision_id(self, context_branch):
411
427
        return osutils.safe_revision_id(self.spec, warn=False)
412
428
 
413
 
SPEC_TYPES.append(RevisionSpec_revid)
414
429
 
415
430
 
416
431
class RevisionSpec_last(RevisionSpec):
462
477
        revno, revision_id = self._revno_and_revision_id(context_branch, None)
463
478
        return revision_id
464
479
 
465
 
SPEC_TYPES.append(RevisionSpec_last)
466
480
 
467
481
 
468
482
class RevisionSpec_before(RevisionSpec):
470
484
 
471
485
    help_txt = """Selects the parent of the revision specified.
472
486
 
473
 
    Supply any revision spec to return the parent of that revision.
 
487
    Supply any revision spec to return the parent of that revision.  This is
 
488
    mostly useful when inspecting revisions that are not in the revision history
 
489
    of a branch.
 
490
 
474
491
    It is an error to request the parent of the null revision (before:0).
475
 
    This is mostly useful when inspecting revisions that are not in the
476
 
    revision history of a branch.
477
492
 
478
493
    Examples::
479
494
 
480
495
      before:1913    -> Return the parent of revno 1913 (revno 1912)
481
496
      before:revid:aaaa@bbbb-1234567890  -> return the parent of revision
482
497
                                            aaaa@bbbb-1234567890
483
 
      bzr diff -r before:revid:aaaa..revid:aaaa
484
 
            -> Find the changes between revision 'aaaa' and its parent.
485
 
               (what changes did 'aaaa' introduce)
 
498
      bzr diff -r before:1913..1913
 
499
            -> Find the changes between revision 1913 and its parent (1912).
 
500
               (What changes did revision 1913 introduce).
 
501
               This is equivalent to:  bzr diff -c 1913
486
502
    """
487
503
 
488
504
    prefix = 'before:'
489
 
    
 
505
 
490
506
    def _match_on(self, branch, revs):
491
507
        r = RevisionSpec.from_string(self.spec)._match_on(branch, revs)
492
508
        if r.revno == 0:
517
533
        base_revspec = RevisionSpec.from_string(self.spec)
518
534
        base_revision_id = base_revspec.as_revision_id(context_branch)
519
535
        if base_revision_id == revision.NULL_REVISION:
520
 
            raise errors.InvalidRevisionSpec(self.user_spec, branch,
 
536
            raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
521
537
                                         'cannot go before the null: revision')
522
538
        context_repo = context_branch.repository
523
539
        context_repo.lock_read()
535
551
                'No parents for revision.')
536
552
        return parents[0]
537
553
 
538
 
SPEC_TYPES.append(RevisionSpec_before)
539
554
 
540
555
 
541
556
class RevisionSpec_tag(RevisionSpec):
557
572
    def _as_revision_id(self, context_branch):
558
573
        return context_branch.tags.lookup_tag(self.spec)
559
574
 
560
 
SPEC_TYPES.append(RevisionSpec_tag)
561
575
 
562
576
 
563
577
class _RevListToTimestamps(object):
591
605
 
592
606
    One way to display all the changes since yesterday would be::
593
607
 
594
 
        bzr log -r date:yesterday..-1
 
608
        bzr log -r date:yesterday..
595
609
 
596
610
    Examples::
597
611
 
598
612
      date:yesterday            -> select the first revision since yesterday
599
613
      date:2006-08-14,17:10:14  -> select the first revision after
600
614
                                   August 14th, 2006 at 5:10pm.
601
 
    """    
 
615
    """
602
616
    prefix = 'date:'
603
617
    _date_re = re.compile(
604
618
            r'(?P<date>(?P<year>\d\d\d\d)-(?P<month>\d\d)-(?P<day>\d\d))?'
664
678
        else:
665
679
            return RevisionInfo(branch, rev + 1)
666
680
 
667
 
SPEC_TYPES.append(RevisionSpec_date)
668
681
 
669
682
 
670
683
class RevisionSpec_ancestor(RevisionSpec):
715
728
            revision_a = revision.ensure_null(branch.last_revision())
716
729
            if revision_a == revision.NULL_REVISION:
717
730
                raise errors.NoCommits(branch)
 
731
            if other_location == '':
 
732
                other_location = branch.get_parent()
718
733
            other_branch = Branch.open(other_location)
719
734
            other_branch.lock_read()
720
735
            try:
732
747
            branch.unlock()
733
748
 
734
749
 
735
 
SPEC_TYPES.append(RevisionSpec_ancestor)
736
750
 
737
751
 
738
752
class RevisionSpec_branch(RevisionSpec):
772
786
            raise errors.NoCommits(other_branch)
773
787
        return last_revision
774
788
 
775
 
SPEC_TYPES.append(RevisionSpec_branch)
 
789
    def _as_tree(self, context_branch):
 
790
        from bzrlib.branch import Branch
 
791
        other_branch = Branch.open(self.spec)
 
792
        last_revision = other_branch.last_revision()
 
793
        last_revision = revision.ensure_null(last_revision)
 
794
        if last_revision == revision.NULL_REVISION:
 
795
            raise errors.NoCommits(other_branch)
 
796
        return other_branch.repository.revision_tree(last_revision)
 
797
 
776
798
 
777
799
 
778
800
class RevisionSpec_submit(RevisionSpec_ancestor):
782
804
 
783
805
    Diffing against this shows all the changes that were made in this branch,
784
806
    and is a good predictor of what merge will do.  The submit branch is
785
 
    used by the bundle and merge directive comands.  If no submit branch
 
807
    used by the bundle and merge directive commands.  If no submit branch
786
808
    is specified, the parent branch is used instead.
787
809
 
788
810
    The common ancestor is the last revision that existed in both
817
839
            self._get_submit_location(context_branch))
818
840
 
819
841
 
820
 
SPEC_TYPES.append(RevisionSpec_submit)
 
842
revspec_registry = registry.Registry()
 
843
def _register_revspec(revspec):
 
844
    revspec_registry.register(revspec.prefix, revspec)
 
845
 
 
846
_register_revspec(RevisionSpec_revno)
 
847
_register_revspec(RevisionSpec_revid)
 
848
_register_revspec(RevisionSpec_last)
 
849
_register_revspec(RevisionSpec_before)
 
850
_register_revspec(RevisionSpec_tag)
 
851
_register_revspec(RevisionSpec_date)
 
852
_register_revspec(RevisionSpec_ancestor)
 
853
_register_revspec(RevisionSpec_branch)
 
854
_register_revspec(RevisionSpec_submit)
 
855
 
 
856
SPEC_TYPES = symbol_versioning.deprecated_list(
 
857
    symbol_versioning.deprecated_in((1, 12, 0)), "SPEC_TYPES", [])