58
57
# TODO: otherwise, it should depend on how I was built -
59
58
# if it's in_history(branch), then check revision_history(),
60
59
# if it's in_store(branch), do the check below
61
return self.branch.repository.has_revision(self.rev_id)
60
return self.rev_id in self.branch.revision_store
152
151
revs = branch.revision_history()
153
152
return self._match_on_and_check(branch, revs)
155
# FIXME: in_history is somewhat broken,
156
# it will return non-history revisions in many
157
# circumstances. The expected facility is that
158
# in_history only returns revision-history revs,
159
# in_store returns any rev. RBC 20051010
160
# aliases for now, when we fix the core logic, then they
161
# will do what you expect.
162
in_store = in_history
165
154
def __repr__(self):
166
155
# this is mostly for helping with testing
167
156
return '<%s %s%s>' % (self.__class__.__name__,
206
195
return RevisionInfo(branch, revs.index(self.spec) + 1, self.spec)
207
196
except ValueError:
208
return RevisionInfo(branch, None, self.spec)
197
return RevisionInfo(branch, None)
210
199
SPEC_TYPES.append(RevisionSpec_revid)
213
202
class RevisionSpec_last(RevisionSpec):
217
205
def _match_on(self, branch, revs):
227
215
SPEC_TYPES.append(RevisionSpec_last)
230
class RevisionSpec_before(RevisionSpec):
234
def _match_on(self, branch, revs):
235
r = RevisionSpec(self.spec)._match_on(branch, revs)
236
if (r.revno is None) or (r.revno == 0):
238
return RevisionInfo(branch, r.revno - 1)
240
SPEC_TYPES.append(RevisionSpec_before)
243
218
class RevisionSpec_tag(RevisionSpec):
249
224
SPEC_TYPES.append(RevisionSpec_tag)
252
class RevisionSpec_revs:
253
def __init__(self, revs, branch):
256
def __getitem__(self, index):
257
r = self.branch.repository.get_revision(self.revs[index])
258
# TODO: Handle timezone.
259
return datetime.datetime.fromtimestamp(r.timestamp)
261
return len(self.revs)
264
227
class RevisionSpec_date(RevisionSpec):
266
229
_date_re = re.compile(
274
237
Spec for date revisions:
276
239
value can be 'yesterday', 'today', 'tomorrow' or a YYYY-MM-DD string.
277
matches the first entry after a given date (either at midnight or
278
at a specified time).
240
it can also start with a '+/-/='. '+' says match the first
241
entry after the given date. '-' is match the first entry before the date
242
'=' is match the first entry after, but still on the given date.
244
+2005-05-12 says find the first matching entry after May 12th, 2005 at 0:00
245
-2005-05-12 says find the first matching entry before May 12th, 2005 at 0:00
246
=2005-05-12 says find the first match after May 12th, 2005 at 0:00 but before
247
May 13th, 2005 at 0:00
280
249
So the proper way of saying 'give me all entries for today' is:
281
-r date:today..date:tomorrow
250
-r {date:+today}:{date:-tomorrow}
251
The default is '=' when not supplied
283
today = datetime.datetime.fromordinal(datetime.date.today().toordinal())
254
if self.spec[:1] in ('+', '-', '='):
255
match_style = self.spec[:1]
256
self.spec = self.spec[1:]
258
# XXX: this should probably be using datetime.date instead
259
today = datetime.datetime.today().replace(hour=0, minute=0, second=0,
284
261
if self.spec.lower() == 'yesterday':
285
262
dt = today - datetime.timedelta(days=1)
286
263
elif self.spec.lower() == 'today':
309
286
dt = datetime.datetime(year=year, month=month, day=day,
310
287
hour=hour, minute=minute, second=second)
313
rev = bisect.bisect(RevisionSpec_revs(revs, branch), dt)
317
return RevisionInfo(branch, None)
291
if match_style == '-':
293
elif match_style == '=':
294
last = dt + datetime.timedelta(days=1)
297
for i in range(len(revs)-1, -1, -1):
298
r = branch.get_revision(revs[i])
299
# TODO: Handle timezone.
300
dt = datetime.datetime.fromtimestamp(r.timestamp)
301
if first >= dt and (last is None or dt >= last):
302
return RevisionInfo(branch, i+1,)
319
return RevisionInfo(branch, rev + 1)
304
for i in range(len(revs)):
305
r = branch.get_revision(revs[i])
306
# TODO: Handle timezone.
307
dt = datetime.datetime.fromtimestamp(r.timestamp)
308
if first <= dt and (last is None or dt <= last):
309
return RevisionInfo(branch, i+1,)
321
311
SPEC_TYPES.append(RevisionSpec_date)
327
317
def _match_on(self, branch, revs):
328
318
from branch import Branch
329
319
from revision import common_ancestor, MultipleRevisionSources
330
other_branch = Branch.open_containing(self.spec)[0]
331
revision_a = branch.last_revision()
332
revision_b = other_branch.last_revision()
320
other_branch = Branch.open_containing(self.spec)
321
revision_a = branch.last_patch()
322
revision_b = other_branch.last_patch()
333
323
for r, b in ((revision_a, branch), (revision_b, other_branch)):
335
325
raise NoCommits(b)
336
revision_source = MultipleRevisionSources(branch.repository,
337
other_branch.repository)
326
revision_source = MultipleRevisionSources(branch, other_branch)
338
327
rev_id = common_ancestor(revision_a, revision_b, revision_source)
340
329
revno = branch.revision_id_to_revno(rev_id)
343
332
return RevisionInfo(branch, revno, rev_id)
345
334
SPEC_TYPES.append(RevisionSpec_ancestor)
347
class RevisionSpec_branch(RevisionSpec):
348
"""A branch: revision specifier.
350
This takes the path to a branch and returns its tip revision id.
354
def _match_on(self, branch, revs):
355
from branch import Branch
356
other_branch = Branch.open_containing(self.spec)[0]
357
revision_b = other_branch.last_revision()
358
if revision_b is None:
359
raise NoCommits(other_branch)
360
# pull in the remote revisions so we can diff
361
branch.fetch(other_branch, revision_b)
363
revno = branch.revision_id_to_revno(revision_b)
364
except NoSuchRevision:
366
return RevisionInfo(branch, revno, revision_b)
368
SPEC_TYPES.append(RevisionSpec_branch)