##// END OF EJS Templates
context: fix workingctx's __contains__ method
Dirkjan Ochtman -
r6845:835a01a0 default
parent child Browse files
Show More
@@ -1,773 +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 if user:
474 474 self._user = user
475 475 if parents:
476 476 self._parents = [changectx(self._repo, p) for p in parents]
477 477 if changes:
478 478 self._status = list(changes)
479 479
480 480 self._extra = {}
481 481 if extra:
482 482 self._extra = extra.copy()
483 483 if 'branch' not in self._extra:
484 484 branch = self._repo.dirstate.branch()
485 485 try:
486 486 branch = branch.decode('UTF-8').encode('UTF-8')
487 487 except UnicodeDecodeError:
488 488 raise util.Abort(_('branch name not in UTF-8!'))
489 489 self._extra['branch'] = branch
490 490 if self._extra['branch'] == '':
491 491 self._extra['branch'] = 'default'
492 492
493 493 def __str__(self):
494 494 return str(self._parents[0]) + "+"
495 495
496 496 def __nonzero__(self):
497 497 return True
498 498
499 499 def __contains__(self, key):
500 return self._dirstate[f] not in "?r"
500 return self._dirstate[key] not in "?r"
501 501
502 502 def __getattr__(self, name):
503 503 if name == '_status':
504 504 self._status = self._repo.status(unknown=True)
505 505 return self._status
506 506 elif name == '_user':
507 507 self._user = self._repo.ui.username()
508 508 return self._user
509 509 elif name == '_date':
510 510 self._date = util.makedate()
511 511 return self._date
512 512 if name == '_manifest':
513 513 self._buildmanifest()
514 514 return self._manifest
515 515 elif name == '_parents':
516 516 p = self._repo.dirstate.parents()
517 517 if p[1] == nullid:
518 518 p = p[:-1]
519 519 self._parents = [changectx(self._repo, x) for x in p]
520 520 return self._parents
521 521 else:
522 522 raise AttributeError, name
523 523
524 524 def _buildmanifest(self):
525 525 """generate a manifest corresponding to the working directory"""
526 526
527 527 man = self._parents[0].manifest().copy()
528 528 copied = self._repo.dirstate.copies()
529 529 cf = lambda x: man.flags(copied.get(x, x))
530 530 ff = self._repo.dirstate.flagfunc(cf)
531 531 modified, added, removed, deleted, unknown = self._status[:5]
532 532 for i, l in (("a", added), ("m", modified), ("u", unknown)):
533 533 for f in l:
534 534 man[f] = man.get(copied.get(f, f), nullid) + i
535 535 try:
536 536 man.set(f, ff(f))
537 537 except OSError:
538 538 pass
539 539
540 540 for f in deleted + removed:
541 541 if f in man:
542 542 del man[f]
543 543
544 544 self._manifest = man
545 545
546 546 def manifest(self): return self._manifest
547 547
548 548 def user(self): return self._user or self._repo.ui.username()
549 549 def date(self): return self._date
550 550 def description(self): return self._text
551 551 def files(self):
552 552 return util.sort(self._status[0] + self._status[1] + self._status[2])
553 553
554 554 def modified(self): return self._status[0]
555 555 def added(self): return self._status[1]
556 556 def removed(self): return self._status[2]
557 557 def deleted(self): return self._status[3]
558 558 def unknown(self): return self._status[4]
559 559 def clean(self): return self._status[5]
560 560 def branch(self): return self._extra['branch']
561 561 def extra(self): return self._extra
562 562
563 563 def tags(self):
564 564 t = []
565 565 [t.extend(p.tags()) for p in self.parents()]
566 566 return t
567 567
568 568 def children(self):
569 569 return []
570 570
571 571 def flags(self, path):
572 572 if '_manifest' in self.__dict__:
573 573 try:
574 574 return self._manifest.flags(path)
575 575 except KeyError:
576 576 return ''
577 577
578 578 pnode = self._parents[0].changeset()[0]
579 579 orig = self._repo.dirstate.copies().get(path, path)
580 580 node, flag = self._repo.manifest.find(pnode, orig)
581 581 try:
582 582 ff = self._repo.dirstate.flagfunc(lambda x: flag or '')
583 583 return ff(path)
584 584 except OSError:
585 585 pass
586 586
587 587 if not node or path in self.deleted() or path in self.removed():
588 588 return ''
589 589 return flag
590 590
591 591 def filectx(self, path, filelog=None):
592 592 """get a file context from the working directory"""
593 593 return workingfilectx(self._repo, path, workingctx=self,
594 594 filelog=filelog)
595 595
596 596 def ancestor(self, c2):
597 597 """return the ancestor context of self and c2"""
598 598 return self._parents[0].ancestor(c2) # punt on two parents for now
599 599
600 600 def walk(self, match):
601 601 return util.sort(self._repo.dirstate.walk(match, True, False).keys())
602 602
603 603 class workingfilectx(filectx):
604 604 """A workingfilectx object makes access to data related to a particular
605 605 file in the working directory convenient."""
606 606 def __init__(self, repo, path, filelog=None, workingctx=None):
607 607 """changeid can be a changeset revision, node, or tag.
608 608 fileid can be a file revision or node."""
609 609 self._repo = repo
610 610 self._path = path
611 611 self._changeid = None
612 612 self._filerev = self._filenode = None
613 613
614 614 if filelog:
615 615 self._filelog = filelog
616 616 if workingctx:
617 617 self._changectx = workingctx
618 618
619 619 def __getattr__(self, name):
620 620 if name == '_changectx':
621 621 self._changectx = workingctx(self._repo)
622 622 return self._changectx
623 623 elif name == '_repopath':
624 624 self._repopath = (self._repo.dirstate.copied(self._path)
625 625 or self._path)
626 626 return self._repopath
627 627 elif name == '_filelog':
628 628 self._filelog = self._repo.file(self._repopath)
629 629 return self._filelog
630 630 else:
631 631 raise AttributeError, name
632 632
633 633 def __nonzero__(self):
634 634 return True
635 635
636 636 def __str__(self):
637 637 return "%s@%s" % (self.path(), self._changectx)
638 638
639 639 def filectx(self, fileid):
640 640 '''opens an arbitrary revision of the file without
641 641 opening a new filelog'''
642 642 return filectx(self._repo, self._repopath, fileid=fileid,
643 643 filelog=self._filelog)
644 644
645 645 def rev(self):
646 646 if '_changectx' in self.__dict__:
647 647 return self._changectx.rev()
648 648 return self._filelog.linkrev(self._filenode)
649 649
650 650 def data(self): return self._repo.wread(self._path)
651 651 def renamed(self):
652 652 rp = self._repopath
653 653 if rp == self._path:
654 654 return None
655 655 return rp, self._changectx._parents[0]._manifest.get(rp, nullid)
656 656
657 657 def parents(self):
658 658 '''return parent filectxs, following copies if necessary'''
659 659 p = self._path
660 660 rp = self._repopath
661 661 pcl = self._changectx._parents
662 662 fl = self._filelog
663 663 pl = [(rp, pcl[0]._manifest.get(rp, nullid), fl)]
664 664 if len(pcl) > 1:
665 665 if rp != p:
666 666 fl = None
667 667 pl.append((p, pcl[1]._manifest.get(p, nullid), fl))
668 668
669 669 return [filectx(self._repo, p, fileid=n, filelog=l)
670 670 for p,n,l in pl if n != nullid]
671 671
672 672 def children(self):
673 673 return []
674 674
675 675 def size(self): return os.stat(self._repo.wjoin(self._path)).st_size
676 676 def date(self):
677 677 t, tz = self._changectx.date()
678 678 try:
679 679 return (int(os.lstat(self._repo.wjoin(self._path)).st_mtime), tz)
680 680 except OSError, err:
681 681 if err.errno != errno.ENOENT: raise
682 682 return (t, tz)
683 683
684 684 def cmp(self, text): return self._repo.wread(self._path) == text
685 685
686 686 class memctx(object):
687 687 """A memctx is a subset of changectx supposed to be built on memory
688 688 and passed to commit functions.
689 689
690 690 NOTE: this interface and the related memfilectx are experimental and
691 691 may change without notice.
692 692
693 693 parents - a pair of parent nodeids.
694 694 filectxfn - a callable taking (repo, memctx, path) arguments and
695 695 returning a memctx object.
696 696 date - any valid date string or (unixtime, offset), or None.
697 697 user - username string, or None.
698 698 extra - a dictionary of extra values, or None.
699 699 """
700 700 def __init__(self, repo, parents, text, files, filectxfn, user=None,
701 701 date=None, extra=None):
702 702 self._repo = repo
703 703 self._rev = None
704 704 self._node = None
705 705 self._text = text
706 706 self._date = date and util.parsedate(date) or util.makedate()
707 707 self._user = user
708 708 parents = [(p or nullid) for p in parents]
709 709 p1, p2 = parents
710 710 self._parents = [changectx(self._repo, p) for p in (p1, p2)]
711 711 files = util.sort(list(files))
712 712 self._status = [files, [], [], [], []]
713 713 self._filectxfn = filectxfn
714 714
715 715 self._extra = extra and extra.copy() or {}
716 716 if 'branch' not in self._extra:
717 717 self._extra['branch'] = 'default'
718 718 elif self._extra.get('branch') == '':
719 719 self._extra['branch'] = 'default'
720 720
721 721 def __str__(self):
722 722 return str(self._parents[0]) + "+"
723 723
724 724 def __int__(self):
725 725 return self._rev
726 726
727 727 def __nonzero__(self):
728 728 return True
729 729
730 730 def user(self): return self._user or self._repo.ui.username()
731 731 def date(self): return self._date
732 732 def description(self): return self._text
733 733 def files(self): return self.modified()
734 734 def modified(self): return self._status[0]
735 735 def added(self): return self._status[1]
736 736 def removed(self): return self._status[2]
737 737 def deleted(self): return self._status[3]
738 738 def unknown(self): return self._status[4]
739 739 def clean(self): return self._status[5]
740 740 def branch(self): return self._extra['branch']
741 741 def extra(self): return self._extra
742 742 def flags(self, f): return self[f].flags()
743 743
744 744 def parents(self):
745 745 """return contexts for each parent changeset"""
746 746 return self._parents
747 747
748 748 def filectx(self, path, filelog=None):
749 749 """get a file context from the working directory"""
750 750 return self._filectxfn(self._repo, self, path)
751 751
752 752 class memfilectx(object):
753 753 """A memfilectx is a subset of filectx supposed to be built by client
754 754 code and passed to commit functions.
755 755 """
756 756 def __init__(self, path, data, islink, isexec, copied):
757 757 """copied is the source file path, or None."""
758 758 self._path = path
759 759 self._data = data
760 760 self._flags = (islink and 'l' or '') + (isexec and 'x' or '')
761 761 self._copied = None
762 762 if copied:
763 763 self._copied = (copied, nullid)
764 764
765 765 def __nonzero__(self): return True
766 766 def __str__(self): return "%s@%s" % (self.path(), self._changectx)
767 767 def path(self): return self._path
768 768 def data(self): return self._data
769 769 def flags(self): return self._flags
770 770 def isexec(self): return 'x' in self._flags
771 771 def islink(self): return 'l' in self._flags
772 772 def renamed(self): return self._copied
773 773
General Comments 0
You need to be logged in to leave comments. Login now