##// END OF EJS Templates
convert: fix marshalling in P4 convert extension to use a binary stream...
Peter Ingebretson -
r9474:6ea65327 default
parent child Browse files
Show More
@@ -1,205 +1,205 b''
1 1 #
2 2 # Perforce source for convert extension.
3 3 #
4 4 # Copyright 2009, Frank Kingswood <frank@kingswood-consulting.co.uk>
5 5 #
6 6 # This software may be used and distributed according to the terms of the
7 7 # GNU General Public License version 2, incorporated herein by reference.
8 8 #
9 9
10 10 from mercurial import util
11 11 from mercurial.i18n import _
12 12
13 13 from common import commit, converter_source, checktool, NoRepo
14 14 import marshal
15 15 import re
16 16
17 17 def loaditer(f):
18 18 "Yield the dictionary objects generated by p4"
19 19 try:
20 20 while True:
21 21 d = marshal.load(f)
22 22 if not d:
23 23 break
24 24 yield d
25 25 except EOFError:
26 26 pass
27 27
28 28 class p4_source(converter_source):
29 29 def __init__(self, ui, path, rev=None):
30 30 super(p4_source, self).__init__(ui, path, rev=rev)
31 31
32 32 if "/" in path and not path.startswith('//'):
33 33 raise NoRepo('%s does not look like a P4 repo' % path)
34 34
35 35 checktool('p4', abort=False)
36 36
37 37 self.p4changes = {}
38 38 self.heads = {}
39 39 self.changeset = {}
40 40 self.files = {}
41 41 self.tags = {}
42 42 self.lastbranch = {}
43 43 self.parent = {}
44 44 self.encoding = "latin_1"
45 45 self.depotname = {} # mapping from local name to depot name
46 46 self.modecache = {}
47 47 self.re_type = re.compile("([a-z]+)?(text|binary|symlink|apple|resource|unicode|utf\d+)(\+\w+)?$")
48 48 self.re_keywords = re.compile(r"\$(Id|Header|Date|DateTime|Change|File|Revision|Author):[^$\n]*\$")
49 49 self.re_keywords_old = re.compile("\$(Id|Header):[^$\n]*\$")
50 50
51 51 self._parse(ui, path)
52 52
53 53 def _parse_view(self, path):
54 54 "Read changes affecting the path"
55 55 cmd = 'p4 -G changes -s submitted "%s"' % path
56 stdout = util.popen(cmd)
56 stdout = util.popen(cmd, mode='rb')
57 57 for d in loaditer(stdout):
58 58 c = d.get("change", None)
59 59 if c:
60 60 self.p4changes[c] = True
61 61
62 62 def _parse(self, ui, path):
63 63 "Prepare list of P4 filenames and revisions to import"
64 64 ui.status(_('reading p4 views\n'))
65 65
66 66 # read client spec or view
67 67 if "/" in path:
68 68 self._parse_view(path)
69 69 if path.startswith("//") and path.endswith("/..."):
70 70 views = {path[:-3]:""}
71 71 else:
72 72 views = {"//": ""}
73 73 else:
74 74 cmd = 'p4 -G client -o "%s"' % path
75 clientspec = marshal.load(util.popen(cmd))
75 clientspec = marshal.load(util.popen(cmd, mode='rb'))
76 76
77 77 views = {}
78 78 for client in clientspec:
79 79 if client.startswith("View"):
80 80 sview, cview = clientspec[client].split()
81 81 self._parse_view(sview)
82 82 if sview.endswith("...") and cview.endswith("..."):
83 83 sview = sview[:-3]
84 84 cview = cview[:-3]
85 85 cview = cview[2:]
86 86 cview = cview[cview.find("/") + 1:]
87 87 views[sview] = cview
88 88
89 89 # list of changes that affect our source files
90 90 self.p4changes = self.p4changes.keys()
91 91 self.p4changes.sort(key=int)
92 92
93 93 # list with depot pathnames, longest first
94 94 vieworder = views.keys()
95 95 vieworder.sort(key=lambda x: -len(x))
96 96
97 97 # handle revision limiting
98 98 startrev = self.ui.config('convert', 'p4.startrev', default=0)
99 99 self.p4changes = [x for x in self.p4changes
100 100 if ((not startrev or int(x) >= int(startrev)) and
101 101 (not self.rev or int(x) <= int(self.rev)))]
102 102
103 103 # now read the full changelists to get the list of file revisions
104 104 ui.status(_('collecting p4 changelists\n'))
105 105 lastid = None
106 106 for change in self.p4changes:
107 107 cmd = "p4 -G describe %s" % change
108 stdout = util.popen(cmd)
108 stdout = util.popen(cmd, mode='rb')
109 109 d = marshal.load(stdout)
110 110
111 111 desc = self.recode(d["desc"])
112 112 shortdesc = desc.split("\n", 1)[0]
113 113 t = '%s %s' % (d["change"], repr(shortdesc)[1:-1])
114 114 ui.status(util.ellipsis(t, 80) + '\n')
115 115
116 116 if lastid:
117 117 parents = [lastid]
118 118 else:
119 119 parents = []
120 120
121 121 date = (int(d["time"]), 0) # timezone not set
122 122 c = commit(author=self.recode(d["user"]), date=util.datestr(date),
123 123 parents=parents, desc=desc, branch='', extra={"p4": change})
124 124
125 125 files = []
126 126 i = 0
127 127 while ("depotFile%d" % i) in d and ("rev%d" % i) in d:
128 128 oldname = d["depotFile%d" % i]
129 129 filename = None
130 130 for v in vieworder:
131 131 if oldname.startswith(v):
132 132 filename = views[v] + oldname[len(v):]
133 133 break
134 134 if filename:
135 135 files.append((filename, d["rev%d" % i]))
136 136 self.depotname[filename] = oldname
137 137 i += 1
138 138 self.changeset[change] = c
139 139 self.files[change] = files
140 140 lastid = change
141 141
142 142 if lastid:
143 143 self.heads = [lastid]
144 144
145 145 def getheads(self):
146 146 return self.heads
147 147
148 148 def getfile(self, name, rev):
149 149 cmd = 'p4 -G print "%s#%s"' % (self.depotname[name], rev)
150 stdout = util.popen(cmd)
150 stdout = util.popen(cmd, mode='rb')
151 151
152 152 mode = None
153 153 contents = ""
154 154 keywords = None
155 155
156 156 for d in loaditer(stdout):
157 157 code = d["code"]
158 158 data = d.get("data")
159 159
160 160 if code == "error":
161 161 raise IOError(d["generic"], data)
162 162
163 163 elif code == "stat":
164 164 p4type = self.re_type.match(d["type"])
165 165 if p4type:
166 166 mode = ""
167 167 flags = (p4type.group(1) or "") + (p4type.group(3) or "")
168 168 if "x" in flags:
169 169 mode = "x"
170 170 if p4type.group(2) == "symlink":
171 171 mode = "l"
172 172 if "ko" in flags:
173 173 keywords = self.re_keywords_old
174 174 elif "k" in flags:
175 175 keywords = self.re_keywords
176 176
177 177 elif code == "text" or code == "binary":
178 178 contents += data
179 179
180 180 if mode is None:
181 181 raise IOError(0, "bad stat")
182 182
183 183 self.modecache[(name, rev)] = mode
184 184
185 185 if keywords:
186 186 contents = keywords.sub("$\\1$", contents)
187 187 if mode == "l" and contents.endswith("\n"):
188 188 contents = contents[:-1]
189 189
190 190 return contents
191 191
192 192 def getmode(self, name, rev):
193 193 return self.modecache[(name, rev)]
194 194
195 195 def getchanges(self, rev):
196 196 return self.files[rev], {}
197 197
198 198 def getcommit(self, rev):
199 199 return self.changeset[rev]
200 200
201 201 def gettags(self):
202 202 return self.tags
203 203
204 204 def getchangedfiles(self, rev, i):
205 205 return sorted([x[0] for x in self.files[rev]])
General Comments 0
You need to be logged in to leave comments. Login now