~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/revisionspec.py

  • Committer: John Arbash Meinel
  • Date: 2006-08-23 23:49:54 UTC
  • mto: This revision was merged to the branch mainline in revision 1979.
  • Revision ID: john@arbash-meinel.com-20060823234954-5153c0f043a564b8
Deprecate calling RevisionSpec directly, and instead use a helper function. Also merge the old RevisionSpec_int class into RevisionSpec_revno

Show diffs side-by-side

added added

removed removed

Lines of Context:
22
22
from bzrlib import (
23
23
    errors,
24
24
    revision,
 
25
    symbol_versioning,
 
26
    trace,
25
27
    )
26
28
 
27
29
 
113
115
 
114
116
    prefix = None
115
117
 
116
 
    def __new__(cls, spec, foo=_marker):
117
 
        """Parse a revision specifier.
 
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'
 
124
                               ' bzrlib.revisionspec.get_revision_spec()'
 
125
                               ' instead.',
 
126
                               DeprecationWarning, stacklevel=2)
 
127
        return get_revision_spec(spec)
 
128
 
 
129
    def __init__(self, spec, _internal=False):
 
130
        """Create a RevisionSpec referring to the Null revision.
 
131
 
 
132
        :param spec: The original spec supplied by the user
 
133
        :param _internal: Used to ensure that RevisionSpec is not being
 
134
            called directly. Only from get_revision_spec()
118
135
        """
119
 
        if spec is None:
120
 
            return object.__new__(RevisionSpec, spec)
121
 
 
122
 
        try:
123
 
            spec = int(spec)
124
 
        except ValueError:
125
 
            pass
126
 
 
127
 
        if isinstance(spec, int):
128
 
            return object.__new__(RevisionSpec_int, spec)
129
 
        elif isinstance(spec, basestring):
130
 
            for spectype in SPEC_TYPES:
131
 
                if spec.startswith(spectype.prefix):
132
 
                    return object.__new__(spectype, spec)
133
 
            else:
134
 
                raise errors.NoSuchRevisionSpec(spec)
135
 
        else:
136
 
            raise TypeError('Unhandled revision type %s' % spec)
137
 
 
138
 
    def __init__(self, spec):
 
136
        if not _internal:
 
137
            # XXX: Update this after 0.10 is released
 
138
            symbol_versioning.warn('Creating a RevisionSpec directly has'
 
139
                                   ' been deprecated in version 0.11. Use'
 
140
                                   ' bzrlib.revisionspec.get_revision_spec()'
 
141
                                   ' instead.',
 
142
                                   DeprecationWarning, stacklevel=2)
 
143
        self.user_spec = spec
139
144
        if self.prefix and spec.startswith(self.prefix):
140
145
            spec = spec[len(self.prefix):]
141
146
        self.spec = spec
142
147
 
143
148
    def _match_on(self, branch, revs):
 
149
        trace.mutter('Returning RevisionSpec._match_on: None')
144
150
        return RevisionInfo(branch, 0, None)
145
151
 
146
152
    def _match_on_and_check(self, branch, revs):
151
157
            # special case - the empty tree
152
158
            return info
153
159
        elif self.prefix:
154
 
            raise errors.InvalidRevisionSpec(self.prefix + self.spec, branch)
 
160
            raise errors.InvalidRevisionSpec(self.user_spec, branch)
155
161
        else:
156
162
            raise errors.InvalidRevisionSpec(self.spec, branch)
157
163
 
186
192
        return True
187
193
 
188
194
 
 
195
_revno_regex = None
 
196
 
 
197
def get_revision_spec(spec):
 
198
    """Parse a revision spec into a RevisionSpec object.
 
199
 
 
200
    :param spec: A string specified by the user
 
201
    :return: A RevisionSpec object that understands how to parse the
 
202
        supplied notation.
 
