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