~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/revisionspec.py

  • Committer: Lalo Martins
  • Date: 2005-09-14 05:22:13 UTC
  • mfrom: (1185.1.10)
  • mto: (1185.1.22)
  • mto: This revision was merged to the branch mainline in revision 1390.
  • Revision ID: lalo@exoweb.net-20050914052213-2aa5c1005959abdf
merging from Robert's integration branch

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
 
18
18
import datetime
19
19
import re
20
 
from bzrlib.errors import BzrError, NoSuchRevision, NoCommits
 
20
from bzrlib.errors import BzrError, NoSuchRevision
21
21
 
22
22
_marker = []
23
23
 
49
49
            self.rev_id = rev_id
50
50
 
51
51
    def __nonzero__(self):
52
 
        # first the easy ones...
53
 
        if self.rev_id is None:
54
 
            return False
55
 
        if self.revno is not None:
56
 
            return True
57
 
        # TODO: otherwise, it should depend on how I was built -
58
 
        # if it's in_history(branch), then check revision_history(),
59
 
        # if it's in_store(branch), do the check below
60
 
        return self.branch.revision_store.has_id(self.rev_id)
 
52
        return not (self.revno is None or self.rev_id is None)
61
53
 
62
54
    def __len__(self):
63
55
        return 2
151
143
        revs = branch.revision_history()
152
144
        return self._match_on_and_check(branch, revs)
153
145
 
154
 
        # FIXME: in_history is somewhat broken,
155
 
        # it will return non-history revisions in many
156
 
        # circumstances. The expected facility is that
157
 
        # in_history only returns revision-history revs,
158
 
        # in_store returns any rev. RBC 20051010
159
 
    # aliases for now, when we fix the core logic, then they
160
 
    # will do what you expect.
161
 
    in_store = in_history
162
 
    in_branch = in_store
163
 
        
164
146
    def __repr__(self):
165
147
        # this is mostly for helping with testing
