##// END OF EJS Templates
workingctx: add __contains__ method
Matt Mackall -
r6771:f5d7cfcb default
parent child Browse files
Show More
@@ -1,770 +1,773
1 1 # context.py - changeset and file context objects for mercurial
2 2 #
3 3 # Copyright 2006, 2007 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms
6 6 # of the GNU General Public License, incorporated herein by reference.
7 7
8 8 from node import nullid, nullrev, short, hex
9 9 from i18n import _
10 10 import ancestor, bdiff, revlog, util, os, errno
11 11
12 12 class changectx(object):
13 13 """A changecontext object makes access to data related to a particular
14 14 changeset convenient."""
15 15 def __init__(self, repo, changeid=''):
16 16 """changeid is a revision number, node, or tag"""
17 17 if changeid == '':
18 18 changeid = '.'
19 19 self._repo = repo
20 20 self._node = self._repo.lookup(changeid)
21 21 self._rev = self._repo.changelog.rev(self._node)
22 22
23 23 def __str__(self):
24 24 return short(self.node())
25 25
26 26 def __int__(self):
27 27 return self.rev()
28 28
29 29 def __repr__(self):
30 30 return "<changectx %s>" % str(self)
31 31
32 32 def __hash__(self):
33 33 try:
34 34 return hash(self._rev)
35 35 except AttributeError:
36 36 return id(self)
37 37
38 38 def __eq__(self, other):
39 39 try:
40 40 return self._rev == other._rev
41 41 except AttributeError:
42 42 return False
43 43
44 44 def __ne__(self, other):
45 45 return not (self == other)
46 46
47 47 def __nonzero__(self):
48 48 return self._rev != nullrev
49 49
50 50 def __getattr__(self, name):
51 51 if name == '_changeset':
52 52 self._changeset = self._repo.changelog.read(self.node())
53 53 return self._changeset
54 54 elif name == '_manifest':
55 55 self._manifest = self._repo.manifest.read(self._changeset[0])
56 56 return self._manifest
57 57 elif name == '_manifestdelta':
58 58 md = self._repo.manifest.readdelta(self._changeset[0])
59 59 self._manifestdelta = md
60 60 return self._manifestdelta
61 61 elif name == '_parents':
62 62 p = self._repo.changelog.parents(self._node)
63 63 if p[1] == nullid:
64 64 p = p[:-1]
65 65 self._parents = [changectx(self._repo, x) for x in p]
66 66 return self._parents
67 67 else:
68 68 raise AttributeError, name
69 69
70 70 def __contains__(self, key):
71 71 return key in self._manifest
72 72
73 73 def __getitem__(self, key):
74 74 return self.filectx(key)
75 75
76 76 def __iter__(self):
77 77 for f in util.sort(self._manifest):
78 78 yield f
79 79
80 80 def changeset(self): return self._changeset
81 81 def manifest(self): return self._manifest
82 82
83 83 def rev(self): return self._rev
84 84 def node(self): return self._node
85 85 def hex(self): return hex(self._node)
86 86 def user(self): return self._changeset[1]
87 87 def date(self): return self._changeset[2]
88 88 def files(self): return self._changeset[3]
89 89 def description(self): return self._changeset[4]
90 90 def branch(self): return self._changeset[5].get("branch")
91 91 def extra(self): return self._changeset[5]
92 92 def tags(self): return self._repo.nodetags(self._node)
93 93
94 94 def parents(self):
95 95 """return contexts for each parent changeset"""
96 96 return self._parents
97 97
98 98 def children(self):
99 99 """return contexts for each child changeset"""
100 100 c = self._repo.changelog.children(self._node)
101 101 return [changectx(self._repo, x) for x in c]
102 102
103 103 def _fileinfo(self, path):
104 104 if '_manifest' in self.__dict__:
105 105 try:
106 106 return self._manifest[path], self._manifest.flags(path)
107 107 except KeyError:
108 108 raise revlog.LookupError(self._node, path,
109 109 _('not found in manifest'))
110 110 if '_manifestdelta' in self.__dict__ or path in self.files():
111 111 if path in self._manifestdelta:
112 112 return self._manifestdelta[path], self._manifestdelta.flags(path)
113 113 node, flag = self._repo.manifest.find(self._changeset[0], path)
114 114 if not node:
115 115 raise revlog.LookupError(self._node, path,
116 116 _('not found in manifest'))
117 117
118 118 return node, flag
119 119
120 120 def filenode(self, path):
121 121 return self._fileinfo(path)[0]
122 122
123 123 def flags(self, path):
124 124 try:
125 125 return self._fileinfo(path)[1]
126 126 except revlog.LookupError:
127 127 return ''
128 128
129 129 def filectx(self, path, fileid=None, filelog=None):
130 130 """get a file context from this changeset"""
131 131 if fileid is None:
132 132 fileid = self.filenode(path)
133 133 return filectx(self._repo, path, fileid=fileid,
134 134 changectx=self, filelog=filelog)
135 135
136 136 def filectxs(self):
137 137 """generate a file context for each file in this changeset's
138 138 manifest"""
139 139 for f in util.sort(mf):
140 140 yield self.filectx(f, fileid=mf[f])
141 141
142 142 def ancestor(self, c2):
143 143 """
144 144 return the ancestor context of self and c2
145 145 """
146 146 n = self._repo.changelog.ancestor(self._node, c2._node)
147 147 return changectx(self._repo, n)
148 148
149 149 def walk(self, match):
150 150 fdict = dict.fromkeys(match.files())
151 151 # for dirstate.walk, files=['.'] means "walk the whole tree".
152 152 # follow that here, too
153 153 fdict.pop('.', None)
154 154 for fn in self:
155 155 for ffn in fdict:
156 156 # match if the file is the exact name or a directory
157 157 if ffn == fn or fn.startswith("%s/" % ffn):
158 158 del fdict[ffn]
159 159 break
160 160 if match(fn):
161 161 yield fn
162 162 for fn in util.sort(fdict):
163 163 if match.bad(fn, 'No such file in rev ' + str(self)) and match(fn):
164 164 yield fn
165 165
166 166 class filectx(object):
167 167 """A filecontext object makes access to data related to a particular
168 168 filerevision convenient."""
169 169 def __init__(self, repo, path, changeid=None, fileid=None,
170 170 filelog=None, changectx=None):
171 171 """changeid can be a changeset revision, node, or tag.
172 172 fileid can be a file revision or node."""
173 173 self._repo = repo
174 174 self._path = path
175 175
176 176 assert (changeid is not None
177 177 or fileid is not None
178 178 or changectx is not None)
179 179
180 180 if filelog:
181 181 self._filelog = filelog
182 182
183 183 if changeid is not None:
184 184 self._changeid = changeid
185 185 if changectx is not None:
186 186 self._changectx = changectx
187 187 if fileid is not None:
188 188 self._fileid = fileid
189 189
190 190 def __getattr__(self, name):
191 191 if name == '_changectx':
192 192 self._changectx = changectx(self._repo, self._changeid)
193 193 return self._changectx
194 194 elif name == '_filelog':
195 195 self._filelog = self._repo.file(self._path)
196 196 return self._filelog
197 197 elif name == '_changeid':
198 198 if '_changectx' in self.__dict__:
199 199 self._changeid = self._changectx.rev()
200 200 else:
201 201 self._changeid = self._filelog.linkrev(self._filenode)
202 202 return self._changeid
203 203 elif name == '_filenode':
204 204 if '_fileid' in self.__dict__:
205 205 self._filenode = self._filelog.lookup(self._fileid)
206 206 else:
207 207 self._filenode = self._changectx.filenode(self._path)
208 208 return self._filenode
209 209 elif name == '_filerev':
210 210 self._filerev = self._filelog.rev(self._filenode)
211 211 return self._filerev
212 212 elif name == '_repopath':
213 213 self._repopath = self._path
214 214 return self._repopath
215 215 else:
216 216 raise AttributeError, name
217 217
218 218 def __nonzero__(self):
219 219 try:
220 220 n = self._filenode
221 221 return True
222 222 except revlog.LookupError:
223 223 # file is missing
224 224 return False
225 225
226 226 def __str__(self):
227 227 return "%s@%s" % (self.path(), short(self.node()))
228 228
229 229 def __repr__(self):
230 230 return "<filectx %s>" % str(self)
231 231
232 232 def __hash__(self):
233 233 try:
234 234 return hash((self._path, self._fileid))
235 235 except AttributeError:
236 236 return id(self)
237 237
238 238 def __eq__(self, other):
239 239 try:
240 240 return (self._path == other._path
241 241 and self._fileid == other._fileid)
242 242 except AttributeError:
243 243 return False
244 244
245 245 def __ne__(self, other):
246 246 return not (self == other)
247 247
248 248 def filectx(self, fileid):
249 249 '''opens an arbitrary revision of the file without
250 250 opening a new filelog'''
251 251 return filectx(self._repo, self._path, fileid=fileid,
252 252 filelog=self._filelog)
253 253
254 254 def filerev(self): return self._filerev
255 255 def filenode(self): return self._filenode
256 256 def flags(self): return self._changectx.flags(self._path)
257 257 def filelog(self): return self._filelog
258 258
259 259 def rev(self):
260 260 if '_changectx' in self.__dict__:
261 261 return self._changectx.rev()
262 262 if '_changeid' in self.__dict__:
263 263 return self._changectx.rev()
264 264 return self._filelog.linkrev(self._filenode)
265 265
266 266 def linkrev(self): return self._filelog.linkrev(self._filenode)
267 267 def node(self): return self._changectx.node()
268 268 def user(self): return self._changectx.user()
269 269 def date(self): return self._changectx.date()
270 270 def files(self): return self._changectx.files()
271 271 def description(self): return self._changectx.description()
272 272 def branch(self): return self._changectx.branch()
273 273 def manifest(self): return self._changectx.manifest()
274 274 def changectx(self): return self._changectx
275 275
276 276 def data(self): return self._filelog.read(self._filenode)
277 277 def path(self): return self._path
278 278 def size(self): return self._filelog.size(self._filerev)
279 279
280 280 def cmp(self, text): return self._filelog.cmp(self._filenode, text)
281 281
282 282 def renamed(self):
283 283 """check if file was actually renamed in this changeset revision
284 284
285 285 If rename logged in file revision, we report copy for changeset only
286 286 if file revisions linkrev points back to the changeset in question
287 287 or both changeset parents contain different file revisions.
288 288 """
289 289
290 290 renamed = self._filelog.renamed(self._filenode)
291 291 if not renamed:
292 292 return renamed
293 293
294 294 if self.rev() == self.linkrev():
295 295 return renamed
296 296
297 297 name = self.path()
298 298 fnode = self._filenode
299 299 for p in self._changectx.parents():
300 300 try:
301 301 if fnode == p.filenode(name):
302 302 return None
303 303 except revlog.LookupError:
304 304 pass
305 305 return renamed
306 306
307 307 def parents(self):
308 308 p = self._path
309 309 fl = self._filelog
310 310 pl = [(p, n, fl) for n in self._filelog.parents(self._filenode)]
311 311
312 312 r = self._filelog.renamed(self._filenode)
313 313 if r:
314 314 pl[0] = (r[0], r[1], None)
315 315
316 316 return [filectx(self._repo, p, fileid=n, filelog=l)
317 317 for p,n,l in pl if n != nullid]
318 318
319 319 def children(self):
320 320 # hard for renames
321 321 c = self._filelog.children(self._filenode)
322 322 return [filectx(self._repo, self._path, fileid=x,
323 323 filelog=self._filelog) for x in c]
324 324
325 325 def annotate(self, follow=False, linenumber=None):
326 326 '''returns a list of tuples of (ctx, line) for each line
327 327 in the file, where ctx is the filectx of the node where
328 328 that line was last changed.
329 329 This returns tuples of ((ctx, linenumber), line) for each line,
330 330 if "linenumber" parameter is NOT "None".
331 331 In such tuples, linenumber means one at the first appearance
332 332 in the managed file.
333 333 To reduce annotation cost,
334 334 this returns fixed value(False is used) as linenumber,
335 335 if "linenumber" parameter is "False".'''
336 336
337 337 def decorate_compat(text, rev):
338 338 return ([rev] * len(text.splitlines()), text)
339 339
340 340 def without_linenumber(text, rev):
341 341 return ([(rev, False)] * len(text.splitlines()), text)
342 342
343 343 def with_linenumber(text, rev):
344 344 size = len(text.splitlines())
345 345 return ([(rev, i) for i in xrange(1, size + 1)], text)
346 346
347 347 decorate = (((linenumber is None) and decorate_compat) or
348 348 (linenumber and with_linenumber) or
349 349 without_linenumber)
350 350
351 351 def pair(parent, child):
352 352 for a1, a2, b1, b2 in bdiff.blocks(parent[1], child[1]):
353 353 child[0][b1:b2] = parent[0][a1:a2]
354 354 return child
355 355
356 356 getlog = util.cachefunc(lambda x: self._repo.file(x))
357 357 def getctx(path, fileid):
358 358 log = path == self._path and self._filelog or getlog(path)
359 359 return filectx(self._repo, path, fileid=fileid, filelog=log)
360 360 getctx = util.cachefunc(getctx)
361 361
362 362 def parents(f):
363 363 # we want to reuse filectx objects as much as possible
364 364 p = f._path
365 365 if f._filerev is None: # working dir
366 366 pl = [(n.path(), n.filerev()) for n in f.parents()]
367 367 else:
368 368 pl = [(p, n) for n in f._filelog.parentrevs(f._filerev)]
369 369
370 370 if follow:
371 371 r = f.renamed()
372 372 if r:
373 373 pl[0] = (r[0], getlog(r[0]).rev(r[1]))
374 374
375 375 return [getctx(p, n) for p, n in pl if n != nullrev]
376 376
377 377 # use linkrev to find the first changeset where self appeared
378 378 if self.rev() != self.linkrev():
379 379 base = self.filectx(self.filerev())
380 380 else:
381 381 base = self
382 382
383 383 # find all ancestors
384 384 needed = {base: 1}
385 385 visit = [base]
386 386 files = [base._path]
387 387 while visit:
388 388 f = visit.pop(0)
389 389 for p in parents(f):
390 390 if p not in needed:
391 391 needed[p] = 1
392 392 visit.append(p)
393 393 if p._path not in files:
394 394 files.append(p._path)
395 395 else:
396 396 # count how many times we'll use this
397 397 needed[p] += 1
398 398
399 399 # sort by revision (per file) which is a topological order
400 400 visit = []
401 401 for f in files:
402 402 fn = [(n.rev(), n) for n in needed if n._path == f]
403 403 visit.extend(fn)
404 404
405 405 hist = {}
406 406 for r, f in util.sort(visit):
407 407 curr = decorate(f.data(), f)
408 408 for p in parents(f):
409 409 if p != nullid:
410 410 curr = pair(hist[p], curr)
411 411 # trim the history of unneeded revs
412 412 needed[p] -= 1
413 413 if not needed[p]:
414 414 del hist[p]
415 415 hist[f] = curr
416 416
417 417 return zip(hist[f][0], hist[f][1].splitlines(1))
418 418
419 419 def ancestor(self, fc2):
420 420 """
421 421 find the common ancestor file context, if any, of self, and fc2
422 422 """
423 423
424 424 acache = {}
425 425
426 426 # prime the ancestor cache for the working directory
427 427 for c in (self, fc2):
428 428 if c._filerev == None:
429 429 pl = [(n.path(), n.filenode()) for n in c.parents()]
430 430 acache[(c._path, None)] = pl
431 431
432 432 flcache = {self._repopath:self._filelog, fc2._repopath:fc2._filelog}
433 433 def parents(vertex):
434 434 if vertex in acache:
435 435 return acache[vertex]
436 436 f, n = vertex
437 437 if f not in flcache:
438 438 flcache[f] = self._repo.file(f)
439 439 fl = flcache[f]
440 440 pl = [(f, p) for p in fl.parents(n) if p != nullid]
441 441 re = fl.renamed(n)
442 442 if re:
443 443 pl.append(re)
444 444 acache[vertex] = pl
445 445 return pl
446 446
447 447 a, b = (self._path, self._filenode), (fc2._path, fc2._filenode)
448 448 v = ancestor.ancestor(a, b, parents)
449 449 if v:
450 450 f, n = v
451 451 return filectx(self._repo, f, fileid=n, filelog=flcache[f])
452 452
453 453 return None
454 454
455 455 class workingctx(changectx):
456 456 """A workingctx object makes access to data related to
457 457 the current working directory convenient.
458 458 parents - a pair of parent nodeids, or None to use the dirstate.
459 459 date - any valid date string or (unixtime, offset), or None.
460 460 user - username string, or None.
461 461 extra - a dictionary of extra values, or None.
462 462 changes - a list of file lists as returned by localrepo.status()
463 463 or None to use the repository status.
464 464 """
465 465 def __init__(self, repo, parents=None, text="", user=None, date=None,
466 466 extra=None, changes=None):
467 467 self._repo = repo
468 468 self._rev = None
469 469 self._node = None
470 470 self._text = text
471 471 if date:
472 472 self._date = util.parsedate(date)
473 473 else:
474 474 self._date = util.makedate()
475 475 if user:
476 476 self._user = user
477 477 else:
478 478 self._user = self._repo.ui.username()
479 479 if parents:
480 480 p1, p2 = parents
481 481 self._parents = [changectx(self._repo, p) for p in (p1, p2)]
482 482 if changes:
483 483 self._status = list(changes)
484 484
485 485 self._extra = {}
486 486 if extra:
487 487 self._extra = extra.copy()
488 488 if 'branch' not in self._extra:
489 489 branch = self._repo.dirstate.branch()
490 490 try:
491 491 branch = branch.decode('UTF-8').encode('UTF-8')
492 492 except UnicodeDecodeError:
493 493 raise util.Abort(_('branch name not in UTF-8!'))
494 494 self._extra['branch'] = branch
495 495 if self._extra['branch'] == '':
496 496 self._extra['branch'] = 'default'
497 497
498 498 def __str__(self):
499 499 return str(self._parents[0]) + "+"
500 500
501 501 def __nonzero__(self):
502 502 return True
503 503
504 def __contains__(self, key):
505 return self._dirstate[f] not in "?r"
506
504 507 def __getattr__(self, name):
505 508 if name == '_status':
506 509 self._status = self._repo.status(unknown=True)
507 510 return self._status
508 511 if name == '_manifest':
509 512 self._buildmanifest()
510 513 return self._manifest
511 514 elif name == '_parents':
512 515 p = self._repo.dirstate.parents()
513 516 if p[1] == nullid:
514 517 p = p[:-1]
515 518 self._parents = [changectx(self._repo, x) for x in p]
516 519 return self._parents
517 520 else:
518 521 raise AttributeError, name
519 522
520 523 def _buildmanifest(self):
521 524 """generate a manifest corresponding to the working directory"""
522 525
523 526 man = self._parents[0].manifest().copy()
524 527 copied = self._repo.dirstate.copies()
525 528 cf = lambda x: man.flags(copied.get(x, x))
526 529 ff = self._repo.dirstate.flagfunc(cf)
527 530 modified, added, removed, deleted, unknown = self._status[:5]
528 531 for i, l in (("a", added), ("m", modified), ("u", unknown)):
529 532 for f in l:
530 533 man[f] = man.get(copied.get(f, f), nullid) + i
531 534 try:
532 535 man.set(f, ff(f))
533 536 except OSError:
534 537 pass
535 538
536 539 for f in deleted + removed:
537 540 if f in man:
538 541 del man[f]
539 542
540 543 self._manifest = man
541 544
542 545 def manifest(self): return self._manifest
543 546
544 547 def user(self): return self._user
545 548 def date(self): return self._date
546 549 def description(self): return self._text
547 550 def files(self):
548 551 return util.sort(self._status[0] + self._status[1] + self._status[2])
549 552
550 553 def modified(self): return self._status[0]
551 554 def added(self): return self._status[1]
552 555 def removed(self): return self._status[2]
553 556 def deleted(self): return self._status[3]
554 557 def unknown(self): return self._status[4]
555 558 def clean(self): return self._status[5]
556 559 def branch(self): return self._extra['branch']
557 560 def extra(self): return self._extra
558 561
559 562 def tags(self):
560 563 t = []
561 564 [t.extend(p.tags()) for p in self.parents()]
562 565 return t
563 566
564 567 def children(self):
565 568 return []
566 569
567 570 def flags(self, path):
568 571 if '_manifest' in self.__dict__:
569 572 try:
570 573 return self._manifest.flags(path)
571 574 except KeyError:
572 575 return ''
573 576
574 577 pnode = self._parents[0].changeset()[0]
575 578 orig = self._repo.dirstate.copies().get(path, path)
576 579 node, flag = self._repo.manifest.find(pnode, orig)
577 580 try:
578 581 ff = self._repo.dirstate.flagfunc(lambda x: flag or '')
579 582 return ff(path)
580 583 except OSError:
581 584 pass
582 585
583 586 if not node or path in self.deleted() or path in self.removed():
584 587 return ''
585 588 return flag
586 589
587 590 def filectx(self, path, filelog=None):
588 591 """get a file context from the working directory"""
589 592 return workingfilectx(self._repo, path, workingctx=self,
590 593 filelog=filelog)
591 594
592 595 def ancestor(self, c2):
593 596 """return the ancestor context of self and c2"""
594 597 return self._parents[0].ancestor(c2) # punt on two parents for now
595 598
596 599 def walk(self, match):
597 600 for src, fn, st in self._repo.dirstate.walk(match, True, False):
598 601 yield fn
599 602
600 603 class workingfilectx(filectx):
601 604 """A workingfilectx object makes access to data related to a particular
602 605 file in the working directory convenient."""
603 606 def __init__(self, repo, path, filelog=None, workingctx=None):
604 607 """changeid can be a changeset revision, node, or tag.
605 608 fileid can be a file revision or node."""
606 609 self._repo = repo
607 610 self._path = path
608 611 self._changeid = None
609 612 self._filerev = self._filenode = None
610 613
611 614 if filelog:
612 615 self._filelog = filelog
613 616 if workingctx:
614 617 self._changectx = workingctx
615 618
616 619 def __getattr__(self, name):
617 620 if name == '_changectx':
618 621 self._changectx = workingctx(self._repo)
619 622 return self._changectx
620 623 elif name == '_repopath':
621 624 self._repopath = (self._repo.dirstate.copied(self._path)
622 625 or self._path)
623 626 return self._repopath
624 627 elif name == '_filelog':
625 628 self._filelog = self._repo.file(self._repopath)
626 629 return self._filelog
627 630 else:
628 631 raise AttributeError, name
629 632
630 633 def __nonzero__(self):
631 634 return True
632 635
633 636 def __str__(self):
634 637 return "%s@%s" % (self.path(), self._changectx)
635 638
636 639 def filectx(self, fileid):
637 640 '''opens an arbitrary revision of the file without
638 641 opening a new filelog'''
639 642 return filectx(self._repo, self._repopath, fileid=fileid,
640 643 filelog=self._filelog)
641 644
642 645 def rev(self):
643 646 if '_changectx' in self.__dict__:
644 647 return self._changectx.rev()
645 648 return self._filelog.linkrev(self._filenode)
646 649
647 650 def data(self): return self._repo.wread(self._path)
648 651 def renamed(self):
649 652 rp = self._repopath
650 653 if rp == self._path:
651 654 return None
652 655 return rp, self._changectx._parents[0]._manifest.get(rp, nullid)
653 656
654 657 def parents(self):
655 658 '''return parent filectxs, following copies if necessary'''
656 659 p = self._path
657 660 rp = self._repopath
658 661 pcl = self._changectx._parents
659 662 fl = self._filelog
660 663 pl = [(rp, pcl[0]._manifest.get(rp, nullid), fl)]
661 664 if len(pcl) > 1:
662 665 if rp != p:
663 666 fl = None
664 667 pl.append((p, pcl[1]._manifest.get(p, nullid), fl))
665 668
666 669 return [filectx(self._repo, p, fileid=n, filelog=l)
667 670 for p,n,l in pl if n != nullid]
668 671
669 672 def children(self):
670 673 return []
671 674
672 675 def size(self): return os.stat(self._repo.wjoin(self._path)).st_size
673 676 def date(self):
674 677 t, tz = self._changectx.date()
675 678 try:
676 679 return (int(os.lstat(self._repo.wjoin(self._path)).st_mtime), tz)
677 680 except OSError, err:
678 681 if err.errno != errno.ENOENT: raise
679 682 return (t, tz)
680 683
681 684 def cmp(self, text): return self._repo.wread(self._path) == text
682 685
683 686 class memctx(object):
684 687 """A memctx is a subset of changectx supposed to be built on memory
685 688 and passed to commit functions.
686 689
687 690 NOTE: this interface and the related memfilectx are experimental and
688 691 may change without notice.
689 692
690 693 parents - a pair of parent nodeids.
691 694 filectxfn - a callable taking (repo, memctx, path) arguments and
692 695 returning a memctx object.
693 696 date - any valid date string or (unixtime, offset), or None.
694 697 user - username string, or None.
695 698 extra - a dictionary of extra values, or None.
696 699 """
697 700 def __init__(self, repo, parents, text, files, filectxfn, user=None,
698 701 date=None, extra=None):
699 702 self._repo = repo
700 703 self._rev = None
701 704 self._node = None
702 705 self._text = text
703 706 self._date = date and util.parsedate(date) or util.makedate()
704 707 self._user = user or self._repo.ui.username()
705 708 parents = [(p or nullid) for p in parents]
706 709 p1, p2 = parents
707 710 self._parents = [changectx(self._repo, p) for p in (p1, p2)]
708 711 files = util.sort(list(files))
709 712 self._status = [files, [], [], [], []]
710 713 self._filectxfn = filectxfn
711 714
712 715 self._extra = extra and extra.copy() or {}
713 716 if 'branch' not in self._extra:
714 717 self._extra['branch'] = 'default'
715 718 elif self._extra.get('branch') == '':
716 719 self._extra['branch'] = 'default'
717 720
718 721 def __str__(self):
719 722 return str(self._parents[0]) + "+"
720 723
721 724 def __int__(self):
722 725 return self._rev
723 726
724 727 def __nonzero__(self):
725 728 return True
726 729
727 730 def user(self): return self._user
728 731 def date(self): return self._date
729 732 def description(self): return self._text
730 733 def files(self): return self.modified()
731 734 def modified(self): return self._status[0]
732 735 def added(self): return self._status[1]
733 736 def removed(self): return self._status[2]
734 737 def deleted(self): return self._status[3]
735 738 def unknown(self): return self._status[4]
736 739 def clean(self): return self._status[5]
737 740 def branch(self): return self._extra['branch']
738 741 def extra(self): return self._extra
739 742 def flags(self, f): return self[f].flags()
740 743
741 744 def parents(self):
742 745 """return contexts for each parent changeset"""
743 746 return self._parents
744 747
745 748 def filectx(self, path, filelog=None):
746 749 """get a file context from the working directory"""
747 750 return self._filectxfn(self._repo, self, path)
748 751
749 752 class memfilectx(object):
750 753 """A memfilectx is a subset of filectx supposed to be built by client
751 754 code and passed to commit functions.
752 755 """
753 756 def __init__(self, path, data, islink, isexec, copied):
754 757 """copied is the source file path, or None."""
755 758 self._path = path
756 759 self._data = data
757 760 self._flags = (islink and 'l' or '') + (isexec and 'x' or '')
758 761 self._copied = None
759 762 if copied:
760 763 self._copied = (copied, nullid)
761 764
762 765 def __nonzero__(self): return True
763 766 def __str__(self): return "%s@%s" % (self.path(), self._changectx)
764 767 def path(self): return self._path
765 768 def data(self): return self._data
766 769 def flags(self): return self._flags
767 770 def isexec(self): return 'x' in self._flags
768 771 def islink(self): return 'l' in self._flags
769 772 def renamed(self): return self._copied
770 773
General Comments 0
You need to be logged in to leave comments. Login now