##// END OF EJS Templates
Merge with crew
Matt Mackall -
r3352:69fe021c merge default
parent child Browse files
Show More
@@ -0,0 +1,34 b''
1 #!/bin/sh
2
3 echo % init foo-base
4 hg init foo-base
5
6 echo % create alpha in first repo
7 cd foo-base
8 echo 'alpha' > alpha
9 hg ci -A -m 'add alpha' -d '1 0'
10 cd ..
11
12 echo % clone foo-base to foo-work
13 hg clone foo-base foo-work
14
15 echo % create beta in second repo
16 cd foo-work
17 echo 'beta' > beta
18 hg ci -A -m 'add beta' -d '2 0'
19 cd ..
20
21 echo % create gamma in first repo
22 cd foo-base
23 echo 'gamma' > gamma
24 hg ci -A -m 'add gamma' -d '3 0'
25 cd ..
26
27 echo % pull into work and merge
28 cd foo-work
29 hg pull -q
30 hg merge
31
32 echo % revert to changeset 1 to simulate a failed merge
33 rm -fr *
34 hg up -C 1
@@ -0,0 +1,14 b''
1 % init foo-base
2 % create alpha in first repo
3 adding alpha
4 % clone foo-base to foo-work
5 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
6 % create beta in second repo
7 adding beta
8 % create gamma in first repo
9 adding gamma
10 % pull into work and merge
11 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
12 (branch merge, don't forget to commit)
13 % revert to changeset 1 to simulate a failed merge
14 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
@@ -1,480 +1,481 b''
1 # context.py - changeset and file context objects for mercurial
1 # context.py - changeset and file context objects for mercurial
2 #
2 #
3 # Copyright 2006 Matt Mackall <mpm@selenic.com>
3 # Copyright 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from node import *
8 from node import *
9 from i18n import gettext as _
9 from i18n import gettext as _
10 from demandload import demandload
10 from demandload import demandload
11 demandload(globals(), "ancestor bdiff repo revlog util os")
11 demandload(globals(), "ancestor bdiff repo revlog util os")
12
12
13 class changectx(object):
13 class changectx(object):
14 """A changecontext object makes access to data related to a particular
14 """A changecontext object makes access to data related to a particular
15 changeset convenient."""
15 changeset convenient."""
16 def __init__(self, repo, changeid=None):
16 def __init__(self, repo, changeid=None):
17 """changeid is a revision number, node, or tag"""
17 """changeid is a revision number, node, or tag"""
18 self._repo = repo
18 self._repo = repo
19
19
20 if not changeid and changeid != 0:
20 if not changeid and changeid != 0:
21 p1, p2 = self._repo.dirstate.parents()
21 p1, p2 = self._repo.dirstate.parents()
22 self._rev = self._repo.changelog.rev(p1)
22 self._rev = self._repo.changelog.rev(p1)
23 if self._rev == -1:
23 if self._rev == -1:
24 changeid = 'tip'
24 changeid = 'tip'
25 else:
25 else:
26 self._node = p1
26 self._node = p1
27 return
27 return
28
28
29 self._node = self._repo.lookup(changeid)
29 self._node = self._repo.lookup(changeid)
30 self._rev = self._repo.changelog.rev(self._node)
30 self._rev = self._repo.changelog.rev(self._node)
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>" % str(self)
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 __getattr__(self, name):
44 def __getattr__(self, name):
45 if name == '_changeset':
45 if name == '_changeset':
46 self._changeset = self._repo.changelog.read(self.node())
46 self._changeset = self._repo.changelog.read(self.node())
47 return self._changeset
47 return self._changeset
48 elif name == '_manifest':
48 elif name == '_manifest':
49 self._manifest = self._repo.manifest.read(self._changeset[0])
49 self._manifest = self._repo.manifest.read(self._changeset[0])
50 return self._manifest
50 return self._manifest
51 elif name == '_manifestdelta':
51 elif name == '_manifestdelta':
52 md = self._repo.manifest.readdelta(self._changeset[0])
52 md = self._repo.manifest.readdelta(self._changeset[0])
53 self._manifestdelta = md
53 self._manifestdelta = md
54 return self._manifestdelta
54 return self._manifestdelta
55 else:
55 else:
56 raise AttributeError, name
56 raise AttributeError, name
57
57
58 def changeset(self): return self._changeset
58 def changeset(self): return self._changeset
59 def manifest(self): return self._manifest
59 def manifest(self): return self._manifest
60
60
61 def rev(self): return self._rev
61 def rev(self): return self._rev
62 def node(self): return self._node
62 def node(self): return self._node
63 def user(self): return self._changeset[1]
63 def user(self): return self._changeset[1]
64 def date(self): return self._changeset[2]
64 def date(self): return self._changeset[2]
65 def files(self): return self._changeset[3]
65 def files(self): return self._changeset[3]
66 def description(self): return self._changeset[4]
66 def description(self): return self._changeset[4]
67
67
68 def parents(self):
68 def parents(self):
69 """return contexts for each parent changeset"""
69 """return contexts for each parent changeset"""
70 p = self._repo.changelog.parents(self._node)
70 p = self._repo.changelog.parents(self._node)
71 return [ changectx(self._repo, x) for x in p ]
71 return [ changectx(self._repo, x) for x in p ]
72
72
73 def children(self):
73 def children(self):
74 """return contexts for each child changeset"""
74 """return contexts for each child changeset"""
75 c = self._repo.changelog.children(self._node)
75 c = self._repo.changelog.children(self._node)
76 return [ changectx(self._repo, x) for x in c ]
76 return [ changectx(self._repo, x) for x in c ]
77
77
78 def filenode(self, path):
78 def filenode(self, path):
79 if '_manifest' in self.__dict__:
79 if '_manifest' in self.__dict__:
80 try:
80 try:
81 return self._manifest[path]
81 return self._manifest[path]
82 except KeyError:
82 except KeyError:
83 raise repo.LookupError(_("'%s' not found in manifest") % path)
83 raise repo.LookupError(_("'%s' not found in manifest") % path)
84 if '_manifestdelta' in self.__dict__ or path in self.files():
84 if '_manifestdelta' in self.__dict__ or path in self.files():
85 if path in self._manifestdelta:
85 if path in self._manifestdelta:
86 return self._manifestdelta[path]
86 return self._manifestdelta[path]
87 node, flag = self._repo.manifest.find(self._changeset[0], path)
87 node, flag = self._repo.manifest.find(self._changeset[0], path)
88 if not node:
88 if not node:
89 raise repo.LookupError(_("'%s' not found in manifest") % path)
89 raise repo.LookupError(_("'%s' not found in manifest") % path)
90
90
91 return node
91 return node
92
92
93 def filectx(self, path, fileid=None):
93 def filectx(self, path, fileid=None):
94 """get a file context from this changeset"""
94 """get a file context from this changeset"""
95 if fileid is None:
95 if fileid is None:
96 fileid = self.filenode(path)
96 fileid = self.filenode(path)
97 return filectx(self._repo, path, fileid=fileid, changectx=self)
97 return filectx(self._repo, path, fileid=fileid, changectx=self)
98
98
99 def filectxs(self):
99 def filectxs(self):
100 """generate a file context for each file in this changeset's
100 """generate a file context for each file in this changeset's
101 manifest"""
101 manifest"""
102 mf = self.manifest()
102 mf = self.manifest()
103 m = mf.keys()
103 m = mf.keys()
104 m.sort()
104 m.sort()
105 for f in m:
105 for f in m:
106 yield self.filectx(f, fileid=mf[f])
106 yield self.filectx(f, fileid=mf[f])
107
107
108 def ancestor(self, c2):
108 def ancestor(self, c2):
109 """
109 """
110 return the ancestor context of self and c2
110 return the ancestor context of self and c2
111 """
111 """
112 n = self._repo.changelog.ancestor(self._node, c2._node)
112 n = self._repo.changelog.ancestor(self._node, c2._node)
113 return changectx(self._repo, n)
113 return changectx(self._repo, n)
114
114
115 class filectx(object):
115 class filectx(object):
116 """A filecontext object makes access to data related to a particular
116 """A filecontext object makes access to data related to a particular
117 filerevision convenient."""
117 filerevision convenient."""
118 def __init__(self, repo, path, changeid=None, fileid=None,
118 def __init__(self, repo, path, changeid=None, fileid=None,
119 filelog=None, changectx=None):
119 filelog=None, changectx=None):
120 """changeid can be a changeset revision, node, or tag.
120 """changeid can be a changeset revision, node, or tag.
121 fileid can be a file revision or node."""
121 fileid can be a file revision or node."""
122 self._repo = repo
122 self._repo = repo
123 self._path = path
123 self._path = path
124
124
125 assert changeid is not None or fileid is not None
125 assert changeid is not None or fileid is not None
126
126
127 if filelog:
127 if filelog:
128 self._filelog = filelog
128 self._filelog = filelog
129 if changectx:
129 if changectx:
130 self._changectx = changectx
130 self._changectx = changectx
131 self._changeid = changectx.node()
131 self._changeid = changectx.node()
132
132
133 if fileid is None:
133 if fileid is None:
134 self._changeid = changeid
134 self._changeid = changeid
135 else:
135 else:
136 self._fileid = fileid
136 self._fileid = fileid
137
137
138 def __getattr__(self, name):
138 def __getattr__(self, name):
139 if name == '_changectx':
139 if name == '_changectx':
140 self._changectx = changectx(self._repo, self._changeid)
140 self._changectx = changectx(self._repo, self._changeid)
141 return self._changectx
141 return self._changectx
142 elif name == '_filelog':
142 elif name == '_filelog':
143 self._filelog = self._repo.file(self._path)
143 self._filelog = self._repo.file(self._path)
144 return self._filelog
144 return self._filelog
145 elif name == '_changeid':
145 elif name == '_changeid':
146 self._changeid = self._filelog.linkrev(self._filenode)
146 self._changeid = self._filelog.linkrev(self._filenode)
147 return self._changeid
147 return self._changeid
148 elif name == '_filenode':
148 elif name == '_filenode':
149 try:
149 try:
150 if '_fileid' in self.__dict__:
150 if '_fileid' in self.__dict__:
151 self._filenode = self._filelog.lookup(self._fileid)
151 self._filenode = self._filelog.lookup(self._fileid)
152 else:
152 else:
153 self._filenode = self._changectx.filenode(self._path)
153 self._filenode = self._changectx.filenode(self._path)
154 except revlog.RevlogError, inst:
154 except revlog.RevlogError, inst:
155 raise repo.LookupError(str(inst))
155 raise repo.LookupError(str(inst))
156 return self._filenode
156 return self._filenode
157 elif name == '_filerev':
157 elif name == '_filerev':
158 self._filerev = self._filelog.rev(self._filenode)
158 self._filerev = self._filelog.rev(self._filenode)
159 return self._filerev
159 return self._filerev
160 else:
160 else:
161 raise AttributeError, name
161 raise AttributeError, name
162
162
163 def __nonzero__(self):
163 def __nonzero__(self):
164 return self._filerev != nullid
164 return self._filerev != nullid
165
165
166 def __str__(self):
166 def __str__(self):
167 return "%s@%s" % (self.path(), short(self.node()))
167 return "%s@%s" % (self.path(), short(self.node()))
168
168
169 def __repr__(self):
169 def __repr__(self):
170 return "<filectx %s>" % str(self)
170 return "<filectx %s>" % str(self)
171
171
172 def __eq__(self, other):
172 def __eq__(self, other):
173 return self._path == other._path and self._changeid == other._changeid
173 return self._path == other._path and self._changeid == other._changeid
174
174
175 def filectx(self, fileid):
175 def filectx(self, fileid):
176 '''opens an arbitrary revision of the file without
176 '''opens an arbitrary revision of the file without
177 opening a new filelog'''
177 opening a new filelog'''
178 return filectx(self._repo, self._path, fileid=fileid,
178 return filectx(self._repo, self._path, fileid=fileid,
179 filelog=self._filelog)
179 filelog=self._filelog)
180
180
181 def filerev(self): return self._filerev
181 def filerev(self): return self._filerev
182 def filenode(self): return self._filenode
182 def filenode(self): return self._filenode
183 def filelog(self): return self._filelog
183 def filelog(self): return self._filelog
184
184
185 def rev(self):
185 def rev(self):
186 if '_changectx' in self.__dict__:
186 if '_changectx' in self.__dict__:
187 return self._changectx.rev()
187 return self._changectx.rev()
188 return self._filelog.linkrev(self._filenode)
188 return self._filelog.linkrev(self._filenode)
189
189
190 def node(self): return self._changectx.node()
190 def node(self): return self._changectx.node()
191 def user(self): return self._changectx.user()
191 def user(self): return self._changectx.user()
192 def date(self): return self._changectx.date()
192 def date(self): return self._changectx.date()
193 def files(self): return self._changectx.files()
193 def files(self): return self._changectx.files()
194 def description(self): return self._changectx.description()
194 def description(self): return self._changectx.description()
195 def manifest(self): return self._changectx.manifest()
195 def manifest(self): return self._changectx.manifest()
196 def changectx(self): return self._changectx
196 def changectx(self): return self._changectx
197
197
198 def data(self): return self._filelog.read(self._filenode)
198 def data(self): return self._filelog.read(self._filenode)
199 def renamed(self): return self._filelog.renamed(self._filenode)
199 def renamed(self): return self._filelog.renamed(self._filenode)
200 def path(self): return self._path
200 def path(self): return self._path
201 def size(self): return self._filelog.size(self._filerev)
201 def size(self): return self._filelog.size(self._filerev)
202
202
203 def cmp(self, text): return self._filelog.cmp(self._filenode, text)
203 def cmp(self, text): return self._filelog.cmp(self._filenode, text)
204
204
205 def parents(self):
205 def parents(self):
206 p = self._path
206 p = self._path
207 fl = self._filelog
207 fl = self._filelog
208 pl = [ (p, n, fl) for n in self._filelog.parents(self._filenode) ]
208 pl = [ (p, n, fl) for n in self._filelog.parents(self._filenode) ]
209
209
210 r = self.renamed()
210 r = self.renamed()
211 if r:
211 if r:
212 pl[0] = (r[0], r[1], None)
212 pl[0] = (r[0], r[1], None)
213
213
214 return [ filectx(self._repo, p, fileid=n, filelog=l)
214 return [ filectx(self._repo, p, fileid=n, filelog=l)
215 for p,n,l in pl if n != nullid ]
215 for p,n,l in pl if n != nullid ]
216
216
217 def children(self):
217 def children(self):
218 # hard for renames
218 # hard for renames
219 c = self._filelog.children(self._filenode)
219 c = self._filelog.children(self._filenode)
220 return [ filectx(self._repo, self._path, fileid=x,
220 return [ filectx(self._repo, self._path, fileid=x,
221 filelog=self._filelog) for x in c ]
221 filelog=self._filelog) for x in c ]
222
222
223 def annotate(self, follow=False):
223 def annotate(self, follow=False):
224 '''returns a list of tuples of (ctx, line) for each line
224 '''returns a list of tuples of (ctx, line) for each line
225 in the file, where ctx is the filectx of the node where
225 in the file, where ctx is the filectx of the node where
226 that line was last changed'''
226 that line was last changed'''
227
227
228 def decorate(text, rev):
228 def decorate(text, rev):
229 return ([rev] * len(text.splitlines()), text)
229 return ([rev] * len(text.splitlines()), text)
230
230
231 def pair(parent, child):
231 def pair(parent, child):
232 for a1, a2, b1, b2 in bdiff.blocks(parent[1], child[1]):
232 for a1, a2, b1, b2 in bdiff.blocks(parent[1], child[1]):
233 child[0][b1:b2] = parent[0][a1:a2]
233 child[0][b1:b2] = parent[0][a1:a2]
234 return child
234 return child
235
235
236 getlog = util.cachefunc(lambda x: self._repo.file(x))
236 getlog = util.cachefunc(lambda x: self._repo.file(x))
237 def getctx(path, fileid):
237 def getctx(path, fileid):
238 log = path == self._path and self._filelog or getlog(path)
238 log = path == self._path and self._filelog or getlog(path)
239 return filectx(self._repo, path, fileid=fileid, filelog=log)
239 return filectx(self._repo, path, fileid=fileid, filelog=log)
240 getctx = util.cachefunc(getctx)
240 getctx = util.cachefunc(getctx)
241
241
242 def parents(f):
242 def parents(f):
243 # we want to reuse filectx objects as much as possible
243 # we want to reuse filectx objects as much as possible
244 p = f._path
244 p = f._path
245 if f._filerev is None: # working dir
245 if f._filerev is None: # working dir
246 pl = [ (n.path(), n.filerev()) for n in f.parents() ]
246 pl = [ (n.path(), n.filerev()) for n in f.parents() ]
247 else:
247 else:
248 pl = [ (p, n) for n in f._filelog.parentrevs(f._filerev) ]
248 pl = [ (p, n) for n in f._filelog.parentrevs(f._filerev) ]
249
249
250 if follow:
250 if follow:
251 r = f.renamed()
251 r = f.renamed()
252 if r:
252 if r:
253 pl[0] = (r[0], getlog(r[0]).rev(r[1]))
253 pl[0] = (r[0], getlog(r[0]).rev(r[1]))
254
254
255 return [ getctx(p, n) for p, n in pl if n != -1 ]
255 return [ getctx(p, n) for p, n in pl if n != -1 ]
256
256
257 # find all ancestors
257 # find all ancestors
258 needed = {self: 1}
258 needed = {self: 1}
259 visit = [self]
259 visit = [self]
260 files = [self._path]
260 files = [self._path]
261 while visit:
261 while visit:
262 f = visit.pop(0)
262 f = visit.pop(0)
263 for p in parents(f):
263 for p in parents(f):
264 if p not in needed:
264 if p not in needed:
265 needed[p] = 1
265 needed[p] = 1
266 visit.append(p)
266 visit.append(p)
267 if p._path not in files:
267 if p._path not in files:
268 files.append(p._path)
268 files.append(p._path)
269 else:
269 else:
270 # count how many times we'll use this
270 # count how many times we'll use this
271 needed[p] += 1
271 needed[p] += 1
272
272
273 # sort by revision (per file) which is a topological order
273 # sort by revision (per file) which is a topological order
274 visit = []
274 visit = []
275 files.reverse()
275 files.reverse()
276 for f in files:
276 for f in files:
277 fn = [(n._filerev, n) for n in needed.keys() if n._path == f]
277 fn = [(n._filerev, n) for n in needed.keys() if n._path == f]
278 fn.sort()
278 fn.sort()
279 visit.extend(fn)
279 visit.extend(fn)
280 hist = {}
280 hist = {}
281
281
282 for r, f in visit:
282 for r, f in visit:
283 curr = decorate(f.data(), f)
283 curr = decorate(f.data(), f)
284 for p in parents(f):
284 for p in parents(f):
285 if p != nullid:
285 if p != nullid:
286 curr = pair(hist[p], curr)
286 curr = pair(hist[p], curr)
287 # trim the history of unneeded revs
287 # trim the history of unneeded revs
288 needed[p] -= 1
288 needed[p] -= 1
289 if not needed[p]:
289 if not needed[p]:
290 del hist[p]
290 del hist[p]
291 hist[f] = curr
291 hist[f] = curr
292
292
293 return zip(hist[f][0], hist[f][1].splitlines(1))
293 return zip(hist[f][0], hist[f][1].splitlines(1))
294
294
295 def ancestor(self, fc2):
295 def ancestor(self, fc2):
296 """
296 """
297 find the common ancestor file context, if any, of self, and fc2
297 find the common ancestor file context, if any, of self, and fc2
298 """
298 """
299
299
300 acache = {}
300 acache = {}
301
301
302 # prime the ancestor cache for the working directory
302 # prime the ancestor cache for the working directory
303 for c in (self, fc2):
303 for c in (self, fc2):
304 if c._filerev == None:
304 if c._filerev == None:
305 pl = [ (n.path(), n.filenode()) for n in c.parents() ]
305 pl = [ (n.path(), n.filenode()) for n in c.parents() ]
306 acache[(c._path, None)] = pl
306 acache[(c._path, None)] = pl
307
307
308 flcache = {self._path:self._filelog, fc2._path:fc2._filelog}
308 flcache = {self._path:self._filelog, fc2._path:fc2._filelog}
309 def parents(vertex):
309 def parents(vertex):
310 if vertex in acache:
310 if vertex in acache:
311 return acache[vertex]
311 return acache[vertex]
312 f, n = vertex
312 f, n = vertex
313 if f not in flcache:
313 if f not in flcache:
314 flcache[f] = self._repo.file(f)
314 flcache[f] = self._repo.file(f)
315 fl = flcache[f]
315 fl = flcache[f]
316 pl = [ (f,p) for p in fl.parents(n) if p != nullid ]
316 pl = [ (f,p) for p in fl.parents(n) if p != nullid ]
317 re = fl.renamed(n)
317 re = fl.renamed(n)
318 if re:
318 if re:
319 pl.append(re)
319 pl.append(re)
320 acache[vertex]=pl
320 acache[vertex]=pl
321 return pl
321 return pl
322
322
323 a, b = (self._path, self._filenode), (fc2._path, fc2._filenode)
323 a, b = (self._path, self._filenode), (fc2._path, fc2._filenode)
324 v = ancestor.ancestor(a, b, parents)
324 v = ancestor.ancestor(a, b, parents)
325 if v:
325 if v:
326 f,n = v
326 f,n = v
327 return filectx(self._repo, f, fileid=n, filelog=flcache[f])
327 return filectx(self._repo, f, fileid=n, filelog=flcache[f])
328
328
329 return None
329 return None
330
330
331 class workingctx(changectx):
331 class workingctx(changectx):
332 """A workingctx object makes access to data related to
332 """A workingctx object makes access to data related to
333 the current working directory convenient."""
333 the current working directory convenient."""
334 def __init__(self, repo):
334 def __init__(self, repo):
335 self._repo = repo
335 self._repo = repo
336 self._rev = None
336 self._rev = None
337 self._node = None
337 self._node = None
338
338
339 def __str__(self):
339 def __str__(self):
340 return str(self._parents[0]) + "+"
340 return str(self._parents[0]) + "+"
341
341
342 def __nonzero__(self):
342 def __nonzero__(self):
343 return True
343 return True
344
344
345 def __getattr__(self, name):
345 def __getattr__(self, name):
346 if name == '_parents':
346 if name == '_parents':
347 self._parents = self._repo.parents()
347 self._parents = self._repo.parents()
348 return self._parents
348 return self._parents
349 if name == '_status':
349 if name == '_status':
350 self._status = self._repo.status()
350 self._status = self._repo.status()
351 return self._status
351 return self._status
352 if name == '_manifest':
352 if name == '_manifest':
353 self._buildmanifest()
353 self._buildmanifest()
354 return self._manifest
354 return self._manifest
355 else:
355 else:
356 raise AttributeError, name
356 raise AttributeError, name
357
357
358 def _buildmanifest(self):
358 def _buildmanifest(self):
359 """generate a manifest corresponding to the working directory"""
359 """generate a manifest corresponding to the working directory"""
360
360
361 man = self._parents[0].manifest().copy()
361 man = self._parents[0].manifest().copy()
362 copied = self._repo.dirstate.copies()
362 copied = self._repo.dirstate.copies()
363 modified, added, removed, deleted, unknown = self._status[:5]
363 modified, added, removed, deleted, unknown = self._status[:5]
364 for i,l in (("a", added), ("m", modified), ("u", unknown)):
364 for i,l in (("a", added), ("m", modified), ("u", unknown)):
365 for f in l:
365 for f in l:
366 man[f] = man.get(copied.get(f, f), nullid) + i
366 man[f] = man.get(copied.get(f, f), nullid) + i
367 man.set(f, util.is_exec(self._repo.wjoin(f), man.execf(f)))
367 man.set(f, util.is_exec(self._repo.wjoin(f), man.execf(f)))
368
368
369 for f in deleted + removed:
369 for f in deleted + removed:
370 del man[f]
370 if f in man:
371 del man[f]
371
372
372 self._manifest = man
373 self._manifest = man
373
374
374 def manifest(self): return self._manifest
375 def manifest(self): return self._manifest
375
376
376 def user(self): return self._repo.ui.username()
377 def user(self): return self._repo.ui.username()
377 def date(self): return util.makedate()
378 def date(self): return util.makedate()
378 def description(self): return ""
379 def description(self): return ""
379 def files(self):
380 def files(self):
380 f = self.modified() + self.added() + self.removed()
381 f = self.modified() + self.added() + self.removed()
381 f.sort()
382 f.sort()
382 return f
383 return f
383
384
384 def modified(self): return self._status[0]
385 def modified(self): return self._status[0]
385 def added(self): return self._status[1]
386 def added(self): return self._status[1]
386 def removed(self): return self._status[2]
387 def removed(self): return self._status[2]
387 def deleted(self): return self._status[3]
388 def deleted(self): return self._status[3]
388 def unknown(self): return self._status[4]
389 def unknown(self): return self._status[4]
389 def clean(self): return self._status[5]
390 def clean(self): return self._status[5]
390
391
391 def parents(self):
392 def parents(self):
392 """return contexts for each parent changeset"""
393 """return contexts for each parent changeset"""
393 return self._parents
394 return self._parents
394
395
395 def children(self):
396 def children(self):
396 return []
397 return []
397
398
398 def filectx(self, path):
399 def filectx(self, path):
399 """get a file context from the working directory"""
400 """get a file context from the working directory"""
400 return workingfilectx(self._repo, path, workingctx=self)
401 return workingfilectx(self._repo, path, workingctx=self)
401
402
402 def ancestor(self, c2):
403 def ancestor(self, c2):
403 """return the ancestor context of self and c2"""
404 """return the ancestor context of self and c2"""
404 return self._parents[0].ancestor(c2) # punt on two parents for now
405 return self._parents[0].ancestor(c2) # punt on two parents for now
405
406
406 class workingfilectx(filectx):
407 class workingfilectx(filectx):
407 """A workingfilectx object makes access to data related to a particular
408 """A workingfilectx object makes access to data related to a particular
408 file in the working directory convenient."""
409 file in the working directory convenient."""
409 def __init__(self, repo, path, filelog=None, workingctx=None):
410 def __init__(self, repo, path, filelog=None, workingctx=None):
410 """changeid can be a changeset revision, node, or tag.
411 """changeid can be a changeset revision, node, or tag.
411 fileid can be a file revision or node."""
412 fileid can be a file revision or node."""
412 self._repo = repo
413 self._repo = repo
413 self._path = path
414 self._path = path
414 self._changeid = None
415 self._changeid = None
415 self._filerev = self._filenode = None
416 self._filerev = self._filenode = None
416
417
417 if filelog:
418 if filelog:
418 self._filelog = filelog
419 self._filelog = filelog
419 if workingctx:
420 if workingctx:
420 self._changectx = workingctx
421 self._changectx = workingctx
421
422
422 def __getattr__(self, name):
423 def __getattr__(self, name):
423 if name == '_changectx':
424 if name == '_changectx':
424 self._changectx = workingctx(repo)
425 self._changectx = workingctx(repo)
425 return self._changectx
426 return self._changectx
426 elif name == '_repopath':
427 elif name == '_repopath':
427 self._repopath = (self._repo.dirstate.copied(self._path)
428 self._repopath = (self._repo.dirstate.copied(self._path)
428 or self._path)
429 or self._path)
429 return self._repopath
430 return self._repopath
430 elif name == '_filelog':
431 elif name == '_filelog':
431 self._filelog = self._repo.file(self._repopath)
432 self._filelog = self._repo.file(self._repopath)
432 return self._filelog
433 return self._filelog
433 else:
434 else:
434 raise AttributeError, name
435 raise AttributeError, name
435
436
436 def __nonzero__(self):
437 def __nonzero__(self):
437 return True
438 return True
438
439
439 def __str__(self):
440 def __str__(self):
440 return "%s@%s" % (self.path(), self._changectx)
441 return "%s@%s" % (self.path(), self._changectx)
441
442
442 def filectx(self, fileid):
443 def filectx(self, fileid):
443 '''opens an arbitrary revision of the file without
444 '''opens an arbitrary revision of the file without
444 opening a new filelog'''
445 opening a new filelog'''
445 return filectx(self._repo, self._repopath, fileid=fileid,
446 return filectx(self._repo, self._repopath, fileid=fileid,
446 filelog=self._filelog)
447 filelog=self._filelog)
447
448
448 def rev(self):
449 def rev(self):
449 if '_changectx' in self.__dict__:
450 if '_changectx' in self.__dict__:
450 return self._changectx.rev()
451 return self._changectx.rev()
451 return self._filelog.linkrev(self._filenode)
452 return self._filelog.linkrev(self._filenode)
452
453
453 def data(self): return self._repo.wread(self._path)
454 def data(self): return self._repo.wread(self._path)
454 def renamed(self):
455 def renamed(self):
455 rp = self._repopath
456 rp = self._repopath
456 if rp == self._path:
457 if rp == self._path:
457 return None
458 return None
458 return rp, self._workingctx._parents._manifest.get(rp, nullid)
459 return rp, self._workingctx._parents._manifest.get(rp, nullid)
459
460
460 def parents(self):
461 def parents(self):
461 '''return parent filectxs, following copies if necessary'''
462 '''return parent filectxs, following copies if necessary'''
462 p = self._path
463 p = self._path
463 rp = self._repopath
464 rp = self._repopath
464 pcl = self._changectx._parents
465 pcl = self._changectx._parents
465 fl = self._filelog
466 fl = self._filelog
466 pl = [ (rp, pcl[0]._manifest.get(rp, nullid), fl) ]
467 pl = [ (rp, pcl[0]._manifest.get(rp, nullid), fl) ]
467 if len(pcl) > 1:
468 if len(pcl) > 1:
468 if rp != p:
469 if rp != p:
469 fl = None
470 fl = None
470 pl.append((p, pcl[1]._manifest.get(p, nullid), fl))
471 pl.append((p, pcl[1]._manifest.get(p, nullid), fl))
471
472
472 return [ filectx(self._repo, p, fileid=n, filelog=l)
473 return [ filectx(self._repo, p, fileid=n, filelog=l)
473 for p,n,l in pl if n != nullid ]
474 for p,n,l in pl if n != nullid ]
474
475
475 def children(self):
476 def children(self):
476 return []
477 return []
477
478
478 def size(self): return os.stat(self._repo.wjoin(self._path)).st_size
479 def size(self): return os.stat(self._repo.wjoin(self._path)).st_size
479
480
480 def cmp(self, text): return self._repo.wread(self._path) == text
481 def cmp(self, text): return self._repo.wread(self._path) == text
General Comments 0
You need to be logged in to leave comments. Login now