31 |
31 |
32 def __str__(self): |
32 def __str__(self): |
33 return short(self.node()) |
33 return short(self.node()) |
34 |
34 |
35 def __repr__(self): |
35 def __repr__(self): |
36 return "<changectx %s>" % short(self.node()) |
36 return "<changectx %s>" % str(self) |
37 |
37 |
38 def __eq__(self, other): |
38 def __eq__(self, other): |
39 return self._rev == other._rev |
39 return self._rev == other._rev |
40 |
40 |
41 def __nonzero__(self): |
41 def __nonzero__(self): |
42 return self._rev != -1 |
42 return self._rev != -1 |
43 |
43 |
44 def changeset(self): |
44 def __getattr__(self, name): |
45 try: |
45 if name == '_changeset': |
46 return self._changeset |
|
47 except AttributeError: |
|
48 self._changeset = self._repo.changelog.read(self.node()) |
46 self._changeset = self._repo.changelog.read(self.node()) |
49 return self._changeset |
47 return self._changeset |
50 |
48 elif name == '_manifest': |
51 def manifest(self): |
49 self._manifest = self._repo.manifest.read(self._changeset[0]) |
52 try: |
|
53 return self._manifest |
50 return self._manifest |
54 except AttributeError: |
51 else: |
55 self._manifest = self._repo.manifest.read(self.changeset()[0]) |
52 raise AttributeError, name |
56 return self._manifest |
53 |
|
54 def changeset(self): return self._changeset |
|
55 def manifest(self): return self._manifest |
57 |
56 |
58 def rev(self): return self._rev |
57 def rev(self): return self._rev |
59 def node(self): return self._node |
58 def node(self): return self._node |
60 def user(self): return self.changeset()[1] |
59 def user(self): return self._changeset[1] |
61 def date(self): return self.changeset()[2] |
60 def date(self): return self._changeset[2] |
62 def files(self): return self.changeset()[3] |
61 def files(self): return self._changeset[3] |
63 def description(self): return self.changeset()[4] |
62 def description(self): return self._changeset[4] |
64 |
63 |
65 def parents(self): |
64 def parents(self): |
66 """return contexts for each parent changeset""" |
65 """return contexts for each parent changeset""" |
67 p = self._repo.changelog.parents(self._node) |
66 p = self._repo.changelog.parents(self._node) |
68 return [ changectx(self._repo, x) for x in p ] |
67 return [ changectx(self._repo, x) for x in p ] |
71 """return contexts for each child changeset""" |
70 """return contexts for each child changeset""" |
72 c = self._repo.changelog.children(self._node) |
71 c = self._repo.changelog.children(self._node) |
73 return [ changectx(self._repo, x) for x in c ] |
72 return [ changectx(self._repo, x) for x in c ] |
74 |
73 |
75 def filenode(self, path): |
74 def filenode(self, path): |
76 node, flag = self._repo.manifest.find(self.changeset()[0], path) |
75 if hasattr(self, "_manifest"): |
|
76 return self._manifest[path] |
|
77 node, flag = self._repo.manifest.find(self._changeset[0], path) |
77 return node |
78 return node |
78 |
79 |
79 def filectx(self, path, fileid=None): |
80 def filectx(self, path, fileid=None): |
80 """get a file context from this changeset""" |
81 """get a file context from this changeset""" |
81 if fileid is None: |
82 if fileid is None: |
82 fileid = self.filenode(path) |
83 fileid = self.filenode(path) |
83 if not fileid: |
84 return filectx(self._repo, path, fileid=fileid, changectx=self) |
84 raise repo.LookupError(_("'%s' does not exist in changeset %s") % |
|
85 (path, hex(self.node()))) |
|
86 return filectx(self._repo, path, fileid=fileid) |
|
87 |
85 |
88 def filectxs(self): |
86 def filectxs(self): |
89 """generate a file context for each file in this changeset's |
87 """generate a file context for each file in this changeset's |
90 manifest""" |
88 manifest""" |
91 mf = self.manifest() |
89 mf = self.manifest() |
102 return changectx(self._repo, n) |
100 return changectx(self._repo, n) |
103 |
101 |
104 class filectx(object): |
102 class filectx(object): |
105 """A filecontext object makes access to data related to a particular |
103 """A filecontext object makes access to data related to a particular |
106 filerevision convenient.""" |
104 filerevision convenient.""" |
107 def __init__(self, repo_, path, changeid=None, fileid=None, filelog=None): |
105 def __init__(self, repo, path, changeid=None, fileid=None, |
|
106 filelog=None, changectx=None): |
108 """changeid can be a changeset revision, node, or tag. |
107 """changeid can be a changeset revision, node, or tag. |
109 fileid can be a file revision or node.""" |
108 fileid can be a file revision or node.""" |
110 self._repo = repo_ |
109 self._repo = repo |
111 self._path = path |
110 self._path = path |
112 |
111 |
113 assert changeid is not None or fileid is not None |
112 assert changeid is not None or fileid is not None |
114 |
113 |
115 if filelog: |
114 if filelog: |
116 self._filelog = filelog |
115 self._filelog = filelog |
117 else: |
116 if changectx: |
118 self._filelog = self._repo.file(self._path) |
117 self._changectx = changectx |
|
118 self._changeid = changectx.node() |
119 |
119 |
120 if fileid is None: |
120 if fileid is None: |
121 self._changeid = changeid |
121 self._changeid = changeid |
122 else: |
122 else: |
123 try: |
123 self._fileid = fileid |
124 self._filenode = self._filelog.lookup(fileid) |
|
125 except revlog.RevlogError, inst: |
|
126 raise repo.LookupError(str(inst)) |
|
127 self._changeid = self._filelog.linkrev(self._filenode) |
|
128 |
124 |
129 def __getattr__(self, name): |
125 def __getattr__(self, name): |
130 if name == '_changectx': |
126 if name == '_changectx': |
131 self._changectx = changectx(self._repo, self._changeid) |
127 self._changectx = changectx(self._repo, self._changeid) |
132 return self._changectx |
128 return self._changectx |
|
129 elif name == '_filelog': |
|
130 self._filelog = self._repo.file(self._path) |
|
131 return self._filelog |
|
132 elif name == '_changeid': |
|
133 self._changeid = self._filelog.linkrev(self._filenode) |
|
134 return self._changeid |
133 elif name == '_filenode': |
135 elif name == '_filenode': |
134 self._filenode = self._changectx.filenode(self._path) |
136 try: |
|
137 if hasattr(self, "_fileid"): |
|
138 self._filenode = self._filelog.lookup(self._fileid) |
|
139 else: |
|
140 self._filenode = self._changectx.filenode(self._path) |
|
141 except revlog.RevlogError, inst: |
|
142 raise repo.LookupError(str(inst)) |
135 return self._filenode |
143 return self._filenode |
136 elif name == '_filerev': |
144 elif name == '_filerev': |
137 self._filerev = self._filelog.rev(self._filenode) |
145 self._filerev = self._filelog.rev(self._filenode) |
138 return self._filerev |
146 return self._filerev |
139 else: |
147 else: |
291 if v: |
309 if v: |
292 f,n = v |
310 f,n = v |
293 return filectx(self._repo, f, fileid=n, filelog=flcache[f]) |
311 return filectx(self._repo, f, fileid=n, filelog=flcache[f]) |
294 |
312 |
295 return None |
313 return None |
|
314 |
|
315 class workingctx(changectx): |
|
316 """A workingctx object makes access to data related to |
|
317 the current working directory convenient.""" |
|
318 def __init__(self, repo): |
|
319 self._repo = repo |
|
320 self._rev = None |
|
321 self._node = None |
|
322 |
|
323 def __str__(self): |
|
324 return "." |
|
325 |
|
326 def __nonzero__(self): |
|
327 return True |
|
328 |
|
329 def __getattr__(self, name): |
|
330 if name == '_parents': |
|
331 self._parents = self._repo.parents() |
|
332 return self._parents |
|
333 if name == '_status': |
|
334 self._status = self._repo.status() |
|
335 return self._status |
|
336 if name == '_manifest': |
|
337 self._buildmanifest() |
|
338 return self._manifest |
|
339 else: |
|
340 raise AttributeError, name |
|
341 |
|
342 def _buildmanifest(self): |
|
343 """generate a manifest corresponding to the working directory""" |
|
344 |
|
345 man = self._parents[0].manifest().copy() |
|
346 copied = self._repo.dirstate.copies() |
|
347 modified, added, removed, deleted, unknown = self._status[:5] |
|
348 for i,l in (("a", added), ("m", modified), ("u", unknown)): |
|
349 for f in l: |
|
350 man[f] = man.get(copied.get(f, f), nullid) + i |
|
351 man.set(f, util.is_exec(self._repo.wjoin(f), man.execf(f))) |
|
352 |
|
353 for f in deleted + removed: |
|
354 del man[f] |
|
355 |
|
356 self._manifest = man |
|
357 |
|
358 def manifest(self): return self._manifest |
|
359 |
|
360 def user(self): return self._repo.ui.username() |
|
361 def date(self): return util.makedate() |
|
362 def description(self): return "" |
|
363 def files(self): |
|
364 f = self.modified() + self.added() + self.removed() |
|
365 f.sort() |
|
366 return f |
|
367 |
|
368 def modified(self): return self._status[0] |
|
369 def added(self): return self._status[1] |
|
370 def removed(self): return self._status[2] |
|
371 def deleted(self): return self._status[3] |
|
372 def unknown(self): return self._status[4] |
|
373 def clean(self): return self._status[5] |
|
374 |
|
375 def parents(self): |
|
376 """return contexts for each parent changeset""" |
|
377 return self._parents |
|
378 |
|
379 def children(self): |
|
380 return [] |
|
381 |
|
382 def filectx(self, path): |
|
383 """get a file context from the working directory""" |
|
384 return workingfilectx(self._repo, path, workingctx=self) |
|
385 |
|
386 def ancestor(self, c2): |
|
387 """return the ancestor context of self and c2""" |
|
388 return self._parents[0].ancestor(c2) # punt on two parents for now |
|
389 |
|
390 class workingfilectx(filectx): |
|
391 """A workingfilectx object makes access to data related to a particular |
|
392 file in the working directory convenient.""" |
|
393 def __init__(self, repo, path, filelog=None, workingctx=None): |
|
394 """changeid can be a changeset revision, node, or tag. |
|
395 fileid can be a file revision or node.""" |
|
396 self._repo = repo |
|
397 self._path = path |
|
398 self._changeid = None |
|
399 self._filerev = self._filenode = None |
|
400 |
|
401 if filelog: |
|
402 self._filelog = filelog |
|
403 if workingctx: |
|
404 self._changectx = workingctx |
|
405 |
|
406 def __getattr__(self, name): |
|
407 if name == '_changectx': |
|
408 self._changectx = workingctx(repo) |
|
409 return self._changectx |
|
410 elif name == '_repopath': |
|
411 self._repopath = self._repo.dirstate.copied(p) or self._path |
|
412 elif name == '_filelog': |
|
413 self._filelog = self._repo.file(self._repopath) |
|
414 return self._filelog |
|
415 else: |
|
416 raise AttributeError, name |
|
417 |
|
418 def __nonzero__(self): |
|
419 return True |
|
420 |
|
421 def __str__(self): |
|
422 return "%s@." % self.path() |
|
423 |
|
424 def filectx(self, fileid): |
|
425 '''opens an arbitrary revision of the file without |
|
426 opening a new filelog''' |
|
427 return filectx(self._repo, self._repopath, fileid=fileid, |
|
428 filelog=self._filelog) |
|
429 |
|
430 def rev(self): |
|
431 if hasattr(self, "_changectx"): |
|
432 return self._changectx.rev() |
|
433 return self._filelog.linkrev(self._filenode) |
|
434 |
|
435 def data(self): return self._repo.wread(self._path) |
|
436 def renamed(self): |
|
437 rp = self._repopath |
|
438 if rp == self._path: |
|
439 return None |
|
440 return rp, self._workingctx._parents._manifest.get(rp, nullid) |
|
441 |
|
442 def parents(self): |
|
443 '''return parent filectxs, following copies if necessary''' |
|
444 p = self._path |
|
445 rp = self._repopath |
|
446 pcl = self._workingctx._parents |
|
447 fl = self._filelog |
|
448 pl = [ (rp, pcl[0]._manifest.get(rp, nullid), fl) ] |
|
449 if len(pcl) > 1: |
|
450 if rp != p: |
|
451 fl = None |
|
452 pl.append((p, pcl[1]._manifest.get(p, nullid), fl)) |
|
453 |
|
454 return [ filectx(self._repo, p, fileid=n, filelog=l) |
|
455 for p,n,l in pl if n != nullid ] |
|
456 |
|
457 def children(self): |
|
458 return [] |
|
459 |