##// END OF EJS Templates
filelog: make metadata method private
Matt Mackall -
r3123:4ea58eb3 default
parent child Browse files
Show More
@@ -1,131 +1,131 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
9
10 class changectx(object):
10 class changectx(object):
11 """A changecontext object makes access to data related to a particular
11 """A changecontext object makes access to data related to a particular
12 changeset convenient."""
12 changeset convenient."""
13 def __init__(self, repo, changeid):
13 def __init__(self, repo, changeid):
14 """changeid is a revision number, node, or tag"""
14 """changeid is a revision number, node, or tag"""
15 self._repo = repo
15 self._repo = repo
16
16
17 self._node = self._repo.lookup(changeid)
17 self._node = self._repo.lookup(changeid)
18 self._rev = self._repo.changelog.rev(self._node)
18 self._rev = self._repo.changelog.rev(self._node)
19
19
20 def changeset(self):
20 def changeset(self):
21 try:
21 try:
22 return self._changeset
22 return self._changeset
23 except AttributeError:
23 except AttributeError:
24 self._changeset = self._repo.changelog.read(self.node())
24 self._changeset = self._repo.changelog.read(self.node())
25 return self._changeset
25 return self._changeset
26
26
27 def manifest(self):
27 def manifest(self):
28 try:
28 try:
29 return self._manifest
29 return self._manifest
30 except AttributeError:
30 except AttributeError:
31 self._manifest = self._repo.manifest.read(self.changeset()[0])
31 self._manifest = self._repo.manifest.read(self.changeset()[0])
32 return self._manifest
32 return self._manifest
33
33
34 def rev(self): return self._rev
34 def rev(self): return self._rev
35 def node(self): return self._node
35 def node(self): return self._node
36 def user(self): return self.changeset()[1]
36 def user(self): return self.changeset()[1]
37 def date(self): return self.changeset()[2]
37 def date(self): return self.changeset()[2]
38 def files(self): return self.changeset()[3]
38 def files(self): return self.changeset()[3]
39 def description(self): return self.changeset()[4]
39 def description(self): return self.changeset()[4]
40
40
41 def parents(self):
41 def parents(self):
42 """return contexts for each parent changeset"""
42 """return contexts for each parent changeset"""
43 p = self._repo.changelog.parents(self._node)
43 p = self._repo.changelog.parents(self._node)
44 return [ changectx(self._repo, x) for x in p ]
44 return [ changectx(self._repo, x) for x in p ]
45
45
46 def children(self):
46 def children(self):
47 """return contexts for each child changeset"""
47 """return contexts for each child changeset"""
48 c = self._repo.changelog.children(self._node)
48 c = self._repo.changelog.children(self._node)
49 return [ changectx(self._repo, x) for x in c ]
49 return [ changectx(self._repo, x) for x in c ]
50
50
51 def filenode(self, path):
51 def filenode(self, path):
52 node, flag = self._repo.manifest.find(self.changeset()[0], path)
52 node, flag = self._repo.manifest.find(self.changeset()[0], path)
53 return node
53 return node
54
54
55 def filectx(self, path, fileid=None):
55 def filectx(self, path, fileid=None):
56 """get a file context from this changeset"""
56 """get a file context from this changeset"""
57 if fileid is None:
57 if fileid is None:
58 fileid = self.filenode(path)
58 fileid = self.filenode(path)
59 return filectx(self._repo, path, fileid=fileid)
59 return filectx(self._repo, path, fileid=fileid)
60
60
61 def filectxs(self):
61 def filectxs(self):
62 """generate a file context for each file in this changeset's
62 """generate a file context for each file in this changeset's
63 manifest"""
63 manifest"""
64 mf = self.manifest()
64 mf = self.manifest()
65 m = mf.keys()
65 m = mf.keys()
66 m.sort()
66 m.sort()
67 for f in m:
67 for f in m:
68 yield self.filectx(f, fileid=mf[f])
68 yield self.filectx(f, fileid=mf[f])
69
69
70 class filectx(object):
70 class filectx(object):
71 """A filecontext object makes access to data related to a particular
71 """A filecontext object makes access to data related to a particular
72 filerevision convenient."""
72 filerevision convenient."""
73 def __init__(self, repo, path, changeid=None, fileid=None):
73 def __init__(self, repo, path, changeid=None, fileid=None):
74 """changeid can be a changeset revision, node, or tag.
74 """changeid can be a changeset revision, node, or tag.
75 fileid can be a file revision or node."""
75 fileid can be a file revision or node."""
76 self._repo = repo
76 self._repo = repo
77 self._path = path
77 self._path = path
78
78
79 assert changeid or fileid
79 assert changeid or fileid
80
80
81 if not fileid:
81 if not fileid:
82 # if given a changeset id, go ahead and look up the file
82 # if given a changeset id, go ahead and look up the file
83 self._changeid = changeid
83 self._changeid = changeid
84 self._changectx = self.changectx()
84 self._changectx = self.changectx()
85 self._filelog = self._repo.file(self._path)
85 self._filelog = self._repo.file(self._path)
86 self._filenode = self._changectx.filenode(self._path)
86 self._filenode = self._changectx.filenode(self._path)
87 else:
87 else:
88 # else be lazy
88 # else be lazy
89 self._filelog = self._repo.file(self._path)
89 self._filelog = self._repo.file(self._path)
90 self._filenode = self._filelog.lookup(fileid)
90 self._filenode = self._filelog.lookup(fileid)
91 self._changeid = self._filelog.linkrev(self._filenode)
91 self._changeid = self._filelog.linkrev(self._filenode)
92 self._filerev = self._filelog.rev(self._filenode)
92 self._filerev = self._filelog.rev(self._filenode)
93
93
94 def changectx(self):
94 def changectx(self):
95 try:
95 try:
96 return self._changectx
96 return self._changectx
97 except AttributeError:
97 except AttributeError:
98 self._changectx = changectx(self._repo, self._changeid)
98 self._changectx = changectx(self._repo, self._changeid)
99 return self._changectx
99 return self._changectx
100
100
101 def filerev(self): return self._filerev
101 def filerev(self): return self._filerev
102 def filenode(self): return self._filenode
102 def filenode(self): return self._filenode
103 def filelog(self): return self._filelog
103 def filelog(self): return self._filelog
104
104
105 def rev(self): return self.changectx().rev()
105 def rev(self): return self.changectx().rev()
106 def node(self): return self.changectx().node()
106 def node(self): return self.changectx().node()
107 def user(self): return self.changectx().user()
107 def user(self): return self.changectx().user()
108 def date(self): return self.changectx().date()
108 def date(self): return self.changectx().date()
109 def files(self): return self.changectx().files()
109 def files(self): return self.changectx().files()
110 def description(self): return self.changectx().description()
110 def description(self): return self.changectx().description()
111 def manifest(self): return self.changectx().manifest()
111 def manifest(self): return self.changectx().manifest()
112
112
113 def data(self): return self._filelog.read(self._filenode)
113 def data(self): return self._filelog.read(self._filenode)
114 def metadata(self): return self._filelog.readmeta(self._filenode)
115 def renamed(self): return self._filelog.renamed(self._filenode)
114 def renamed(self): return self._filelog.renamed(self._filenode)
116 def path(self): return self._path
115 def path(self): return self._path
117
116
118 def parents(self):
117 def parents(self):
119 p = [ (self._path, n) for n in self._filelog.parents(self._filenode) ]
118 p = [ (self._path, n) for n in self._filelog.parents(self._filenode) ]
120 r = self.renamed()
119 r = self.renamed()
120
121 if r:
121 if r:
122 p[0] = r
122 p[0] = r
123 return [ filectx(self._repo, p, fileid=n) for p,n in p if n != nullid ]
123 return [ filectx(self._repo, p, fileid=n) for p,n in p if n != nullid ]
124
124
125 def children(self):
125 def children(self):
126 # hard for renames
126 # hard for renames
127 c = self._filelog.children(self._filenode)
127 c = self._filelog.children(self._filenode)
128 return [ filectx(self._repo, self._path, fileid=x) for x in c ]
128 return [ filectx(self._repo, self._path, fileid=x) for x in c ]
129
129
130 def annotate(self):
130 def annotate(self):
131 return self._filelog.annotate(self._filenode)
131 return self._filelog.annotate(self._filenode)
@@ -1,155 +1,155 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(), "bdiff os")
10 demandload(globals(), "bdiff 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 size(self, rev):
69 """return the size of a given revision"""
69 """return the size 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 revlog.size(self, 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)
87
87
88 def annotate(self, node):
88 def annotate(self, node):
89
89
90 def decorate(text, rev):
90 def decorate(text, rev):
91 return ([rev] * len(text.splitlines()), text)
91 return ([rev] * len(text.splitlines()), text)
92
92
93 def pair(parent, child):
93 def pair(parent, child):
94 for a1, a2, b1, b2 in bdiff.blocks(parent[1], child[1]):
94 for a1, a2, b1, b2 in bdiff.blocks(parent[1], child[1]):
95 child[0][b1:b2] = parent[0][a1:a2]
95 child[0][b1:b2] = parent[0][a1:a2]
96 return child
96 return child
97
97
98 # find all ancestors
98 # find all ancestors
99 needed = {(self, node):1}
99 needed = {(self, node):1}
100 files = [self]
100 files = [self]
101 visit = [(self, node)]
101 visit = [(self, node)]
102 while visit:
102 while visit:
103 f, n = visit.pop(0)
103 f, n = visit.pop(0)
104 rn = f.renamed(n)
104 rn = f.renamed(n)
105 if rn:
105 if rn:
106 f, n = rn
106 f, n = rn
107 f = filelog(self.opener, f, self.defversion)
107 f = filelog(self.opener, f, self.defversion)
108 files.insert(0, f)
108 files.insert(0, f)
109 if (f, n) not in needed:
109 if (f, n) not in needed:
110 needed[(f, n)] = 1
110 needed[(f, n)] = 1
111 else:
111 else:
112 needed[(f, n)] += 1
112 needed[(f, n)] += 1
113 for p in f.parents(n):
113 for p in f.parents(n):
114 if p == nullid:
114 if p == nullid:
115 continue
115 continue
116 if (f, p) not in needed:
116 if (f, p) not in needed:
117 needed[(f, p)] = 1
117 needed[(f, p)] = 1
118 visit.append((f, p))
118 visit.append((f, p))
119 else:
119 else:
120 # count how many times we'll use this
120 # count how many times we'll use this
121 needed[(f, p)] += 1
121 needed[(f, p)] += 1
122
122
123 # sort by revision (per file) which is a topological order
123 # sort by revision (per file) which is a topological order
124 visit = []
124 visit = []
125 for f in files:
125 for f in files:
126 fn = [(f.rev(n[1]), f, n[1]) for n in needed.keys() if n[0] == f]
126 fn = [(f.rev(n[1]), f, n[1]) for n in needed.keys() if n[0] == f]
127 fn.sort()
127 fn.sort()
128 visit.extend(fn)
128 visit.extend(fn)
129 hist = {}
129 hist = {}
130
130
131 for i in range(len(visit)):
131 for i in range(len(visit)):
132 r, f, n = visit[i]
132 r, f, n = visit[i]
133 curr = decorate(f.read(n), f.linkrev(n))
133 curr = decorate(f.read(n), f.linkrev(n))
134 if r == -1:
134 if r == -1:
135 continue
135 continue
136 parents = f.parents(n)
136 parents = f.parents(n)
137 # follow parents across renames
137 # follow parents across renames
138 if r < 1 and i > 0:
138 if r < 1 and i > 0:
139 j = i
139 j = i
140 while j > 0 and visit[j][1] == f:
140 while j > 0 and visit[j][1] == f:
141 j -= 1
141 j -= 1
142 parents = (visit[j][2],)
142 parents = (visit[j][2],)
143 f = visit[j][1]
143 f = visit[j][1]
144 else:
144 else:
145 parents = f.parents(n)
145 parents = f.parents(n)
146 for p in parents:
146 for p in parents:
147 if p != nullid:
147 if p != nullid:
148 curr = pair(hist[p], curr)
148 curr = pair(hist[p], curr)
149 # trim the history of unneeded revs
149 # trim the history of unneeded revs
150 needed[(f, p)] -= 1
150 needed[(f, p)] -= 1
151 if not needed[(f, p)]:
151 if not needed[(f, p)]:
152 del hist[p]
152 del hist[p]
153 hist[n] = curr
153 hist[n] = curr
154
154
155 return zip(hist[n][0], hist[n][1].splitlines(1))
155 return zip(hist[n][0], hist[n][1].splitlines(1))
General Comments 0
You need to be logged in to leave comments. Login now