##// END OF EJS Templates
convert: fix the handling of empty changlist descriptions in P4...
David Soria Parra -
r31590:78ac8acf default
parent child Browse files
Show More
@@ -1,368 +1,373 b''
1 # Perforce source for convert extension.
1 # Perforce source for convert extension.
2 #
2 #
3 # Copyright 2009, Frank Kingswood <frank@kingswood-consulting.co.uk>
3 # Copyright 2009, Frank Kingswood <frank@kingswood-consulting.co.uk>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7 from __future__ import absolute_import
7 from __future__ import absolute_import
8
8
9 import marshal
9 import marshal
10 import re
10 import re
11
11
12 from mercurial.i18n import _
12 from mercurial.i18n import _
13 from mercurial import (
13 from mercurial import (
14 error,
14 error,
15 util,
15 util,
16 )
16 )
17
17
18 from . import common
18 from . import common
19
19
20 def loaditer(f):
20 def loaditer(f):
21 "Yield the dictionary objects generated by p4"
21 "Yield the dictionary objects generated by p4"
22 try:
22 try:
23 while True:
23 while True:
24 d = marshal.load(f)
24 d = marshal.load(f)
25 if not d:
25 if not d:
26 break
26 break
27 yield d
27 yield d
28 except EOFError:
28 except EOFError:
29 pass
29 pass
30
30
31 def decodefilename(filename):
31 def decodefilename(filename):
32 """Perforce escapes special characters @, #, *, or %
32 """Perforce escapes special characters @, #, *, or %
33 with %40, %23, %2A, or %25 respectively
33 with %40, %23, %2A, or %25 respectively
34
34
35 >>> decodefilename('portable-net45%252Bnetcore45%252Bwp8%252BMonoAndroid')
35 >>> decodefilename('portable-net45%252Bnetcore45%252Bwp8%252BMonoAndroid')
36 'portable-net45%2Bnetcore45%2Bwp8%2BMonoAndroid'
36 'portable-net45%2Bnetcore45%2Bwp8%2BMonoAndroid'
37 >>> decodefilename('//Depot/Directory/%2525/%2523/%23%40.%2A')
37 >>> decodefilename('//Depot/Directory/%2525/%2523/%23%40.%2A')
38 '//Depot/Directory/%25/%23/#@.*'
38 '//Depot/Directory/%25/%23/#@.*'
39 """
39 """
40 replacements = [('%2A', '*'), ('%23', '#'), ('%40', '@'), ('%25', '%')]
40 replacements = [('%2A', '*'), ('%23', '#'), ('%40', '@'), ('%25', '%')]
41 for k, v in replacements:
41 for k, v in replacements:
42 filename = filename.replace(k, v)
42 filename = filename.replace(k, v)
43 return filename
43 return filename
44
44
45 class p4_source(common.converter_source):
45 class p4_source(common.converter_source):
46 def __init__(self, ui, path, revs=None):
46 def __init__(self, ui, path, revs=None):
47 # avoid import cycle
47 # avoid import cycle
48 from . import convcmd
48 from . import convcmd
49
49
50 super(p4_source, self).__init__(ui, path, revs=revs)
50 super(p4_source, self).__init__(ui, path, revs=revs)
51
51
52 if "/" in path and not path.startswith('//'):
52 if "/" in path and not path.startswith('//'):
53 raise common.NoRepo(_('%s does not look like a P4 repository') %
53 raise common.NoRepo(_('%s does not look like a P4 repository') %
54 path)
54 path)
55
55
56 common.checktool('p4', abort=False)
56 common.checktool('p4', abort=False)
57
57
58 self.revmap = {}
58 self.revmap = {}
59 self.encoding = self.ui.config('convert', 'p4.encoding',
59 self.encoding = self.ui.config('convert', 'p4.encoding',
60 default=convcmd.orig_encoding)
60 default=convcmd.orig_encoding)
61 self.re_type = re.compile(
61 self.re_type = re.compile(
62 "([a-z]+)?(text|binary|symlink|apple|resource|unicode|utf\d+)"
62 "([a-z]+)?(text|binary|symlink|apple|resource|unicode|utf\d+)"
63 "(\+\w+)?$")
63 "(\+\w+)?$")
64 self.re_keywords = re.compile(
64 self.re_keywords = re.compile(
65 r"\$(Id|Header|Date|DateTime|Change|File|Revision|Author)"
65 r"\$(Id|Header|Date|DateTime|Change|File|Revision|Author)"
66 r":[^$\n]*\$")
66 r":[^$\n]*\$")
67 self.re_keywords_old = re.compile("\$(Id|Header):[^$\n]*\$")
67 self.re_keywords_old = re.compile("\$(Id|Header):[^$\n]*\$")
68
68
69 if revs and len(revs) > 1:
69 if revs and len(revs) > 1:
70 raise error.Abort(_("p4 source does not support specifying "
70 raise error.Abort(_("p4 source does not support specifying "
71 "multiple revisions"))
71 "multiple revisions"))
72
72
73 def setrevmap(self, revmap):
73 def setrevmap(self, revmap):
74 """Sets the parsed revmap dictionary.
74 """Sets the parsed revmap dictionary.
75
75
76 Revmap stores mappings from a source revision to a target revision.
76 Revmap stores mappings from a source revision to a target revision.
77 It is set in convertcmd.convert and provided by the user as a file
77 It is set in convertcmd.convert and provided by the user as a file
78 on the commandline.
78 on the commandline.
79
79
80 Revisions in the map are considered beeing present in the
80 Revisions in the map are considered beeing present in the
81 repository and ignored during _parse(). This allows for incremental
81 repository and ignored during _parse(). This allows for incremental
82 imports if a revmap is provided.
82 imports if a revmap is provided.
83 """
83 """
84 self.revmap = revmap
84 self.revmap = revmap
85
85
86 def _parse_view(self, path):
86 def _parse_view(self, path):
87 "Read changes affecting the path"
87 "Read changes affecting the path"
88 cmd = 'p4 -G changes -s submitted %s' % util.shellquote(path)
88 cmd = 'p4 -G changes -s submitted %s' % util.shellquote(path)
89 stdout = util.popen(cmd, mode='rb')
89 stdout = util.popen(cmd, mode='rb')
90 p4changes = {}
90 p4changes = {}
91 for d in loaditer(stdout):
91 for d in loaditer(stdout):
92 c = d.get("change", None)
92 c = d.get("change", None)
93 if c:
93 if c:
94 p4changes[c] = True
94 p4changes[c] = True
95 return p4changes
95 return p4changes
96
96
97 def _parse(self, ui, path):
97 def _parse(self, ui, path):
98 "Prepare list of P4 filenames and revisions to import"
98 "Prepare list of P4 filenames and revisions to import"
99 p4changes = {}
99 p4changes = {}
100 changeset = {}
100 changeset = {}
101 files_map = {}
101 files_map = {}
102 copies_map = {}
102 copies_map = {}
103 localname = {}
103 localname = {}
104 depotname = {}
104 depotname = {}
105 heads = []
105 heads = []
106
106
107 ui.status(_('reading p4 views\n'))
107 ui.status(_('reading p4 views\n'))
108
108
109 # read client spec or view
109 # read client spec or view
110 if "/" in path:
110 if "/" in path:
111 p4changes.update(self._parse_view(path))
111 p4changes.update(self._parse_view(path))
112 if path.startswith("//") and path.endswith("/..."):
112 if path.startswith("//") and path.endswith("/..."):
113 views = {path[:-3]:""}
113 views = {path[:-3]:""}
114 else:
114 else:
115 views = {"//": ""}
115 views = {"//": ""}
116 else:
116 else:
117 cmd = 'p4 -G client -o %s' % util.shellquote(path)
117 cmd = 'p4 -G client -o %s' % util.shellquote(path)
118 clientspec = marshal.load(util.popen(cmd, mode='rb'))
118 clientspec = marshal.load(util.popen(cmd, mode='rb'))
119
119
120 views = {}
120 views = {}
121 for client in clientspec:
121 for client in clientspec:
122 if client.startswith("View"):
122 if client.startswith("View"):
123 sview, cview = clientspec[client].split()
123 sview, cview = clientspec[client].split()
124 p4changes.update(self._parse_view(sview))
124 p4changes.update(self._parse_view(sview))
125 if sview.endswith("...") and cview.endswith("..."):
125 if sview.endswith("...") and cview.endswith("..."):
126 sview = sview[:-3]
126 sview = sview[:-3]
127 cview = cview[:-3]
127 cview = cview[:-3]
128 cview = cview[2:]
128 cview = cview[2:]
129 cview = cview[cview.find("/") + 1:]
129 cview = cview[cview.find("/") + 1:]
130 views[sview] = cview
130 views[sview] = cview
131
131
132 # list of changes that affect our source files
132 # list of changes that affect our source files
133 p4changes = p4changes.keys()
133 p4changes = p4changes.keys()
134 p4changes.sort(key=int)
134 p4changes.sort(key=int)
135
135
136 # list with depot pathnames, longest first
136 # list with depot pathnames, longest first
137 vieworder = views.keys()
137 vieworder = views.keys()
138 vieworder.sort(key=len, reverse=True)
138 vieworder.sort(key=len, reverse=True)
139
139
140 # handle revision limiting
140 # handle revision limiting
141 startrev = self.ui.config('convert', 'p4.startrev', default=0)
141 startrev = self.ui.config('convert', 'p4.startrev', default=0)
142
142
143 # now read the full changelists to get the list of file revisions
143 # now read the full changelists to get the list of file revisions
144 ui.status(_('collecting p4 changelists\n'))
144 ui.status(_('collecting p4 changelists\n'))
145 lastid = None
145 lastid = None
146 for change in p4changes:
146 for change in p4changes:
147 if startrev and int(change) < int(startrev):
147 if startrev and int(change) < int(startrev):
148 continue
148 continue
149 if self.revs and int(change) > int(self.revs[0]):
149 if self.revs and int(change) > int(self.revs[0]):
150 continue
150 continue
151 if change in self.revmap:
151 if change in self.revmap:
152 # Ignore already present revisions, but set the parent pointer.
152 # Ignore already present revisions, but set the parent pointer.
153 lastid = change
153 lastid = change
154 continue
154 continue
155
155
156 if lastid:
156 if lastid:
157 parents = [lastid]
157 parents = [lastid]
158 else:
158 else:
159 parents = []
159 parents = []
160
160
161 d = self._fetch_revision(change)
161 d = self._fetch_revision(change)
162 c = self._construct_commit(d, parents)
162 c = self._construct_commit(d, parents)
163
163
164 shortdesc = c.desc.splitlines(True)[0].rstrip('\r\n')
164 descarr = c.desc.splitlines(True)
165 if len(descarr) > 0:
166 shortdesc = descarr[0].rstrip('\r\n')
167 else:
168 shortdesc = '**empty changelist description**'
169
165 t = '%s %s' % (c.rev, repr(shortdesc)[1:-1])
170 t = '%s %s' % (c.rev, repr(shortdesc)[1:-1])
166 ui.status(util.ellipsis(t, 80) + '\n')
171 ui.status(util.ellipsis(t, 80) + '\n')
167
172
168 files = []
173 files = []
169 copies = {}
174 copies = {}
170 copiedfiles = []
175 copiedfiles = []
171 i = 0
176 i = 0
172 while ("depotFile%d" % i) in d and ("rev%d" % i) in d:
177 while ("depotFile%d" % i) in d and ("rev%d" % i) in d:
173 oldname = d["depotFile%d" % i]
178 oldname = d["depotFile%d" % i]
174 filename = None
179 filename = None
175 for v in vieworder:
180 for v in vieworder:
176 if oldname.lower().startswith(v.lower()):
181 if oldname.lower().startswith(v.lower()):
177 filename = decodefilename(views[v] + oldname[len(v):])
182 filename = decodefilename(views[v] + oldname[len(v):])
178 break
183 break
179 if filename:
184 if filename:
180 files.append((filename, d["rev%d" % i]))
185 files.append((filename, d["rev%d" % i]))
181 depotname[filename] = oldname
186 depotname[filename] = oldname
182 if (d.get("action%d" % i) == "move/add"):
187 if (d.get("action%d" % i) == "move/add"):
183 copiedfiles.append(filename)
188 copiedfiles.append(filename)
184 localname[oldname] = filename
189 localname[oldname] = filename
185 i += 1
190 i += 1
186
191
187 # Collect information about copied files
192 # Collect information about copied files
188 for filename in copiedfiles:
193 for filename in copiedfiles:
189 oldname = depotname[filename]
194 oldname = depotname[filename]
190
195
191 flcmd = 'p4 -G filelog %s' \
196 flcmd = 'p4 -G filelog %s' \
192 % util.shellquote(oldname)
197 % util.shellquote(oldname)
193 flstdout = util.popen(flcmd, mode='rb')
198 flstdout = util.popen(flcmd, mode='rb')
194
199
195 copiedfilename = None
200 copiedfilename = None
196 for d in loaditer(flstdout):
201 for d in loaditer(flstdout):
197 copiedoldname = None
202 copiedoldname = None
198
203
199 i = 0
204 i = 0
200 while ("change%d" % i) in d:
205 while ("change%d" % i) in d:
201 if (d["change%d" % i] == change and
206 if (d["change%d" % i] == change and
202 d["action%d" % i] == "move/add"):
207 d["action%d" % i] == "move/add"):
203 j = 0
208 j = 0
204 while ("file%d,%d" % (i, j)) in d:
209 while ("file%d,%d" % (i, j)) in d:
205 if d["how%d,%d" % (i, j)] == "moved from":
210 if d["how%d,%d" % (i, j)] == "moved from":
206 copiedoldname = d["file%d,%d" % (i, j)]
211 copiedoldname = d["file%d,%d" % (i, j)]
207 break
212 break
208 j += 1
213 j += 1
209 i += 1
214 i += 1
210
215
211 if copiedoldname and copiedoldname in localname:
216 if copiedoldname and copiedoldname in localname:
212 copiedfilename = localname[copiedoldname]
217 copiedfilename = localname[copiedoldname]
213 break
218 break
214
219
215 if copiedfilename:
220 if copiedfilename:
216 copies[filename] = copiedfilename
221 copies[filename] = copiedfilename
217 else:
222 else:
218 ui.warn(_("cannot find source for copied file: %s@%s\n")
223 ui.warn(_("cannot find source for copied file: %s@%s\n")
219 % (filename, change))
224 % (filename, change))
220
225
221 changeset[change] = c
226 changeset[change] = c
222 files_map[change] = files
227 files_map[change] = files
223 copies_map[change] = copies
228 copies_map[change] = copies
224 lastid = change
229 lastid = change
225
230
226 if lastid and len(changeset) > 0:
231 if lastid and len(changeset) > 0:
227 heads = [lastid]
232 heads = [lastid]
228
233
229 return {
234 return {
230 'changeset': changeset,
235 'changeset': changeset,
231 'files': files_map,
236 'files': files_map,
232 'copies': copies_map,
237 'copies': copies_map,
233 'heads': heads,
238 'heads': heads,
234 'depotname': depotname,
239 'depotname': depotname,
235 }
240 }
236
241
237 @util.propertycache
242 @util.propertycache
238 def _parse_once(self):
243 def _parse_once(self):
239 return self._parse(self.ui, self.path)
244 return self._parse(self.ui, self.path)
240
245
241 @util.propertycache
246 @util.propertycache
242 def copies(self):
247 def copies(self):
243 return self._parse_once['copies']
248 return self._parse_once['copies']
244
249
245 @util.propertycache
250 @util.propertycache
246 def files(self):
251 def files(self):
247 return self._parse_once['files']
252 return self._parse_once['files']
248
253
249 @util.propertycache
254 @util.propertycache
250 def changeset(self):
255 def changeset(self):
251 return self._parse_once['changeset']
256 return self._parse_once['changeset']
252
257
253 @util.propertycache
258 @util.propertycache
254 def heads(self):
259 def heads(self):
255 return self._parse_once['heads']
260 return self._parse_once['heads']
256
261
257 @util.propertycache
262 @util.propertycache
258 def depotname(self):
263 def depotname(self):
259 return self._parse_once['depotname']
264 return self._parse_once['depotname']
260
265
261 def getheads(self):
266 def getheads(self):
262 return self.heads
267 return self.heads
263
268
264 def getfile(self, name, rev):
269 def getfile(self, name, rev):
265 cmd = 'p4 -G print %s' \
270 cmd = 'p4 -G print %s' \
266 % util.shellquote("%s#%s" % (self.depotname[name], rev))
271 % util.shellquote("%s#%s" % (self.depotname[name], rev))
267
272
268 lasterror = None
273 lasterror = None
269 while True:
274 while True:
270 stdout = util.popen(cmd, mode='rb')
275 stdout = util.popen(cmd, mode='rb')
271
276
272 mode = None
277 mode = None
273 contents = []
278 contents = []
274 keywords = None
279 keywords = None
275
280
276 for d in loaditer(stdout):
281 for d in loaditer(stdout):
277 code = d["code"]
282 code = d["code"]
278 data = d.get("data")
283 data = d.get("data")
279
284
280 if code == "error":
285 if code == "error":
281 # if this is the first time error happened
286 # if this is the first time error happened
282 # re-attempt getting the file
287 # re-attempt getting the file
283 if not lasterror:
288 if not lasterror:
284 lasterror = IOError(d["generic"], data)
289 lasterror = IOError(d["generic"], data)
285 # this will exit inner-most for-loop
290 # this will exit inner-most for-loop
286 break
291 break
287 else:
292 else:
288 raise lasterror
293 raise lasterror
289
294
290 elif code == "stat":
295 elif code == "stat":
291 action = d.get("action")
296 action = d.get("action")
292 if action in ["purge", "delete", "move/delete"]:
297 if action in ["purge", "delete", "move/delete"]:
293 return None, None
298 return None, None
294 p4type = self.re_type.match(d["type"])
299 p4type = self.re_type.match(d["type"])
295 if p4type:
300 if p4type:
296 mode = ""
301 mode = ""
297 flags = ((p4type.group(1) or "")
302 flags = ((p4type.group(1) or "")
298 + (p4type.group(3) or ""))
303 + (p4type.group(3) or ""))
299 if "x" in flags:
304 if "x" in flags:
300 mode = "x"
305 mode = "x"
301 if p4type.group(2) == "symlink":
306 if p4type.group(2) == "symlink":
302 mode = "l"
307 mode = "l"
303 if "ko" in flags:
308 if "ko" in flags:
304 keywords = self.re_keywords_old
309 keywords = self.re_keywords_old
305 elif "k" in flags:
310 elif "k" in flags:
306 keywords = self.re_keywords
311 keywords = self.re_keywords
307
312
308 elif code == "text" or code == "binary":
313 elif code == "text" or code == "binary":
309 contents.append(data)
314 contents.append(data)
310
315
311 lasterror = None
316 lasterror = None
312
317
313 if not lasterror:
318 if not lasterror:
314 break
319 break
315
320
316 if mode is None:
321 if mode is None:
317 return None, None
322 return None, None
318
323
319 contents = ''.join(contents)
324 contents = ''.join(contents)
320
325
321 if keywords:
326 if keywords:
322 contents = keywords.sub("$\\1$", contents)
327 contents = keywords.sub("$\\1$", contents)
323 if mode == "l" and contents.endswith("\n"):
328 if mode == "l" and contents.endswith("\n"):
324 contents = contents[:-1]
329 contents = contents[:-1]
325
330
326 return contents, mode
331 return contents, mode
327
332
328 def getchanges(self, rev, full):
333 def getchanges(self, rev, full):
329 if full:
334 if full:
330 raise error.Abort(_("convert from p4 does not support --full"))
335 raise error.Abort(_("convert from p4 does not support --full"))
331 return self.files[rev], self.copies[rev], set()
336 return self.files[rev], self.copies[rev], set()
332
337
333 def _construct_commit(self, obj, parents=None):
338 def _construct_commit(self, obj, parents=None):
334 """
339 """
335 Constructs a common.commit object from an unmarshalled
340 Constructs a common.commit object from an unmarshalled
336 `p4 describe` output
341 `p4 describe` output
337 """
342 """
338 desc = self.recode(obj.get("desc", ""))
343 desc = self.recode(obj.get("desc", ""))
339 date = (int(obj["time"]), 0) # timezone not set
344 date = (int(obj["time"]), 0) # timezone not set
340 if parents is None:
345 if parents is None:
341 parents = []
346 parents = []
342
347
343 return common.commit(author=self.recode(obj["user"]),
348 return common.commit(author=self.recode(obj["user"]),
344 date=util.datestr(date, '%Y-%m-%d %H:%M:%S %1%2'),
349 date=util.datestr(date, '%Y-%m-%d %H:%M:%S %1%2'),
345 parents=parents, desc=desc, branch=None, rev=obj['change'],
350 parents=parents, desc=desc, branch=None, rev=obj['change'],
346 extra={"p4": obj['change'], "convert_revision": obj['change']})
351 extra={"p4": obj['change'], "convert_revision": obj['change']})
347
352
348 def _fetch_revision(self, rev):
353 def _fetch_revision(self, rev):
349 """Return an output of `p4 describe` including author, commit date as
354 """Return an output of `p4 describe` including author, commit date as
350 a dictionary."""
355 a dictionary."""
351 cmd = "p4 -G describe -s %s" % rev
356 cmd = "p4 -G describe -s %s" % rev
352 stdout = util.popen(cmd, mode='rb')
357 stdout = util.popen(cmd, mode='rb')
353 return marshal.load(stdout)
358 return marshal.load(stdout)
354
359
355 def getcommit(self, rev):
360 def getcommit(self, rev):
356 if rev in self.changeset:
361 if rev in self.changeset:
357 return self.changeset[rev]
362 return self.changeset[rev]
358 elif rev in self.revmap:
363 elif rev in self.revmap:
359 d = self._fetch_revision(rev)
364 d = self._fetch_revision(rev)
360 return self._construct_commit(d, parents=None)
365 return self._construct_commit(d, parents=None)
361 raise error.Abort(
366 raise error.Abort(
362 _("cannot find %s in the revmap or parsed changesets") % rev)
367 _("cannot find %s in the revmap or parsed changesets") % rev)
363
368
364 def gettags(self):
369 def gettags(self):
365 return {}
370 return {}
366
371
367 def getchangedfiles(self, rev, i):
372 def getchangedfiles(self, rev, i):
368 return sorted([x[0] for x in self.files[rev]])
373 return sorted([x[0] for x in self.files[rev]])
@@ -1,145 +1,163 b''
1 #require p4
1 #require p4
2
2
3 $ echo "[extensions]" >> $HGRCPATH
3 $ echo "[extensions]" >> $HGRCPATH
4 $ echo "convert = " >> $HGRCPATH
4 $ echo "convert = " >> $HGRCPATH
5
5
6 create p4 depot
6 create p4 depot
7 $ P4ROOT=`pwd`/depot; export P4ROOT
7 $ P4ROOT=`pwd`/depot; export P4ROOT
8 $ P4AUDIT=$P4ROOT/audit; export P4AUDIT
8 $ P4AUDIT=$P4ROOT/audit; export P4AUDIT
9 $ P4JOURNAL=$P4ROOT/journal; export P4JOURNAL
9 $ P4JOURNAL=$P4ROOT/journal; export P4JOURNAL
10 $ P4LOG=$P4ROOT/log; export P4LOG
10 $ P4LOG=$P4ROOT/log; export P4LOG
11 $ P4PORT=localhost:$HGPORT; export P4PORT
11 $ P4PORT=localhost:$HGPORT; export P4PORT
12 $ P4DEBUG=1; export P4DEBUG
12 $ P4DEBUG=1; export P4DEBUG
13
13
14 start the p4 server
14 start the p4 server
15 $ [ ! -d $P4ROOT ] && mkdir $P4ROOT
15 $ [ ! -d $P4ROOT ] && mkdir $P4ROOT
16 $ p4d -f -J off >$P4ROOT/stdout 2>$P4ROOT/stderr &
16 $ p4d -f -J off >$P4ROOT/stdout 2>$P4ROOT/stderr &
17 $ echo $! >> $DAEMON_PIDS
17 $ echo $! >> $DAEMON_PIDS
18 $ trap "echo stopping the p4 server ; p4 admin stop" EXIT
18 $ trap "echo stopping the p4 server ; p4 admin stop" EXIT
19
19
20 $ # wait for the server to initialize
20 $ # wait for the server to initialize
21 $ while ! p4 ; do
21 $ while ! p4 ; do
22 > sleep 1
22 > sleep 1
23 > done >/dev/null 2>/dev/null
23 > done >/dev/null 2>/dev/null
24
24
25 create a client spec
25 create a client spec
26 $ P4CLIENT=hg-p4-import; export P4CLIENT
26 $ P4CLIENT=hg-p4-import; export P4CLIENT
27 $ DEPOTPATH=//depot/test-mercurial-import/...
27 $ DEPOTPATH=//depot/test-mercurial-import/...
28 $ p4 client -o | sed '/^View:/,$ d' >p4client
28 $ p4 client -o | sed '/^View:/,$ d' >p4client
29 $ echo View: >>p4client
29 $ echo View: >>p4client
30 $ echo " $DEPOTPATH //$P4CLIENT/..." >>p4client
30 $ echo " $DEPOTPATH //$P4CLIENT/..." >>p4client
31 $ p4 client -i <p4client
31 $ p4 client -i <p4client
32 Client hg-p4-import saved.
32 Client hg-p4-import saved.
33
33
34 populate the depot
34 populate the depot
35 $ echo a > a
35 $ echo a > a
36 $ mkdir b
36 $ mkdir b
37 $ echo c > b/c
37 $ echo c > b/c
38 $ p4 add a b/c
38 $ p4 add a b/c
39 //depot/test-mercurial-import/a#1 - opened for add
39 //depot/test-mercurial-import/a#1 - opened for add
40 //depot/test-mercurial-import/b/c#1 - opened for add
40 //depot/test-mercurial-import/b/c#1 - opened for add
41 $ p4 submit -d initial
41 $ p4 submit -d initial
42 Submitting change 1.
42 Submitting change 1.
43 Locking 2 files ...
43 Locking 2 files ...
44 add //depot/test-mercurial-import/a#1
44 add //depot/test-mercurial-import/a#1
45 add //depot/test-mercurial-import/b/c#1
45 add //depot/test-mercurial-import/b/c#1
46 Change 1 submitted.
46 Change 1 submitted.
47
47
48 change some files
48 change some files
49 $ p4 edit a
49 $ p4 edit a
50 //depot/test-mercurial-import/a#1 - opened for edit
50 //depot/test-mercurial-import/a#1 - opened for edit
51 $ echo aa >> a
51 $ echo aa >> a
52 $ p4 submit -d "change a"
52 $ p4 submit -d "change a"
53 Submitting change 2.
53 Submitting change 2.
54 Locking 1 files ...
54 Locking 1 files ...
55 edit //depot/test-mercurial-import/a#2
55 edit //depot/test-mercurial-import/a#2
56 Change 2 submitted.
56 Change 2 submitted.
57
57
58 $ p4 edit b/c
58 $ p4 edit b/c
59 //depot/test-mercurial-import/b/c#1 - opened for edit
59 //depot/test-mercurial-import/b/c#1 - opened for edit
60 $ echo cc >> b/c
60 $ echo cc >> b/c
61 $ p4 submit -d "change b/c"
61 $ p4 submit -d "change b/c"
62 Submitting change 3.
62 Submitting change 3.
63 Locking 1 files ...
63 Locking 1 files ...
64 edit //depot/test-mercurial-import/b/c#2
64 edit //depot/test-mercurial-import/b/c#2
65 Change 3 submitted.
65 Change 3 submitted.
66
66
67 convert
67 convert
68 $ hg convert -s p4 $DEPOTPATH dst
68 $ hg convert -s p4 $DEPOTPATH dst
69 initializing destination dst repository
69 initializing destination dst repository
70 scanning source...
70 scanning source...
71 reading p4 views
71 reading p4 views
72 collecting p4 changelists
72 collecting p4 changelists
73 1 initial
73 1 initial
74 2 change a
74 2 change a
75 3 change b/c
75 3 change b/c
76 sorting...
76 sorting...
77 converting...
77 converting...
78 2 initial
78 2 initial
79 1 change a
79 1 change a
80 0 change b/c
80 0 change b/c
81 $ hg -R dst log --template 'rev={rev} desc="{desc}" tags="{tags}" files="{files}"\n'
81 $ hg -R dst log --template 'rev={rev} desc="{desc}" tags="{tags}" files="{files}"\n'
82 rev=2 desc="change b/c" tags="tip" files="b/c"
82 rev=2 desc="change b/c" tags="tip" files="b/c"
83 rev=1 desc="change a" tags="" files="a"
83 rev=1 desc="change a" tags="" files="a"
84 rev=0 desc="initial" tags="" files="a b/c"
84 rev=0 desc="initial" tags="" files="a b/c"
85
85
86 change some files
86 change some files
87 $ p4 edit a b/c
87 $ p4 edit a b/c
88 //depot/test-mercurial-import/a#2 - opened for edit
88 //depot/test-mercurial-import/a#2 - opened for edit
89 //depot/test-mercurial-import/b/c#2 - opened for edit
89 //depot/test-mercurial-import/b/c#2 - opened for edit
90 $ echo aaa >> a
90 $ echo aaa >> a
91 $ echo ccc >> b/c
91 $ echo ccc >> b/c
92 $ p4 submit -d "change a b/c"
92 $ p4 submit -d "change a b/c"
93 Submitting change 4.
93 Submitting change 4.
94 Locking 2 files ...
94 Locking 2 files ...
95 edit //depot/test-mercurial-import/a#3
95 edit //depot/test-mercurial-import/a#3
96 edit //depot/test-mercurial-import/b/c#3
96 edit //depot/test-mercurial-import/b/c#3
97 Change 4 submitted.
97 Change 4 submitted.
98
98
99 convert again
99 convert again
100 $ hg convert -s p4 $DEPOTPATH dst
100 $ hg convert -s p4 $DEPOTPATH dst
101 scanning source...
101 scanning source...
102 reading p4 views
102 reading p4 views
103 collecting p4 changelists
103 collecting p4 changelists
104 4 change a b/c
104 4 change a b/c
105 sorting...
105 sorting...
106 converting...
106 converting...
107 0 change a b/c
107 0 change a b/c
108 $ hg -R dst log --template 'rev={rev} desc="{desc}" tags="{tags}" files="{files}"\n'
108 $ hg -R dst log --template 'rev={rev} desc="{desc}" tags="{tags}" files="{files}"\n'
109 rev=3 desc="change a b/c" tags="tip" files="a b/c"
109 rev=3 desc="change a b/c" tags="tip" files="a b/c"
110 rev=2 desc="change b/c" tags="" files="b/c"
110 rev=2 desc="change b/c" tags="" files="b/c"
111 rev=1 desc="change a" tags="" files="a"
111 rev=1 desc="change a" tags="" files="a"
112 rev=0 desc="initial" tags="" files="a b/c"
112 rev=0 desc="initial" tags="" files="a b/c"
113
113
114 interesting names
114 interesting names
115 $ echo dddd > "d d"
115 $ echo dddd > "d d"
116 $ mkdir " e"
116 $ mkdir " e"
117 $ echo fff >" e/ f"
117 $ echo fff >" e/ f"
118 $ p4 add "d d" " e/ f"
118 $ p4 add "d d" " e/ f"
119 //depot/test-mercurial-import/d d#1 - opened for add
119 //depot/test-mercurial-import/d d#1 - opened for add
120 //depot/test-mercurial-import/ e/ f#1 - opened for add
120 //depot/test-mercurial-import/ e/ f#1 - opened for add
121 $ p4 submit -d "add d e f"
121 $ p4 submit -d "add d e f"
122 Submitting change 5.
122 Submitting change 5.
123 Locking 2 files ...
123 Locking 2 files ...
124 add //depot/test-mercurial-import/ e/ f#1
124 add //depot/test-mercurial-import/ e/ f#1
125 add //depot/test-mercurial-import/d d#1
125 add //depot/test-mercurial-import/d d#1
126 Change 5 submitted.
126 Change 5 submitted.
127
127
128 convert again
128 convert again
129 $ hg convert -s p4 $DEPOTPATH dst
129 $ hg convert -s p4 $DEPOTPATH dst
130 scanning source...
130 scanning source...
131 reading p4 views
131 reading p4 views
132 collecting p4 changelists
132 collecting p4 changelists
133 5 add d e f
133 5 add d e f
134 sorting...
134 sorting...
135 converting...
135 converting...
136 0 add d e f
136 0 add d e f
137 $ hg -R dst log --template 'rev={rev} desc="{desc}" tags="{tags}" files="{files}"\n'
137 $ hg -R dst log --template 'rev={rev} desc="{desc}" tags="{tags}" files="{files}"\n'
138 rev=4 desc="add d e f" tags="tip" files=" e/ f d d"
138 rev=4 desc="add d e f" tags="tip" files=" e/ f d d"
139 rev=3 desc="change a b/c" tags="" files="a b/c"
139 rev=3 desc="change a b/c" tags="" files="a b/c"
140 rev=2 desc="change b/c" tags="" files="b/c"
140 rev=2 desc="change b/c" tags="" files="b/c"
141 rev=1 desc="change a" tags="" files="a"
141 rev=1 desc="change a" tags="" files="a"
142 rev=0 desc="initial" tags="" files="a b/c"
142 rev=0 desc="initial" tags="" files="a b/c"
143
143
144 empty commit message
145 $ p4 edit a
146 //depot/test-mercurial-import/a#3 - opened for edit
147 $ echo aaaaa >> a
148 $ p4 submit -d ""
149 Submitting change 6.
150 Locking 1 files ...
151 edit //depot/test-mercurial-import/a#4
152 Change 6 submitted.
153 $ hg convert -s p4 $DEPOTPATH dst
154 scanning source...
155 reading p4 views
156 collecting p4 changelists
157 6 **empty changelist description**
158 sorting...
159 converting...
160 0
161
144 exit trap:
162 exit trap:
145 stopping the p4 server
163 stopping the p4 server
General Comments 0
You need to be logged in to leave comments. Login now