comparison upmana/mercurial/context.py @ 121:496dbf12a6cb alpha

Traipse Alpha 'OpenRPG' {091030-00} Traipse is a distribution of OpenRPG that is designed to be easy to setup and go. Traipse also makes it easy for developers to work on code without fear of sacrifice. 'Ornery-Orc' continues the trend of 'Grumpy' and adds fixes to the code. 'Ornery-Orc's main goal is to offer more advanced features and enhance the productivity of the user. Update Summary (Cleaning up for Beta): Adds Bookmarks (Alpha) with cool Smiley Star and Plus Symbol images! Changes made to the map for increased portability. SnowDog has changes planned in Core, though. Added an initial push to the BCG. Not much to see, just shows off how it is re-writing Main code. Fix to remote admin commands Minor fix to texted based server, works in /System/ folder Some Core changes to gametree to correctly disply Pretty Print, thanks David! Fix to Splitter Nodes not being created. Added images to Plugin Control panel for Autostart feature Fix to massive amounts of images loading; from Core fix to gsclient so with_statement imports Added 'boot' command to remote admin Prep work in Pass tool for remote admin rankings and different passwords, ei, Server, Admin, Moderator, etc. Remote Admin Commands more organized, more prep work. Added Confirmation window for sent nodes. Minor changes to allow for portability to an OpenSUSE linux OS (hopefully without breaking) {091028} Made changes to gametree to start working with Element Tree, mostly from Core Minor changes to Map to start working with Element Tree, from Core Preliminary changes to map efficiency, from FlexiRPG Miniatures Layer pop up box allows users to turn off Mini labels, from FlexiRPG Changes to main.py to start working with Element Tree {091029} Changes made to server to start working with Element Tree. Changes made to Meta Server Lib. Prepping test work for a multi meta network page. Minor bug fixed with mini to gametree Zoom Mouse plugin added. {091030} Getting ready for Beta. Server needs debugging so Alpha remains bugged. Plugin UI code cleaned. Auto start works with a graphic, pop-up asks to enable or disable plugin. Update Manager now has a partially working Status Bar. Status Bar captures terminal text, so Merc out put is visible. Manifest.xml file, will be renamed, is now much cleaner. Debug Console has a clear button and a Report Bug button. Prep work for a Term2Win class in Debug Console. Known: Current Alpha fails in Windows.
author sirebral
date Fri, 30 Oct 2009 22:21:40 -0500
parents
children
comparison
equal deleted inserted replaced
120:d86e762a994f 121:496dbf12a6cb
1 # context.py - changeset and file context objects for mercurial
2 #
3 # Copyright 2006, 2007 Matt Mackall <mpm@selenic.com>
4 #
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2, incorporated herein by reference.
7
8 from node import nullid, nullrev, short, hex
9 from i18n import _
10 import ancestor, bdiff, error, util, subrepo
11 import os, errno
12
13 propertycache = util.propertycache
14
15 class changectx(object):
16 """A changecontext object makes access to data related to a particular
17 changeset convenient."""
18 def __init__(self, repo, changeid=''):
19 """changeid is a revision number, node, or tag"""
20 if changeid == '':
21 changeid = '.'
22 self._repo = repo
23 if isinstance(changeid, (long, int)):
24 self._rev = changeid
25 self._node = self._repo.changelog.node(changeid)
26 else:
27 self._node = self._repo.lookup(changeid)
28 self._rev = self._repo.changelog.rev(self._node)
29
30 def __str__(self):
31 return short(self.node())
32
33 def __int__(self):
34 return self.rev()
35
36 def __repr__(self):
37 return "<changectx %s>" % str(self)
38
39 def __hash__(self):
40 try:
41 return hash(self._rev)
42 except AttributeError:
43 return id(self)
44
45 def __eq__(self, other):
46 try:
47 return self._rev == other._rev
48 except AttributeError:
49 return False
50
51 def __ne__(self, other):
52 return not (self == other)
53
54 def __nonzero__(self):
55 return self._rev != nullrev
56
57 @propertycache
58 def _changeset(self):
59 return self._repo.changelog.read(self.node())
60
61 @propertycache
62 def _manifest(self):
63 return self._repo.manifest.read(self._changeset[0])
64
65 @propertycache
66 def _manifestdelta(self):
67 return self._repo.manifest.readdelta(self._changeset[0])
68
69 @propertycache
70 def _parents(self):
71 p = self._repo.changelog.parentrevs(self._rev)
72 if p[1] == nullrev:
73 p = p[:-1]
74 return [changectx(self._repo, x) for x in p]
75
76 @propertycache
77 def substate(self):
78 return subrepo.state(self)
79
80 def __contains__(self, key):
81 return key in self._manifest
82
83 def __getitem__(self, key):
84 return self.filectx(key)
85
86 def __iter__(self):
87 for f in sorted(self._manifest):
88 yield f
89
90 def changeset(self): return self._changeset
91 def manifest(self): return self._manifest
92 def manifestnode(self): return self._changeset[0]
93
94 def rev(self): return self._rev
95 def node(self): return self._node
96 def hex(self): return hex(self._node)
97 def user(self): return self._changeset[1]
98 def date(self): return self._changeset[2]
99 def files(self): return self._changeset[3]
100 def description(self): return self._changeset[4]
101 def branch(self): return self._changeset[5].get("branch")
102 def extra(self): return self._changeset[5]
103 def tags(self): return self._repo.nodetags(self._node)
104
105 def parents(self):
106 """return contexts for each parent changeset"""
107 return self._parents
108
109 def p1(self):
110 return self._parents[0]
111
112 def p2(self):
113 if len(self._parents) == 2:
114 return self._parents[1]
115 return changectx(self._repo, -1)
116
117 def children(self):
118 """return contexts for each child changeset"""
119 c = self._repo.changelog.children(self._node)
120 return [changectx(self._repo, x) for x in c]
121
122 def ancestors(self):
123 for a in self._repo.changelog.ancestors(self._rev):
124 yield changectx(self._repo, a)
125
126 def descendants(self):
127 for d in self._repo.changelog.descendants(self._rev):
128 yield changectx(self._repo, d)
129
130 def _fileinfo(self, path):
131 if '_manifest' in self.__dict__:
132 try:
133 return self._manifest[path], self._manifest.flags(path)
134 except KeyError:
135 raise error.LookupError(self._node, path,
136 _('not found in manifest'))
137 if '_manifestdelta' in self.__dict__ or path in self.files():
138 if path in self._manifestdelta:
139 return self._manifestdelta[path], self._manifestdelta.flags(path)
140 node, flag = self._repo.manifest.find(self._changeset[0], path)
141 if not node:
142 raise error.LookupError(self._node, path,
143 _('not found in manifest'))
144
145 return node, flag
146
147 def filenode(self, path):
148 return self._fileinfo(path)[0]
149
150 def flags(self, path):
151 try:
152 return self._fileinfo(path)[1]
153 except error.LookupError:
154 return ''
155
156 def filectx(self, path, fileid=None, filelog=None):
157 """get a file context from this changeset"""
158 if fileid is None:
159 fileid = self.filenode(path)
160 return filectx(self._repo, path, fileid=fileid,
161 changectx=self, filelog=filelog)
162
163 def ancestor(self, c2):
164 """
165 return the ancestor context of self and c2
166 """
167 n = self._repo.changelog.ancestor(self._node, c2._node)
168 return changectx(self._repo, n)
169
170 def walk(self, match):
171 fset = set(match.files())
172 # for dirstate.walk, files=['.'] means "walk the whole tree".
173 # follow that here, too
174 fset.discard('.')
175 for fn in self:
176 for ffn in fset:
177 # match if the file is the exact name or a directory
178 if ffn == fn or fn.startswith("%s/" % ffn):
179 fset.remove(ffn)
180 break
181 if match(fn):
182 yield fn
183 for fn in sorted(fset):
184 if match.bad(fn, 'No such file in rev ' + str(self)) and match(fn):
185 yield fn
186
187 def sub(self, path):
188 return subrepo.subrepo(self, path)
189
190 class filectx(object):
191 """A filecontext object makes access to data related to a particular
192 filerevision convenient."""
193 def __init__(self, repo, path, changeid=None, fileid=None,
194 filelog=None, changectx=None):
195 """changeid can be a changeset revision, node, or tag.
196 fileid can be a file revision or node."""
197 self._repo = repo
198 self._path = path
199
200 assert (changeid is not None
201 or fileid is not None
202 or changectx is not None)
203
204 if filelog:
205 self._filelog = filelog
206
207 if changeid is not None:
208 self._changeid = changeid
209 if changectx is not None:
210 self._changectx = changectx
211 if fileid is not None:
212 self._fileid = fileid
213
214 @propertycache
215 def _changectx(self):
216 return changectx(self._repo, self._changeid)
217
218 @propertycache
219 def _filelog(self):
220 return self._repo.file(self._path)
221
222 @propertycache
223 def _changeid(self):
224 if '_changectx' in self.__dict__:
225 return self._changectx.rev()
226 else:
227 return self._filelog.linkrev(self._filerev)
228
229 @propertycache
230 def _filenode(self):
231 if '_fileid' in self.__dict__:
232 return self._filelog.lookup(self._fileid)
233 else:
234 return self._changectx.filenode(self._path)
235
236 @propertycache
237 def _filerev(self):
238 return self._filelog.rev(self._filenode)
239
240 @propertycache
241 def _repopath(self):
242 return self._path
243
244 def __nonzero__(self):
245 try:
246 self._filenode
247 return True
248 except error.LookupError:
249 # file is missing
250 return False
251
252 def __str__(self):
253 return "%s@%s" % (self.path(), short(self.node()))
254
255 def __repr__(self):
256 return "<filectx %s>" % str(self)
257
258 def __hash__(self):
259 try:
260 return hash((self._path, self._fileid))
261 except AttributeError:
262 return id(self)
263
264 def __eq__(self, other):
265 try:
266 return (self._path == other._path
267 and self._fileid == other._fileid)
268 except AttributeError:
269 return False
270
271 def __ne__(self, other):
272 return not (self == other)
273
274 def filectx(self, fileid):
275 '''opens an arbitrary revision of the file without
276 opening a new filelog'''
277 return filectx(self._repo, self._path, fileid=fileid,
278 filelog=self._filelog)
279
280 def filerev(self): return self._filerev
281 def filenode(self): return self._filenode
282 def flags(self): return self._changectx.flags(self._path)
283 def filelog(self): return self._filelog
284
285 def rev(self):
286 if '_changectx' in self.__dict__:
287 return self._changectx.rev()
288 if '_changeid' in self.__dict__:
289 return self._changectx.rev()
290 return self._filelog.linkrev(self._filerev)
291
292 def linkrev(self): return self._filelog.linkrev(self._filerev)
293 def node(self): return self._changectx.node()
294 def hex(self): return hex(self.node())
295 def user(self): return self._changectx.user()
296 def date(self): return self._changectx.date()
297 def files(self): return self._changectx.files()
298 def description(self): return self._changectx.description()
299 def branch(self): return self._changectx.branch()
300 def manifest(self): return self._changectx.manifest()
301 def changectx(self): return self._changectx
302
303 def data(self): return self._filelog.read(self._filenode)
304 def path(self): return self._path
305 def size(self): return self._filelog.size(self._filerev)
306
307 def cmp(self, text): return self._filelog.cmp(self._filenode, text)
308
309 def renamed(self):
310 """check if file was actually renamed in this changeset revision
311
312 If rename logged in file revision, we report copy for changeset only
313 if file revisions linkrev points back to the changeset in question
314 or both changeset parents contain different file revisions.
315 """
316
317 renamed = self._filelog.renamed(self._filenode)
318 if not renamed:
319 return renamed
320
321 if self.rev() == self.linkrev():
322 return renamed
323
324 name = self.path()
325 fnode = self._filenode
326 for p in self._changectx.parents():
327 try:
328 if fnode == p.filenode(name):
329 return None
330 except error.LookupError:
331 pass
332 return renamed
333
334 def parents(self):
335 p = self._path
336 fl = self._filelog
337 pl = [(p, n, fl) for n in self._filelog.parents(self._filenode)]
338
339 r = self._filelog.renamed(self._filenode)
340 if r:
341 pl[0] = (r[0], r[1], None)
342
343 return [filectx(self._repo, p, fileid=n, filelog=l)
344 for p,n,l in pl if n != nullid]
345
346 def children(self):
347 # hard for renames
348 c = self._filelog.children(self._filenode)
349 return [filectx(self._repo, self._path, fileid=x,
350 filelog=self._filelog) for x in c]
351
352 def annotate(self, follow=False, linenumber=None):
353 '''returns a list of tuples of (ctx, line) for each line
354 in the file, where ctx is the filectx of the node where
355 that line was last changed.
356 This returns tuples of ((ctx, linenumber), line) for each line,
357 if "linenumber" parameter is NOT "None".
358 In such tuples, linenumber means one at the first appearance
359 in the managed file.
360 To reduce annotation cost,
361 this returns fixed value(False is used) as linenumber,
362 if "linenumber" parameter is "False".'''
363
364 def decorate_compat(text, rev):
365 return ([rev] * len(text.splitlines()), text)
366
367 def without_linenumber(text, rev):
368 return ([(rev, False)] * len(text.splitlines()), text)
369
370 def with_linenumber(text, rev):
371 size = len(text.splitlines())
372 return ([(rev, i) for i in xrange(1, size + 1)], text)
373
374 decorate = (((linenumber is None) and decorate_compat) or
375 (linenumber and with_linenumber) or
376 without_linenumber)
377
378 def pair(parent, child):
379 for a1, a2, b1, b2 in bdiff.blocks(parent[1], child[1]):
380 child[0][b1:b2] = parent[0][a1:a2]
381 return child
382
383 getlog = util.lrucachefunc(lambda x: self._repo.file(x))
384 def getctx(path, fileid):
385 log = path == self._path and self._filelog or getlog(path)
386 return filectx(self._repo, path, fileid=fileid, filelog=log)
387 getctx = util.lrucachefunc(getctx)
388
389 def parents(f):
390 # we want to reuse filectx objects as much as possible
391 p = f._path
392 if f._filerev is None: # working dir
393 pl = [(n.path(), n.filerev()) for n in f.parents()]
394 else:
395 pl = [(p, n) for n in f._filelog.parentrevs(f._filerev)]
396
397 if follow:
398 r = f.renamed()
399 if r:
400 pl[0] = (r[0], getlog(r[0]).rev(r[1]))
401
402 return [getctx(p, n) for p, n in pl if n != nullrev]
403
404 # use linkrev to find the first changeset where self appeared
405 if self.rev() != self.linkrev():
406 base = self.filectx(self.filerev())
407 else:
408 base = self
409
410 # find all ancestors
411 needed = {base: 1}
412 visit = [base]
413 files = [base._path]
414 while visit:
415 f = visit.pop(0)
416 for p in parents(f):
417 if p not in needed:
418 needed[p] = 1
419 visit.append(p)
420 if p._path not in files:
421 files.append(p._path)
422 else:
423 # count how many times we'll use this
424 needed[p] += 1
425
426 # sort by revision (per file) which is a topological order
427 visit = []
428 for f in files:
429 fn = [(n.rev(), n) for n in needed if n._path == f]
430 visit.extend(fn)
431
432 hist = {}
433 for r, f in sorted(visit):
434 curr = decorate(f.data(), f)
435 for p in parents(f):
436 if p != nullid:
437 curr = pair(hist[p], curr)
438 # trim the history of unneeded revs
439 needed[p] -= 1
440 if not needed[p]:
441 del hist[p]
442 hist[f] = curr
443
444 return zip(hist[f][0], hist[f][1].splitlines(1))
445
446 def ancestor(self, fc2):
447 """
448 find the common ancestor file context, if any, of self, and fc2
449 """
450
451 acache = {}
452
453 # prime the ancestor cache for the working directory
454 for c in (self, fc2):
455 if c._filerev is None:
456 pl = [(n.path(), n.filenode()) for n in c.parents()]
457 acache[(c._path, None)] = pl
458
459 flcache = {self._repopath:self._filelog, fc2._repopath:fc2._filelog}
460 def parents(vertex):
461 if vertex in acache:
462 return acache[vertex]
463 f, n = vertex
464 if f not in flcache:
465 flcache[f] = self._repo.file(f)
466 fl = flcache[f]
467 pl = [(f, p) for p in fl.parents(n) if p != nullid]
468 re = fl.renamed(n)
469 if re:
470 pl.append(re)
471 acache[vertex] = pl
472 return pl
473
474 a, b = (self._path, self._filenode), (fc2._path, fc2._filenode)
475 v = ancestor.ancestor(a, b, parents)
476 if v:
477 f, n = v
478 return filectx(self._repo, f, fileid=n, filelog=flcache[f])
479
480 return None
481
482 class workingctx(changectx):
483 """A workingctx object makes access to data related to
484 the current working directory convenient.
485 parents - a pair of parent nodeids, or None to use the dirstate.
486 date - any valid date string or (unixtime, offset), or None.
487 user - username string, or None.
488 extra - a dictionary of extra values, or None.
489 changes - a list of file lists as returned by localrepo.status()
490 or None to use the repository status.
491 """
492 def __init__(self, repo, parents=None, text="", user=None, date=None,
493 extra=None, changes=None):
494 self._repo = repo
495 self._rev = None
496 self._node = None
497 self._text = text
498 if date:
499 self._date = util.parsedate(date)
500 if user:
501 self._user = user
502 if parents:
503 self._parents = [changectx(self._repo, p) for p in parents]
504 if changes:
505 self._status = list(changes)
506
507 self._extra = {}
508 if extra:
509 self._extra = extra.copy()
510 if 'branch' not in self._extra:
511 branch = self._repo.dirstate.branch()
512 try:
513 branch = branch.decode('UTF-8').encode('UTF-8')
514 except UnicodeDecodeError:
515 raise util.Abort(_('branch name not in UTF-8!'))
516 self._extra['branch'] = branch
517 if self._extra['branch'] == '':
518 self._extra['branch'] = 'default'
519
520 def __str__(self):
521 return str(self._parents[0]) + "+"
522
523 def __nonzero__(self):
524 return True
525
526 def __contains__(self, key):
527 return self._repo.dirstate[key] not in "?r"
528
529 @propertycache
530 def _manifest(self):
531 """generate a manifest corresponding to the working directory"""
532
533 man = self._parents[0].manifest().copy()
534 copied = self._repo.dirstate.copies()
535 cf = lambda x: man.flags(copied.get(x, x))
536 ff = self._repo.dirstate.flagfunc(cf)
537 modified, added, removed, deleted, unknown = self._status[:5]
538 for i, l in (("a", added), ("m", modified), ("u", unknown)):
539 for f in l:
540 man[f] = man.get(copied.get(f, f), nullid) + i
541 try:
542 man.set(f, ff(f))
543 except OSError:
544 pass
545
546 for f in deleted + removed:
547 if f in man:
548 del man[f]
549
550 return man
551
552 @propertycache
553 def _status(self):
554 return self._repo.status(unknown=True)
555
556 @propertycache
557 def _user(self):
558 return self._repo.ui.username()
559
560 @propertycache
561 def _date(self):
562 return util.makedate()
563
564 @propertycache
565 def _parents(self):
566 p = self._repo.dirstate.parents()
567 if p[1] == nullid:
568 p = p[:-1]
569 self._parents = [changectx(self._repo, x) for x in p]
570 return self._parents
571
572 def manifest(self): return self._manifest
573
574 def user(self): return self._user or self._repo.ui.username()
575 def date(self): return self._date
576 def description(self): return self._text
577 def files(self):
578 return sorted(self._status[0] + self._status[1] + self._status[2])
579
580 def modified(self): return self._status[0]
581 def added(self): return self._status[1]
582 def removed(self): return self._status[2]
583 def deleted(self): return self._status[3]
584 def unknown(self): return self._status[4]
585 def clean(self): return self._status[5]
586 def branch(self): return self._extra['branch']
587 def extra(self): return self._extra
588
589 def tags(self):
590 t = []
591 [t.extend(p.tags()) for p in self.parents()]
592 return t
593
594 def children(self):
595 return []
596
597 def flags(self, path):
598 if '_manifest' in self.__dict__:
599 try:
600 return self._manifest.flags(path)
601 except KeyError:
602 return ''
603
604 pnode = self._parents[0].changeset()[0]
605 orig = self._repo.dirstate.copies().get(path, path)
606 node, flag = self._repo.manifest.find(pnode, orig)
607 try:
608 ff = self._repo.dirstate.flagfunc(lambda x: flag or '')
609 return ff(path)
610 except OSError:
611 pass
612
613 if not node or path in self.deleted() or path in self.removed():
614 return ''
615 return flag
616
617 def filectx(self, path, filelog=None):
618 """get a file context from the working directory"""
619 return workingfilectx(self._repo, path, workingctx=self,
620 filelog=filelog)
621
622 def ancestor(self, c2):
623 """return the ancestor context of self and c2"""
624 return self._parents[0].ancestor(c2) # punt on two parents for now
625
626 def walk(self, match):
627 return sorted(self._repo.dirstate.walk(match, True, False))
628
629 def dirty(self, missing=False):
630 "check whether a working directory is modified"
631
632 return (self.p2() or self.branch() != self.p1().branch() or
633 self.modified() or self.added() or self.removed() or
634 (missing and self.deleted()))
635
636 class workingfilectx(filectx):
637 """A workingfilectx object makes access to data related to a particular
638 file in the working directory convenient."""
639 def __init__(self, repo, path, filelog=None, workingctx=None):
640 """changeid can be a changeset revision, node, or tag.
641 fileid can be a file revision or node."""
642 self._repo = repo
643 self._path = path
644 self._changeid = None
645 self._filerev = self._filenode = None
646
647 if filelog:
648 self._filelog = filelog
649 if workingctx:
650 self._changectx = workingctx
651
652 @propertycache
653 def _changectx(self):
654 return workingctx(self._repo)
655
656 def __nonzero__(self):
657 return True
658
659 def __str__(self):
660 return "%s@%s" % (self.path(), self._changectx)
661
662 def data(self): return self._repo.wread(self._path)
663 def renamed(self):
664 rp = self._repo.dirstate.copied(self._path)
665 if not rp:
666 return None
667 return rp, self._changectx._parents[0]._manifest.get(rp, nullid)
668
669 def parents(self):
670 '''return parent filectxs, following copies if necessary'''
671 def filenode(ctx, path):
672 return ctx._manifest.get(path, nullid)
673
674 path = self._path
675 fl = self._filelog
676 pcl = self._changectx._parents
677 renamed = self.renamed()
678
679 if renamed:
680 pl = [renamed + (None,)]
681 else:
682 pl = [(path, filenode(pcl[0], path), fl)]
683
684 for pc in pcl[1:]:
685 pl.append((path, filenode(pc, path), fl))
686
687 return [filectx(self._repo, p, fileid=n, filelog=l)
688 for p,n,l in pl if n != nullid]
689
690 def children(self):
691 return []
692
693 def size(self): return os.stat(self._repo.wjoin(self._path)).st_size
694 def date(self):
695 t, tz = self._changectx.date()
696 try:
697 return (int(os.lstat(self._repo.wjoin(self._path)).st_mtime), tz)
698 except OSError, err:
699 if err.errno != errno.ENOENT: raise
700 return (t, tz)
701
702 def cmp(self, text): return self._repo.wread(self._path) == text
703
704 class memctx(object):
705 """Use memctx to perform in-memory commits via localrepo.commitctx().
706
707 Revision information is supplied at initialization time while
708 related files data and is made available through a callback
709 mechanism. 'repo' is the current localrepo, 'parents' is a
710 sequence of two parent revisions identifiers (pass None for every
711 missing parent), 'text' is the commit message and 'files' lists
712 names of files touched by the revision (normalized and relative to
713 repository root).
714
715 filectxfn(repo, memctx, path) is a callable receiving the
716 repository, the current memctx object and the normalized path of
717 requested file, relative to repository root. It is fired by the
718 commit function for every file in 'files', but calls order is
719 undefined. If the file is available in the revision being
720 committed (updated or added), filectxfn returns a memfilectx
721 object. If the file was removed, filectxfn raises an
722 IOError. Moved files are represented by marking the source file
723 removed and the new file added with copy information (see
724 memfilectx).
725
726 user receives the committer name and defaults to current
727 repository username, date is the commit date in any format
728 supported by util.parsedate() and defaults to current date, extra
729 is a dictionary of metadata or is left empty.
730 """
731 def __init__(self, repo, parents, text, files, filectxfn, user=None,
732 date=None, extra=None):
733 self._repo = repo
734 self._rev = None
735 self._node = None
736 self._text = text
737 self._date = date and util.parsedate(date) or util.makedate()
738 self._user = user
739 parents = [(p or nullid) for p in parents]
740 p1, p2 = parents
741 self._parents = [changectx(self._repo, p) for p in (p1, p2)]
742 files = sorted(set(files))
743 self._status = [files, [], [], [], []]
744 self._filectxfn = filectxfn
745
746 self._extra = extra and extra.copy() or {}
747 if 'branch' not in self._extra:
748 self._extra['branch'] = 'default'
749 elif self._extra.get('branch') == '':
750 self._extra['branch'] = 'default'
751
752 def __str__(self):
753 return str(self._parents[0]) + "+"
754
755 def __int__(self):
756 return self._rev
757
758 def __nonzero__(self):
759 return True
760
761 def __getitem__(self, key):
762 return self.filectx(key)
763
764 def p1(self): return self._parents[0]
765 def p2(self): return self._parents[1]
766
767 def user(self): return self._user or self._repo.ui.username()
768 def date(self): return self._date
769 def description(self): return self._text
770 def files(self): return self.modified()
771 def modified(self): return self._status[0]
772 def added(self): return self._status[1]
773 def removed(self): return self._status[2]
774 def deleted(self): return self._status[3]
775 def unknown(self): return self._status[4]
776 def clean(self): return self._status[5]
777 def branch(self): return self._extra['branch']
778 def extra(self): return self._extra
779 def flags(self, f): return self[f].flags()
780
781 def parents(self):
782 """return contexts for each parent changeset"""
783 return self._parents
784
785 def filectx(self, path, filelog=None):
786 """get a file context from the working directory"""
787 return self._filectxfn(self._repo, self, path)
788
789 class memfilectx(object):
790 """memfilectx represents an in-memory file to commit.
791
792 See memctx for more details.
793 """
794 def __init__(self, path, data, islink, isexec, copied):
795 """
796 path is the normalized file path relative to repository root.
797 data is the file content as a string.
798 islink is True if the file is a symbolic link.
799 isexec is True if the file is executable.
800 copied is the source file path if current file was copied in the
801 revision being committed, or None."""
802 self._path = path
803 self._data = data
804 self._flags = (islink and 'l' or '') + (isexec and 'x' or '')
805 self._copied = None
806 if copied:
807 self._copied = (copied, nullid)
808
809 def __nonzero__(self): return True
810 def __str__(self): return "%s@%s" % (self.path(), self._changectx)
811 def path(self): return self._path
812 def data(self): return self._data
813 def flags(self): return self._flags
814 def isexec(self): return 'x' in self._flags
815 def islink(self): return 'l' in self._flags
816 def renamed(self): return self._copied