166
148
        return '<%s %s%s>' % (self.__class__.__name__,
210
192
 
211
193
 
212
194
class RevisionSpec_last(RevisionSpec):
213
 
 
214
195
    prefix = 'last:'
215
196
 
216
197
    def _match_on(self, branch, revs):
226
207
SPEC_TYPES.append(RevisionSpec_last)
227
208
 
228
209
 
229
 
class RevisionSpec_before(RevisionSpec):
230
 
 
231
 
    prefix = 'before:'
232
 
    
233
 
    def _match_on(self, branch, revs):
234
 
        r = RevisionSpec(self.spec)._match_on(branch, revs)
235
 
        if (r.revno is None) or (r.revno == 0):
236
 
            return r
237
 
        return RevisionInfo(branch, r.revno - 1)
238
 
 
239
 
SPEC_TYPES.append(RevisionSpec_before)
240
 
 
241
 
 
242
210
class RevisionSpec_tag(RevisionSpec):
243
211
    prefix = 'tag:'
244
212
 
261
229
        Spec for date revisions:
262
230
          date:value
263
231
          value can be 'yesterday', 'today', 'tomorrow' or a YYYY-MM-DD string.
264
 
          matches the first entry after a given date (either at midnight or
265
 
          at a specified time).
 
232
          it can also start with a '+/-/='. '+' says match the first
 
233
          entry after the given date. '-' is match the first entry before the date
 
234
          '=' is match the first entry after, but still on the given date.
 
235
 
 
236
          +2005-05-12 says find the first matching entry after May 12th, 2005 at 0:00
 
237
          -2005-05-12 says find the first matching entry before May 12th, 2005 at 0:00
 
238
          =2005-05-12 says find the first match after May 12th, 2005 at 0:00 but before
 
239
              May 13th, 2005 at 0:00
266
240
 
267
241
          So the proper way of saying 'give me all entries for today' is:
268
 
              -r date:today..date:tomorrow
 
242
              -r {date:+today}:{date:-tomorrow}
 
243
          The default is '=' when not supplied
269
244
        """
270
 
        today = datetime.datetime.fromordinal(datetime.date.today().toordinal())
 
245
        match_style = '='
 
246
        if self.spec[:1] in ('+', '-', '='):
 
247
            match_style = self.spec[:1]
 
248
            self.spec = self.spec[1:]
 
249
 
 
250
        # XXX: this should probably be using datetime.date instead
 
251
        today = datetime.datetime.today().replace(hour=0, minute=0, second=0,
 
252
                                                  microsecond=0)
271
253
        if self.spec.lower() == 'yesterday':
272
254
            dt = today - datetime.timedelta(days=1)
273
255
        elif self.spec.lower() == 'today':
296
278
            dt = datetime.datetime(year=year, month=month, day=day,
297
279
                    hour=hour, minute=minute, second=second)
298
280
        first = dt
299
 
        for i in range(len(revs)):
300
 
            r = branch.get_revision(revs[i])
301
 
            # TODO: Handle timezone.
302
 
            dt = datetime.datetime.fromtimestamp(r.timestamp)
303
 
            if first <= dt:
304
 
                return RevisionInfo(branch, i+1)
305
 
        return RevisionInfo(branch, None)
 
281
        last = None
 
282
        reversed = False
 
283
        if match_style == '-':
 
284
            reversed = True
 
285
        elif match_style == '=':
 
286
            last = dt + datetime.timedelta(days=1)
 
287
 
 
288
        if reversed:
 
289
            for i in range(len(revs)-1, -1, -1):
 
290
                r = branch.get_revision(revs[i])
 
291
                # TODO: Handle timezone.
 
292
                dt = datetime.datetime.fromtimestamp(r.timestamp)
 
293
                if first >= dt and (last is None or dt >= last):
 
294
                    return RevisionInfo(branch, i+1,)
 
295
        else:
 
296
            for i in range(len(revs)):
 
297
                r = branch.get_revision(revs[i])
 
298
                # TODO: Handle timezone.
 
299
                dt = datetime.datetime.fromtimestamp(r.timestamp)
 
300
                if first <= dt and (last is None or dt <= last):
 
301
                    return RevisionInfo(branch, i+1,)
306
302
 
307
303
SPEC_TYPES.append(RevisionSpec_date)
308
 
 
309
 
 
310
 
class RevisionSpec_ancestor(RevisionSpec):
311
 
    prefix = 'ancestor:'
312
 
 
313
 
    def _match_on(self, branch, revs):
314
 
        from branch import Branch
315
 
        from revision import common_ancestor, MultipleRevisionSources
316
 
        other_branch = Branch.open_containing(self.spec)[0]
317
 
        revision_a = branch.last_revision()
318
 
        revision_b = other_branch.last_revision()
319
 
        for r, b in ((revision_a, branch), (revision_b, other_branch)):
320
 
            if r is None:
321
 
                raise NoCommits(b)
322
 
        revision_source = MultipleRevisionSources(branch, other_branch)
323
 
        rev_id = common_ancestor(revision_a, revision_b, revision_source)
324
 
        try:
325
 
            revno = branch.revision_id_to_revno(rev_id)
326
 
        except NoSuchRevision:
327
 
            revno = None
328
 
        return RevisionInfo(branch, revno, rev_id)
329
 
        
330
 
SPEC_TYPES.append(RevisionSpec_ancestor)
331
 
 
332
 
class RevisionSpec_branch(RevisionSpec):
333
 
    """A branch: revision specifier.
334
 
 
335
 
    This takes the path to a branch and returns its tip revision id.
336
 
    """
337
 
    prefix = 'branch:'
338
 
 
339
 
    def _match_on(self, branch, revs):
340
 
        from branch import Branch
341
 
        from fetch import greedy_fetch
342
 
        other_branch = Branch.open_containing(self.spec)[0]
343
 
        revision_b = other_branch.last_revision()
344
 
        if revision_b is None:
345
 
            raise NoCommits(other_branch)
346
 
        # pull in the remote revisions so we can diff
347
 
        greedy_fetch(branch, other_branch, revision=revision_b)
348
 
        try:
349
 
            revno = branch.revision_id_to_revno(revision_b)
350
 
        except NoSuchRevision:
351
 
            revno = None
352
 
        return RevisionInfo(branch, revno, revision_b)
353
 
        
354
 
SPEC_TYPES.append(RevisionSpec_branch)