203
    """
 
204
    if not isinstance(spec, (type(None), basestring)):
 
205
        raise TypeError('error')
 
206
 
 
207
    if spec is None:
 
208
        return RevisionSpec(None, _internal=True)
 
209
 
 
210
    assert isinstance(spec, basestring), \
 
211
        "You should only supply strings not %s" % (type(spec),)
 
212
 
 
213
    for spectype in SPEC_TYPES:
 
214
        if spec.startswith(spectype.prefix):
 
215
            trace.mutter('Returning RevisionSpec %s for %s',
 
216
                         spectype.__name__, spec)
 
217
            return spectype(spec, _internal=True)
 
218
    else:
 
219
        # RevisionSpec_revno is special cased, because it is the only
 
220
        # one that directly handles plain integers
 
221
        global _revno_regex
 
222
        if _revno_regex is None:
 
223
            _revno_regex = re.compile(r'-?\d+(:.*)?')
 
224
        if _revno_regex.match(spec) is not None:
 
225
            return RevisionSpec_revno(spec, _internal=True)
 
226
 
 
227
        raise errors.NoSuchRevisionSpec(spec)
 
228
        
 
229
        
189
230
# private API
190
231
 
191
 
def _get_int_revno_helper(branch, revs, revno, spec):
192
 
    """Just a helper for the common functionality between int and revno specs.
193
 
 
194
 
    :param branch: The branch to lookup the revno in
195
 
    :param revno: In integer revision number
196
 
    :param revs: The list of revisions we are looking through
197
 
    :param spec: The revision spec being tested. This is only used
198
 
        to pass through to a potential exception
199
 
    :return: A RevisionInfo object (or an exception)
