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
class RevisionSpec_revs:
265
def __init__(self, revs, branch):
268
def __getitem__(self, index):
269
r = self.branch.repository.get_revision(self.revs[index])
270
# TODO: Handle timezone.
271
return datetime.datetime.fromtimestamp(r.timestamp)
273
return len(self.revs)
276
227
class RevisionSpec_date(RevisionSpec):
278
229
_date_re = re.compile(
286
237
Spec for date revisions:
288
239
value can be 'yesterday', 'today', 'tomorrow' or a YYYY-MM-DD string.
289
matches the first entry after a given date (either at midnight or
290
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
292
249
So the proper way of saying 'give me all entries for today' is:
293
-r date:today..date:tomorrow
250
-r {date:+today}:{date:-tomorrow}
251
The default is '=' when not supplied
295
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,
296
261
if self.spec.lower() == 'yesterday':
297
262
dt = today - datetime.timedelta(days=1)
298
263
elif self.spec.lower() == 'today':
321
286
dt = datetime.datetime(year=year, month=month, day=day,
322
287
hour=hour, minute=minute, second=second)
325
rev = bisect.bisect(RevisionSpec_revs(revs, branch), dt)
329
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,)
331
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,)
333
311
SPEC_TYPES.append(RevisionSpec_date)
339
317
def _match_on(self, branch, revs):
340
318
from branch import Branch
341
319
from revision import common_ancestor, MultipleRevisionSources
342
other_branch = Branch.open_containing(self.spec)[0]
343
revision_a = branch.last_revision()
344
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()
345
323
for r, b in ((revision_a, branch), (revision_b, other_branch)):
347
325
raise NoCommits(b)
348
revision_source = MultipleRevisionSources(branch.repository,
349
other_branch.repository)
326
revision_source = MultipleRevisionSources(branch, other_branch)
350
327
rev_id = common_ancestor(revision_a, revision_b, revision_source)
352
329
revno = branch.revision_id_to_revno(rev_id)
355
332
return RevisionInfo(branch, revno, rev_id)
357
334
SPEC_TYPES.append(RevisionSpec_ancestor)
359
class RevisionSpec_branch(RevisionSpec):
360
"""A branch: revision specifier.
362
This takes the path to a branch and returns its tip revision id.
366
def _match_on(self, branch, revs):
367
from branch import Branch
368
other_branch = Branch.open_containing(self.spec)[0]
369
revision_b = other_branch.last_revision()
370
if revision_b is None:
371
raise NoCommits(other_branch)
372
# pull in the remote revisions so we can diff
373
branch.fetch(other_branch, revision_b)
375
revno = branch.revision_id_to_revno(revision_b)
376
except NoSuchRevision:
378
return RevisionInfo(branch, revno, revision_b)
380
SPEC_TYPES.append(RevisionSpec_branch)