##// END OF EJS Templates
convert: p4 use absolute_import
timeless -
r28371:630f5f04 default
parent child Browse files
Show More
@@ -1,290 +1,296 b''
1 1 # Perforce source for convert extension.
2 2 #
3 3 # Copyright 2009, Frank Kingswood <frank@kingswood-consulting.co.uk>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 from __future__ import absolute_import
7 8
8 from mercurial import util, error
9 import marshal
10 import re
11
12 from mercurial import (
13 error,
14 util,
15 )
9 16 from mercurial.i18n import _
10 17
11 from common import commit, converter_source, checktool, NoRepo
12 import marshal
13 import re
18 from . import common
14 19
15 20 def loaditer(f):
16 21 "Yield the dictionary objects generated by p4"
17 22 try:
18 23 while True:
19 24 d = marshal.load(f)
20 25 if not d:
21 26 break
22 27 yield d
23 28 except EOFError:
24 29 pass
25 30
26 31 def decodefilename(filename):
27 32 """Perforce escapes special characters @, #, *, or %
28 33 with %40, %23, %2A, or %25 respectively
29 34
30 35 >>> decodefilename('portable-net45%252Bnetcore45%252Bwp8%252BMonoAndroid')
31 36 'portable-net45%2Bnetcore45%2Bwp8%2BMonoAndroid'
32 37 >>> decodefilename('//Depot/Directory/%2525/%2523/%23%40.%2A')
33 38 '//Depot/Directory/%25/%23/#@.*'
34 39 """
35 40 replacements = [('%2A', '*'), ('%23', '#'), ('%40', '@'), ('%25', '%')]
36 41 for k, v in replacements:
37 42 filename = filename.replace(k, v)
38 43 return filename
39 44
40 class p4_source(converter_source):
45 class p4_source(common.converter_source):
41 46 def __init__(self, ui, path, revs=None):
42 47 # avoid import cycle
43 import convcmd
48 from . import convcmd
44 49
45 50 super(p4_source, self).__init__(ui, path, revs=revs)
46 51
47 52 if "/" in path and not path.startswith('//'):
48 raise NoRepo(_('%s does not look like a P4 repository') % path)
53 raise common.NoRepo(_('%s does not look like a P4 repository') %
54 path)
49 55
50 checktool('p4', abort=False)
56 common.checktool('p4', abort=False)
51 57
52 58 self.p4changes = {}
53 59 self.heads = {}
54 60 self.changeset = {}
55 61 self.files = {}
56 62 self.copies = {}
57 63 self.tags = {}
58 64 self.lastbranch = {}
59 65 self.parent = {}
60 66 self.encoding = self.ui.config('convert', 'p4.encoding',
61 67 default=convcmd.orig_encoding)
62 68 self.depotname = {} # mapping from local name to depot name
63 69 self.localname = {} # mapping from depot name to local name
64 70 self.re_type = re.compile(
65 71 "([a-z]+)?(text|binary|symlink|apple|resource|unicode|utf\d+)"
66 72 "(\+\w+)?$")
67 73 self.re_keywords = re.compile(
68 74 r"\$(Id|Header|Date|DateTime|Change|File|Revision|Author)"
69 75 r":[^$\n]*\$")
70 76 self.re_keywords_old = re.compile("\$(Id|Header):[^$\n]*\$")
71 77
72 78 if revs and len(revs) > 1:
73 79 raise error.Abort(_("p4 source does not support specifying "
74 80 "multiple revisions"))
75 81 self._parse(ui, path)
76 82
77 83 def _parse_view(self, path):
78 84 "Read changes affecting the path"
79 85 cmd = 'p4 -G changes -s submitted %s' % util.shellquote(path)
80 86 stdout = util.popen(cmd, mode='rb')
81 87 for d in loaditer(stdout):
82 88 c = d.get("change", None)
83 89 if c:
84 90 self.p4changes[c] = True
85 91
86 92 def _parse(self, ui, path):
87 93 "Prepare list of P4 filenames and revisions to import"
88 94 ui.status(_('reading p4 views\n'))
89 95
90 96 # read client spec or view
91 97 if "/" in path:
92 98 self._parse_view(path)
93 99 if path.startswith("//") and path.endswith("/..."):
94 100 views = {path[:-3]:""}
95 101 else:
96 102 views = {"//": ""}
97 103 else:
98 104 cmd = 'p4 -G client -o %s' % util.shellquote(path)
99 105 clientspec = marshal.load(util.popen(cmd, mode='rb'))
100 106
101 107 views = {}
102 108 for client in clientspec:
103 109 if client.startswith("View"):
104 110 sview, cview = clientspec[client].split()
105 111 self._parse_view(sview)
106 112 if sview.endswith("...") and cview.endswith("..."):
107 113 sview = sview[:-3]
108 114 cview = cview[:-3]
109 115 cview = cview[2:]
110 116 cview = cview[cview.find("/") + 1:]
111 117 views[sview] = cview
112 118
113 119 # list of changes that affect our source files
114 120 self.p4changes = self.p4changes.keys()
115 121 self.p4changes.sort(key=int)
116 122
117 123 # list with depot pathnames, longest first
118 124 vieworder = views.keys()
119 125 vieworder.sort(key=len, reverse=True)
120 126
121 127 # handle revision limiting
122 128 startrev = self.ui.config('convert', 'p4.startrev', default=0)
123 129 self.p4changes = [x for x in self.p4changes
124 130 if ((not startrev or int(x) >= int(startrev)) and
125 131 (not self.revs or int(x) <= int(self.revs[0])))]
126 132
127 133 # now read the full changelists to get the list of file revisions
128 134 ui.status(_('collecting p4 changelists\n'))
129 135 lastid = None
130 136 for change in self.p4changes:
131 137 cmd = "p4 -G describe -s %s" % change
132 138 stdout = util.popen(cmd, mode='rb')
133 139 d = marshal.load(stdout)
134 140 desc = self.recode(d.get("desc", ""))
135 141 shortdesc = desc.split("\n", 1)[0]
136 142 t = '%s %s' % (d["change"], repr(shortdesc)[1:-1])
137 143 ui.status(util.ellipsis(t, 80) + '\n')
138 144
139 145 if lastid:
140 146 parents = [lastid]
141 147 else:
142 148 parents = []
143 149
144 150 date = (int(d["time"]), 0) # timezone not set
145 c = commit(author=self.recode(d["user"]),
146 date=util.datestr(date, '%Y-%m-%d %H:%M:%S %1%2'),
147 parents=parents, desc=desc, branch=None,
148 extra={"p4": change})
151 c = common.commit(author=self.recode(d["user"]),
152 date=util.datestr(date, '%Y-%m-%d %H:%M:%S %1%2'),
153 parents=parents, desc=desc, branch=None,
154 extra={"p4": change})
149 155
150 156 files = []
151 157 copies = {}
152 158 copiedfiles = []
153 159 i = 0
154 160 while ("depotFile%d" % i) in d and ("rev%d" % i) in d:
155 161 oldname = d["depotFile%d" % i]
156 162 filename = None
157 163 for v in vieworder:
158 164 if oldname.lower().startswith(v.lower()):
159 165 filename = decodefilename(views[v] + oldname[len(v):])
160 166 break
161 167 if filename:
162 168 files.append((filename, d["rev%d" % i]))
163 169 self.depotname[filename] = oldname
164 170 if (d.get("action%d" % i) == "move/add"):
165 171 copiedfiles.append(filename)
166 172 self.localname[oldname] = filename
167 173 i += 1
168 174
169 175 # Collect information about copied files
170 176 for filename in copiedfiles:
171 177 oldname = self.depotname[filename]
172 178
173 179 flcmd = 'p4 -G filelog %s' \
174 180 % util.shellquote(oldname)
175 181 flstdout = util.popen(flcmd, mode='rb')
176 182
177 183 copiedfilename = None
178 184 for d in loaditer(flstdout):
179 185 copiedoldname = None
180 186
181 187 i = 0
182 188 while ("change%d" % i) in d:
183 189 if (d["change%d" % i] == change and
184 190 d["action%d" % i] == "move/add"):
185 191 j = 0
186 192 while ("file%d,%d" % (i, j)) in d:
187 193 if d["how%d,%d" % (i, j)] == "moved from":
188 194 copiedoldname = d["file%d,%d" % (i, j)]
189 195 break
190 196 j += 1
191 197 i += 1
192 198
193 199 if copiedoldname and copiedoldname in self.localname:
194 200 copiedfilename = self.localname[copiedoldname]
195 201 break
196 202
197 203 if copiedfilename:
198 204 copies[filename] = copiedfilename
199 205 else:
200 206 ui.warn(_("cannot find source for copied file: %s@%s\n")
201 207 % (filename, change))
202 208
203 209 self.changeset[change] = c
204 210 self.files[change] = files
205 211 self.copies[change] = copies
206 212 lastid = change
207 213
208 214 if lastid:
209 215 self.heads = [lastid]
210 216
211 217 def getheads(self):
212 218 return self.heads
213 219
214 220 def getfile(self, name, rev):
215 221 cmd = 'p4 -G print %s' \
216 222 % util.shellquote("%s#%s" % (self.depotname[name], rev))
217 223
218 224 lasterror = None
219 225 while True:
220 226 stdout = util.popen(cmd, mode='rb')
221 227
222 228 mode = None
223 229 contents = []
224 230 keywords = None
225 231
226 232 for d in loaditer(stdout):
227 233 code = d["code"]
228 234 data = d.get("data")
229 235
230 236 if code == "error":
231 237 # if this is the first time error happened
232 238 # re-attempt getting the file
233 239 if not lasterror:
234 240 lasterror = IOError(d["generic"], data)
235 241 # this will exit inner-most for-loop
236 242 break
237 243 else:
238 244 raise lasterror
239 245
240 246 elif code == "stat":
241 247 action = d.get("action")
242 248 if action in ["purge", "delete", "move/delete"]:
243 249 return None, None
244 250 p4type = self.re_type.match(d["type"])
245 251 if p4type:
246 252 mode = ""
247 253 flags = ((p4type.group(1) or "")
248 254 + (p4type.group(3) or ""))
249 255 if "x" in flags:
250 256 mode = "x"
251 257 if p4type.group(2) == "symlink":
252 258 mode = "l"
253 259 if "ko" in flags:
254 260 keywords = self.re_keywords_old
255 261 elif "k" in flags:
256 262 keywords = self.re_keywords
257 263
258 264 elif code == "text" or code == "binary":
259 265 contents.append(data)
260 266
261 267 lasterror = None
262 268
263 269 if not lasterror:
264 270 break
265 271
266 272 if mode is None:
267 273 return None, None
268 274
269 275 contents = ''.join(contents)
270 276
271 277 if keywords:
272 278 contents = keywords.sub("$\\1$", contents)
273 279 if mode == "l" and contents.endswith("\n"):
274 280 contents = contents[:-1]
275 281
276 282 return contents, mode
277 283
278 284 def getchanges(self, rev, full):
279 285 if full:
280 286 raise error.Abort(_("convert from p4 does not support --full"))
281 287 return self.files[rev], self.copies[rev], set()
282 288
283 289 def getcommit(self, rev):
284 290 return self.changeset[rev]
285 291
286 292 def gettags(self):
287 293 return self.tags
288 294
289 295 def getchangedfiles(self, rev, i):
290 296 return sorted([x[0] for x in self.files[rev]])
@@ -1,152 +1,151 b''
1 1 #require test-repo
2 2
3 3 $ cd "$TESTDIR"/..
4 4
5 5 $ hg files 'set:(**.py)' | sed 's|\\|/|g' | xargs python contrib/check-py3-compat.py
6 6 contrib/check-code.py not using absolute_import
7 7 contrib/check-code.py requires print_function
8 8 contrib/debugshell.py not using absolute_import
9 9 contrib/hgfixes/fix_bytes.py not using absolute_import
10 10 contrib/hgfixes/fix_bytesmod.py not using absolute_import
11 11 contrib/hgfixes/fix_leftover_imports.py not using absolute_import
12 12 contrib/import-checker.py not using absolute_import
13 13 contrib/import-checker.py requires print_function
14 14 contrib/memory.py not using absolute_import
15 15 contrib/perf.py not using absolute_import
16 16 contrib/python-hook-examples.py not using absolute_import
17 17 contrib/revsetbenchmarks.py not using absolute_import
18 18 contrib/revsetbenchmarks.py requires print_function
19 19 contrib/showstack.py not using absolute_import
20 20 contrib/synthrepo.py not using absolute_import
21 21 contrib/win32/hgwebdir_wsgi.py not using absolute_import
22 22 doc/check-seclevel.py not using absolute_import
23 23 doc/gendoc.py not using absolute_import
24 24 doc/hgmanpage.py not using absolute_import
25 25 hgext/__init__.py not using absolute_import
26 26 hgext/color.py not using absolute_import
27 27 hgext/convert/__init__.py not using absolute_import
28 28 hgext/convert/bzr.py not using absolute_import
29 29 hgext/convert/common.py not using absolute_import
30 30 hgext/convert/convcmd.py not using absolute_import
31 31 hgext/convert/cvs.py not using absolute_import
32 32 hgext/convert/monotone.py not using absolute_import
33 hgext/convert/p4.py not using absolute_import
34 33 hgext/convert/subversion.py not using absolute_import
35 34 hgext/convert/transport.py not using absolute_import
36 35 hgext/eol.py not using absolute_import
37 36 hgext/extdiff.py not using absolute_import
38 37 hgext/factotum.py not using absolute_import
39 38 hgext/fetch.py not using absolute_import
40 39 hgext/gpg.py not using absolute_import
41 40 hgext/graphlog.py not using absolute_import
42 41 hgext/hgcia.py not using absolute_import
43 42 hgext/hgk.py not using absolute_import
44 43 hgext/highlight/__init__.py not using absolute_import
45 44 hgext/highlight/highlight.py not using absolute_import
46 45 hgext/histedit.py not using absolute_import
47 46 hgext/largefiles/__init__.py not using absolute_import
48 47 hgext/largefiles/basestore.py not using absolute_import
49 48 hgext/largefiles/lfcommands.py not using absolute_import
50 49 hgext/largefiles/lfutil.py not using absolute_import
51 50 hgext/largefiles/localstore.py not using absolute_import
52 51 hgext/largefiles/overrides.py not using absolute_import
53 52 hgext/largefiles/proto.py not using absolute_import
54 53 hgext/largefiles/remotestore.py not using absolute_import
55 54 hgext/largefiles/reposetup.py not using absolute_import
56 55 hgext/largefiles/uisetup.py not using absolute_import
57 56 hgext/largefiles/wirestore.py not using absolute_import
58 57 hgext/mq.py not using absolute_import
59 58 hgext/notify.py not using absolute_import
60 59 hgext/patchbomb.py not using absolute_import
61 60 hgext/purge.py not using absolute_import
62 61 hgext/rebase.py not using absolute_import
63 62 hgext/record.py not using absolute_import
64 63 hgext/relink.py not using absolute_import
65 64 hgext/schemes.py not using absolute_import
66 65 hgext/share.py not using absolute_import
67 66 hgext/shelve.py not using absolute_import
68 67 hgext/strip.py not using absolute_import
69 68 hgext/transplant.py not using absolute_import
70 69 hgext/win32mbcs.py not using absolute_import
71 70 hgext/win32text.py not using absolute_import
72 71 i18n/check-translation.py not using absolute_import
73 72 i18n/polib.py not using absolute_import
74 73 setup.py not using absolute_import
75 74 tests/filterpyflakes.py requires print_function
76 75 tests/generate-working-copy-states.py requires print_function
77 76 tests/get-with-headers.py requires print_function
78 77 tests/heredoctest.py requires print_function
79 78 tests/hypothesishelpers.py not using absolute_import
80 79 tests/hypothesishelpers.py requires print_function
81 80 tests/killdaemons.py not using absolute_import
82 81 tests/md5sum.py not using absolute_import
83 82 tests/mockblackbox.py not using absolute_import
84 83 tests/printenv.py not using absolute_import
85 84 tests/readlink.py not using absolute_import
86 85 tests/readlink.py requires print_function
87 86 tests/revlog-formatv0.py not using absolute_import
88 87 tests/run-tests.py not using absolute_import
89 88 tests/seq.py not using absolute_import
90 89 tests/seq.py requires print_function
91 90 tests/silenttestrunner.py not using absolute_import
92 91 tests/silenttestrunner.py requires print_function
93 92 tests/sitecustomize.py not using absolute_import
94 93 tests/svn-safe-append.py not using absolute_import
95 94 tests/svnxml.py not using absolute_import
96 95 tests/test-ancestor.py requires print_function
97 96 tests/test-atomictempfile.py not using absolute_import
98 97 tests/test-batching.py not using absolute_import
99 98 tests/test-batching.py requires print_function
100 99 tests/test-bdiff.py not using absolute_import
101 100 tests/test-bdiff.py requires print_function
102 101 tests/test-context.py not using absolute_import
103 102 tests/test-context.py requires print_function
104 103 tests/test-demandimport.py not using absolute_import
105 104 tests/test-demandimport.py requires print_function
106 105 tests/test-dispatch.py not using absolute_import
107 106 tests/test-dispatch.py requires print_function
108 107 tests/test-doctest.py not using absolute_import
109 108 tests/test-duplicateoptions.py not using absolute_import
110 109 tests/test-duplicateoptions.py requires print_function
111 110 tests/test-filecache.py not using absolute_import
112 111 tests/test-filecache.py requires print_function
113 112 tests/test-filelog.py not using absolute_import
114 113 tests/test-filelog.py requires print_function
115 114 tests/test-hg-parseurl.py not using absolute_import
116 115 tests/test-hg-parseurl.py requires print_function
117 116 tests/test-hgweb-auth.py not using absolute_import
118 117 tests/test-hgweb-auth.py requires print_function
119 118 tests/test-hgwebdir-paths.py not using absolute_import
120 119 tests/test-hybridencode.py not using absolute_import
121 120 tests/test-hybridencode.py requires print_function
122 121 tests/test-lrucachedict.py not using absolute_import
123 122 tests/test-lrucachedict.py requires print_function
124 123 tests/test-manifest.py not using absolute_import
125 124 tests/test-minirst.py not using absolute_import
126 125 tests/test-minirst.py requires print_function
127 126 tests/test-parseindex2.py not using absolute_import
128 127 tests/test-parseindex2.py requires print_function
129 128 tests/test-pathencode.py not using absolute_import
130 129 tests/test-pathencode.py requires print_function
131 130 tests/test-propertycache.py not using absolute_import
132 131 tests/test-propertycache.py requires print_function
133 132 tests/test-revlog-ancestry.py not using absolute_import
134 133 tests/test-revlog-ancestry.py requires print_function
135 134 tests/test-run-tests.py not using absolute_import
136 135 tests/test-simplemerge.py not using absolute_import
137 136 tests/test-status-inprocess.py not using absolute_import
138 137 tests/test-status-inprocess.py requires print_function
139 138 tests/test-symlink-os-yes-fs-no.py not using absolute_import
140 139 tests/test-trusted.py not using absolute_import
141 140 tests/test-trusted.py requires print_function
142 141 tests/test-ui-color.py not using absolute_import
143 142 tests/test-ui-color.py requires print_function
144 143 tests/test-ui-config.py not using absolute_import
145 144 tests/test-ui-config.py requires print_function
146 145 tests/test-ui-verbosity.py not using absolute_import
147 146 tests/test-ui-verbosity.py requires print_function
148 147 tests/test-url.py not using absolute_import
149 148 tests/test-url.py requires print_function
150 149 tests/test-walkrepo.py requires print_function
151 150 tests/test-wireproto.py requires print_function
152 151 tests/tinyproxy.py requires print_function
General Comments 0
You need to be logged in to leave comments. Login now