200
 
    """
201
 
    if revno < 0:
202
 
        if (-revno) >= len(revs):
203
 
            revno = 1
204
 
        else:
205
 
            revno = len(revs) + revno + 1
206
 
    try:
207
 
        revision_id = branch.get_rev_id(revno, revs)
208
 
    except errors.NoSuchRevision:
209
 
        raise errors.InvalidRevisionSpec(spec, branch)
210
 
    return RevisionInfo(branch, revno, revision_id)
211
 
 
212
 
 
213
 
class RevisionSpec_int(RevisionSpec):
214
 
    """Spec is a number.  Special case."""
215
 
 
216
 
    def __init__(self, spec):
217
 
        self.spec = int(spec)
218
 
 
219
 
    def _match_on(self, branch, revs):
220
 
        return _get_int_revno_helper(branch, revs, self.spec, str(self.spec))
221
 
 
222
232
 
223
233
class RevisionSpec_revno(RevisionSpec):
224
234
    prefix = 'revno:'
235
245
 
236
246
        if revno_spec == '':
237
247
            if not branch_spec:
238
 
                raise errors.InvalidRevisionSpec(self.prefix + self.spec,
 
248
                raise errors.InvalidRevisionSpec(self.user_spec,
239
249
                        branch, 'cannot have an empty revno and no branch')
240
250
            revno = None
241
251
        else:
242
252
            try:
243
253
                revno = int(revno_spec)
244
254
            except ValueError, e:
245
 
                raise errors.InvalidRevisionSpec(self.prefix + self.spec,
 
255
                raise errors.InvalidRevisionSpec(self.user_spec,
246
256
                                                 branch, e)
247
257
 
248
258
        if branch_spec:
252
262
            # because we are using a specific branch
253
263
            revs = branch.revision_history()
254
264
 
255
 
        return _get_int_revno_helper(branch, revs, revno,
256
 
                                     self.prefix + self.spec)
 
265
        if revno < 0:
 
266
            if (-revno) >= len(revs):
 
267
                revno = 1
 
268
            else:
 
269
                revno = len(revs) + revno + 1
 
270
        try:
 
271
            revision_id = branch.get_rev_id(revno, revs)
 
272
        except errors.NoSuchRevision:
 
273
            raise errors.InvalidRevisionSpec(self.user_spec, branch)
 
274
        return RevisionInfo(branch, revno, revision_id)
257
275
        
258
276
    def needs_branch(self):
259
277
        return self.spec.find(':') == -1
260
278
 
 
279
# Old compatibility 
 
280
RevisionSpec_int = RevisionSpec_revno
 
281
 
261
282
SPEC_TYPES.append(RevisionSpec_revno)
262
283
 
263
284
 
287
308
        try:
288
309
            offset = int(self.spec)
289
310
        except ValueError, e:
290
 
            raise errors.InvalidRevisionSpec(self.prefix + self.spec, branch, e)
 
311
            raise errors.InvalidRevisionSpec(self.user_spec, branch, e)
291
312
 
292
313
        if offset <= 0:
293
 
            raise errors.InvalidRevisionSpec(self.prefix + self.spec, branch,
 
314
            raise errors.InvalidRevisionSpec(self.user_spec, branch,
294
315
                                             'you must supply a positive value')
295
316
        revno = len(revs) - offset + 1
296
317
        try:
297
318
            revision_id = branch.get_rev_id(revno, revs)
298
319
        except errors.NoSuchRevision:
299
 
            raise errors.InvalidRevisionSpec(self.prefix + self.spec, branch)
 
320
            raise errors.InvalidRevisionSpec(self.user_spec, branch)
300
321
        return RevisionInfo(branch, revno, revision_id)
301
322
 
302
323
SPEC_TYPES.append(RevisionSpec_last)
309
330
    def _match_on(self, branch, revs):
310
331
        r = RevisionSpec(self.spec)._match_on(branch, revs)
311
332
        if r.revno == 0:
312
 
            raise errors.InvalidRevisionSpec(self.prefix + self.spec, branch,
 
333
            raise errors.InvalidRevisionSpec(self.user_spec, branch,
313
334
                                         'cannot go before the null: revision')
314
335
        if r.revno is None:
315
336
            # We need to use the repository history here
328
349
            try:
329
350
                revision_id = branch.get_rev_id(revno, revs)
330
351
            except errors.NoSuchRevision:
331
 
                raise errors.InvalidRevisionSpec(self.prefix + self.spec,
 
352
                raise errors.InvalidRevisionSpec(self.user_spec,
332
353
                                                 branch)
333
354
        return RevisionInfo(branch, revno, revision_id)
334
355
 
339
360
    prefix = 'tag:'
340
361
 
341
362
    def _match_on(self, branch, revs):
342
 
        raise errors.InvalidRevisionSpec(self.prefix + self.spec, branch,
 
363
        raise errors.InvalidRevisionSpec(self.user_spec, branch,
343
364
                                         'tag: namespace registered,'
344
365
                                         ' but not implemented')
345
366
 
394
415
        else:
395
416
            m = self._date_re.match(self.spec)
396
417
            if not m or (not m.group('date') and not m.group('time')):
397
 
                raise errors.InvalidRevisionSpec(self.prefix + self.spec,
 
418
                raise errors.InvalidRevisionSpec(self.user_spec,
398
419
                                                 branch, 'invalid date')
399
420
 
400
421
            try:
417
438
                else:
418
439
                    hour, minute, second = 0,0,0
419
440
            except ValueError:
420
 
                raise errors.InvalidRevisionSpec(self.prefix + self.spec,
 
441
                raise errors.InvalidRevisionSpec(self.user_spec,
421
442
                                                 branch, 'invalid date')
422
443
 
423
444
            dt = datetime.datetime(year=year, month=month, day=day,
441
462
    def _match_on(self, branch, revs):
442
463
        from bzrlib.branch import Branch
443
464
 
 
465
        trace.mutter('matching ancestor: on: %s, %s', self.spec, branch)
444
466
        other_branch = Branch.open(self.spec)
445
467
        revision_a = branch.last_revision()
446
468
        revision_b = other_branch.last_revision()