##// END OF EJS Templates
convert: when converting from Perforce use original local encoding by default...
Eugene Baranov -
r25884:b810b59e stable
parent child Browse files
Show More
@@ -1,444 +1,447 b''
1 # convert.py Foreign SCM converter
1 # convert.py Foreign SCM converter
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
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
7
8 '''import revisions from foreign VCS repositories into Mercurial'''
8 '''import revisions from foreign VCS repositories into Mercurial'''
9
9
10 import convcmd
10 import convcmd
11 import cvsps
11 import cvsps
12 import subversion
12 import subversion
13 from mercurial import cmdutil, templatekw
13 from mercurial import cmdutil, templatekw
14 from mercurial.i18n import _
14 from mercurial.i18n import _
15
15
16 cmdtable = {}
16 cmdtable = {}
17 command = cmdutil.command(cmdtable)
17 command = cmdutil.command(cmdtable)
18 # Note for extension authors: ONLY specify testedwith = 'internal' for
18 # Note for extension authors: ONLY specify testedwith = 'internal' for
19 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
19 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
20 # be specifying the version(s) of Mercurial they are tested with, or
20 # be specifying the version(s) of Mercurial they are tested with, or
21 # leave the attribute unspecified.
21 # leave the attribute unspecified.
22 testedwith = 'internal'
22 testedwith = 'internal'
23
23
24 # Commands definition was moved elsewhere to ease demandload job.
24 # Commands definition was moved elsewhere to ease demandload job.
25
25
26 @command('convert',
26 @command('convert',
27 [('', 'authors', '',
27 [('', 'authors', '',
28 _('username mapping filename (DEPRECATED, use --authormap instead)'),
28 _('username mapping filename (DEPRECATED, use --authormap instead)'),
29 _('FILE')),
29 _('FILE')),
30 ('s', 'source-type', '', _('source repository type'), _('TYPE')),
30 ('s', 'source-type', '', _('source repository type'), _('TYPE')),
31 ('d', 'dest-type', '', _('destination repository type'), _('TYPE')),
31 ('d', 'dest-type', '', _('destination repository type'), _('TYPE')),
32 ('r', 'rev', [], _('import up to source revision REV'), _('REV')),
32 ('r', 'rev', [], _('import up to source revision REV'), _('REV')),
33 ('A', 'authormap', '', _('remap usernames using this file'), _('FILE')),
33 ('A', 'authormap', '', _('remap usernames using this file'), _('FILE')),
34 ('', 'filemap', '', _('remap file names using contents of file'),
34 ('', 'filemap', '', _('remap file names using contents of file'),
35 _('FILE')),
35 _('FILE')),
36 ('', 'full', None,
36 ('', 'full', None,
37 _('apply filemap changes by converting all files again')),
37 _('apply filemap changes by converting all files again')),
38 ('', 'splicemap', '', _('splice synthesized history into place'),
38 ('', 'splicemap', '', _('splice synthesized history into place'),
39 _('FILE')),
39 _('FILE')),
40 ('', 'branchmap', '', _('change branch names while converting'),
40 ('', 'branchmap', '', _('change branch names while converting'),
41 _('FILE')),
41 _('FILE')),
42 ('', 'branchsort', None, _('try to sort changesets by branches')),
42 ('', 'branchsort', None, _('try to sort changesets by branches')),
43 ('', 'datesort', None, _('try to sort changesets by date')),
43 ('', 'datesort', None, _('try to sort changesets by date')),
44 ('', 'sourcesort', None, _('preserve source changesets order')),
44 ('', 'sourcesort', None, _('preserve source changesets order')),
45 ('', 'closesort', None, _('try to reorder closed revisions'))],
45 ('', 'closesort', None, _('try to reorder closed revisions'))],
46 _('hg convert [OPTION]... SOURCE [DEST [REVMAP]]'),
46 _('hg convert [OPTION]... SOURCE [DEST [REVMAP]]'),
47 norepo=True)
47 norepo=True)
48 def convert(ui, src, dest=None, revmapfile=None, **opts):
48 def convert(ui, src, dest=None, revmapfile=None, **opts):
49 """convert a foreign SCM repository to a Mercurial one.
49 """convert a foreign SCM repository to a Mercurial one.
50
50
51 Accepted source formats [identifiers]:
51 Accepted source formats [identifiers]:
52
52
53 - Mercurial [hg]
53 - Mercurial [hg]
54 - CVS [cvs]
54 - CVS [cvs]
55 - Darcs [darcs]
55 - Darcs [darcs]
56 - git [git]
56 - git [git]
57 - Subversion [svn]
57 - Subversion [svn]
58 - Monotone [mtn]
58 - Monotone [mtn]
59 - GNU Arch [gnuarch]
59 - GNU Arch [gnuarch]
60 - Bazaar [bzr]
60 - Bazaar [bzr]
61 - Perforce [p4]
61 - Perforce [p4]
62
62
63 Accepted destination formats [identifiers]:
63 Accepted destination formats [identifiers]:
64
64
65 - Mercurial [hg]
65 - Mercurial [hg]
66 - Subversion [svn] (history on branches is not preserved)
66 - Subversion [svn] (history on branches is not preserved)
67
67
68 If no revision is given, all revisions will be converted.
68 If no revision is given, all revisions will be converted.
69 Otherwise, convert will only import up to the named revision
69 Otherwise, convert will only import up to the named revision
70 (given in a format understood by the source).
70 (given in a format understood by the source).
71
71
72 If no destination directory name is specified, it defaults to the
72 If no destination directory name is specified, it defaults to the
73 basename of the source with ``-hg`` appended. If the destination
73 basename of the source with ``-hg`` appended. If the destination
74 repository doesn't exist, it will be created.
74 repository doesn't exist, it will be created.
75
75
76 By default, all sources except Mercurial will use --branchsort.
76 By default, all sources except Mercurial will use --branchsort.
77 Mercurial uses --sourcesort to preserve original revision numbers
77 Mercurial uses --sourcesort to preserve original revision numbers
78 order. Sort modes have the following effects:
78 order. Sort modes have the following effects:
79
79
80 --branchsort convert from parent to child revision when possible,
80 --branchsort convert from parent to child revision when possible,
81 which means branches are usually converted one after
81 which means branches are usually converted one after
82 the other. It generates more compact repositories.
82 the other. It generates more compact repositories.
83
83
84 --datesort sort revisions by date. Converted repositories have
84 --datesort sort revisions by date. Converted repositories have
85 good-looking changelogs but are often an order of
85 good-looking changelogs but are often an order of
86 magnitude larger than the same ones generated by
86 magnitude larger than the same ones generated by
87 --branchsort.
87 --branchsort.
88
88
89 --sourcesort try to preserve source revisions order, only
89 --sourcesort try to preserve source revisions order, only
90 supported by Mercurial sources.
90 supported by Mercurial sources.
91
91
92 --closesort try to move closed revisions as close as possible
92 --closesort try to move closed revisions as close as possible
93 to parent branches, only supported by Mercurial
93 to parent branches, only supported by Mercurial
94 sources.
94 sources.
95
95
96 If ``REVMAP`` isn't given, it will be put in a default location
96 If ``REVMAP`` isn't given, it will be put in a default location
97 (``<dest>/.hg/shamap`` by default). The ``REVMAP`` is a simple
97 (``<dest>/.hg/shamap`` by default). The ``REVMAP`` is a simple
98 text file that maps each source commit ID to the destination ID
98 text file that maps each source commit ID to the destination ID
99 for that revision, like so::
99 for that revision, like so::
100
100
101 <source ID> <destination ID>
101 <source ID> <destination ID>
102
102
103 If the file doesn't exist, it's automatically created. It's
103 If the file doesn't exist, it's automatically created. It's
104 updated on each commit copied, so :hg:`convert` can be interrupted
104 updated on each commit copied, so :hg:`convert` can be interrupted
105 and can be run repeatedly to copy new commits.
105 and can be run repeatedly to copy new commits.
106
106
107 The authormap is a simple text file that maps each source commit
107 The authormap is a simple text file that maps each source commit
108 author to a destination commit author. It is handy for source SCMs
108 author to a destination commit author. It is handy for source SCMs
109 that use unix logins to identify authors (e.g.: CVS). One line per
109 that use unix logins to identify authors (e.g.: CVS). One line per
110 author mapping and the line format is::
110 author mapping and the line format is::
111
111
112 source author = destination author
112 source author = destination author
113
113
114 Empty lines and lines starting with a ``#`` are ignored.
114 Empty lines and lines starting with a ``#`` are ignored.
115
115
116 The filemap is a file that allows filtering and remapping of files
116 The filemap is a file that allows filtering and remapping of files
117 and directories. Each line can contain one of the following
117 and directories. Each line can contain one of the following
118 directives::
118 directives::
119
119
120 include path/to/file-or-dir
120 include path/to/file-or-dir
121
121
122 exclude path/to/file-or-dir
122 exclude path/to/file-or-dir
123
123
124 rename path/to/source path/to/destination
124 rename path/to/source path/to/destination
125
125
126 Comment lines start with ``#``. A specified path matches if it
126 Comment lines start with ``#``. A specified path matches if it
127 equals the full relative name of a file or one of its parent
127 equals the full relative name of a file or one of its parent
128 directories. The ``include`` or ``exclude`` directive with the
128 directories. The ``include`` or ``exclude`` directive with the
129 longest matching path applies, so line order does not matter.
129 longest matching path applies, so line order does not matter.
130
130
131 The ``include`` directive causes a file, or all files under a
131 The ``include`` directive causes a file, or all files under a
132 directory, to be included in the destination repository. The default
132 directory, to be included in the destination repository. The default
133 if there are no ``include`` statements is to include everything.
133 if there are no ``include`` statements is to include everything.
134 If there are any ``include`` statements, nothing else is included.
134 If there are any ``include`` statements, nothing else is included.
135 The ``exclude`` directive causes files or directories to
135 The ``exclude`` directive causes files or directories to
136 be omitted. The ``rename`` directive renames a file or directory if
136 be omitted. The ``rename`` directive renames a file or directory if
137 it is converted. To rename from a subdirectory into the root of
137 it is converted. To rename from a subdirectory into the root of
138 the repository, use ``.`` as the path to rename to.
138 the repository, use ``.`` as the path to rename to.
139
139
140 ``--full`` will make sure the converted changesets contain exactly
140 ``--full`` will make sure the converted changesets contain exactly
141 the right files with the right content. It will make a full
141 the right files with the right content. It will make a full
142 conversion of all files, not just the ones that have
142 conversion of all files, not just the ones that have
143 changed. Files that already are correct will not be changed. This
143 changed. Files that already are correct will not be changed. This
144 can be used to apply filemap changes when converting
144 can be used to apply filemap changes when converting
145 incrementally. This is currently only supported for Mercurial and
145 incrementally. This is currently only supported for Mercurial and
146 Subversion.
146 Subversion.
147
147
148 The splicemap is a file that allows insertion of synthetic
148 The splicemap is a file that allows insertion of synthetic
149 history, letting you specify the parents of a revision. This is
149 history, letting you specify the parents of a revision. This is
150 useful if you want to e.g. give a Subversion merge two parents, or
150 useful if you want to e.g. give a Subversion merge two parents, or
151 graft two disconnected series of history together. Each entry
151 graft two disconnected series of history together. Each entry
152 contains a key, followed by a space, followed by one or two
152 contains a key, followed by a space, followed by one or two
153 comma-separated values::
153 comma-separated values::
154
154
155 key parent1, parent2
155 key parent1, parent2
156
156
157 The key is the revision ID in the source
157 The key is the revision ID in the source
158 revision control system whose parents should be modified (same
158 revision control system whose parents should be modified (same
159 format as a key in .hg/shamap). The values are the revision IDs
159 format as a key in .hg/shamap). The values are the revision IDs
160 (in either the source or destination revision control system) that
160 (in either the source or destination revision control system) that
161 should be used as the new parents for that node. For example, if
161 should be used as the new parents for that node. For example, if
162 you have merged "release-1.0" into "trunk", then you should
162 you have merged "release-1.0" into "trunk", then you should
163 specify the revision on "trunk" as the first parent and the one on
163 specify the revision on "trunk" as the first parent and the one on
164 the "release-1.0" branch as the second.
164 the "release-1.0" branch as the second.
165
165
166 The branchmap is a file that allows you to rename a branch when it is
166 The branchmap is a file that allows you to rename a branch when it is
167 being brought in from whatever external repository. When used in
167 being brought in from whatever external repository. When used in
168 conjunction with a splicemap, it allows for a powerful combination
168 conjunction with a splicemap, it allows for a powerful combination
169 to help fix even the most badly mismanaged repositories and turn them
169 to help fix even the most badly mismanaged repositories and turn them
170 into nicely structured Mercurial repositories. The branchmap contains
170 into nicely structured Mercurial repositories. The branchmap contains
171 lines of the form::
171 lines of the form::
172
172
173 original_branch_name new_branch_name
173 original_branch_name new_branch_name
174
174
175 where "original_branch_name" is the name of the branch in the
175 where "original_branch_name" is the name of the branch in the
176 source repository, and "new_branch_name" is the name of the branch
176 source repository, and "new_branch_name" is the name of the branch
177 is the destination repository. No whitespace is allowed in the
177 is the destination repository. No whitespace is allowed in the
178 branch names. This can be used to (for instance) move code in one
178 branch names. This can be used to (for instance) move code in one
179 repository from "default" to a named branch.
179 repository from "default" to a named branch.
180
180
181 Mercurial Source
181 Mercurial Source
182 ################
182 ################
183
183
184 The Mercurial source recognizes the following configuration
184 The Mercurial source recognizes the following configuration
185 options, which you can set on the command line with ``--config``:
185 options, which you can set on the command line with ``--config``:
186
186
187 :convert.hg.ignoreerrors: ignore integrity errors when reading.
187 :convert.hg.ignoreerrors: ignore integrity errors when reading.
188 Use it to fix Mercurial repositories with missing revlogs, by
188 Use it to fix Mercurial repositories with missing revlogs, by
189 converting from and to Mercurial. Default is False.
189 converting from and to Mercurial. Default is False.
190
190
191 :convert.hg.saverev: store original revision ID in changeset
191 :convert.hg.saverev: store original revision ID in changeset
192 (forces target IDs to change). It takes a boolean argument and
192 (forces target IDs to change). It takes a boolean argument and
193 defaults to False.
193 defaults to False.
194
194
195 :convert.hg.startrev: specify the initial Mercurial revision.
195 :convert.hg.startrev: specify the initial Mercurial revision.
196 The default is 0.
196 The default is 0.
197
197
198 :convert.hg.revs: revset specifying the source revisions to convert.
198 :convert.hg.revs: revset specifying the source revisions to convert.
199
199
200 CVS Source
200 CVS Source
201 ##########
201 ##########
202
202
203 CVS source will use a sandbox (i.e. a checked-out copy) from CVS
203 CVS source will use a sandbox (i.e. a checked-out copy) from CVS
204 to indicate the starting point of what will be converted. Direct
204 to indicate the starting point of what will be converted. Direct
205 access to the repository files is not needed, unless of course the
205 access to the repository files is not needed, unless of course the
206 repository is ``:local:``. The conversion uses the top level
206 repository is ``:local:``. The conversion uses the top level
207 directory in the sandbox to find the CVS repository, and then uses
207 directory in the sandbox to find the CVS repository, and then uses
208 CVS rlog commands to find files to convert. This means that unless
208 CVS rlog commands to find files to convert. This means that unless
209 a filemap is given, all files under the starting directory will be
209 a filemap is given, all files under the starting directory will be
210 converted, and that any directory reorganization in the CVS
210 converted, and that any directory reorganization in the CVS
211 sandbox is ignored.
211 sandbox is ignored.
212
212
213 The following options can be used with ``--config``:
213 The following options can be used with ``--config``:
214
214
215 :convert.cvsps.cache: Set to False to disable remote log caching,
215 :convert.cvsps.cache: Set to False to disable remote log caching,
216 for testing and debugging purposes. Default is True.
216 for testing and debugging purposes. Default is True.
217
217
218 :convert.cvsps.fuzz: Specify the maximum time (in seconds) that is
218 :convert.cvsps.fuzz: Specify the maximum time (in seconds) that is
219 allowed between commits with identical user and log message in
219 allowed between commits with identical user and log message in
220 a single changeset. When very large files were checked in as
220 a single changeset. When very large files were checked in as
221 part of a changeset then the default may not be long enough.
221 part of a changeset then the default may not be long enough.
222 The default is 60.
222 The default is 60.
223
223
224 :convert.cvsps.mergeto: Specify a regular expression to which
224 :convert.cvsps.mergeto: Specify a regular expression to which
225 commit log messages are matched. If a match occurs, then the
225 commit log messages are matched. If a match occurs, then the
226 conversion process will insert a dummy revision merging the
226 conversion process will insert a dummy revision merging the
227 branch on which this log message occurs to the branch
227 branch on which this log message occurs to the branch
228 indicated in the regex. Default is ``{{mergetobranch
228 indicated in the regex. Default is ``{{mergetobranch
229 ([-\\w]+)}}``
229 ([-\\w]+)}}``
230
230
231 :convert.cvsps.mergefrom: Specify a regular expression to which
231 :convert.cvsps.mergefrom: Specify a regular expression to which
232 commit log messages are matched. If a match occurs, then the
232 commit log messages are matched. If a match occurs, then the
233 conversion process will add the most recent revision on the
233 conversion process will add the most recent revision on the
234 branch indicated in the regex as the second parent of the
234 branch indicated in the regex as the second parent of the
235 changeset. Default is ``{{mergefrombranch ([-\\w]+)}}``
235 changeset. Default is ``{{mergefrombranch ([-\\w]+)}}``
236
236
237 :convert.localtimezone: use local time (as determined by the TZ
237 :convert.localtimezone: use local time (as determined by the TZ
238 environment variable) for changeset date/times. The default
238 environment variable) for changeset date/times. The default
239 is False (use UTC).
239 is False (use UTC).
240
240
241 :hooks.cvslog: Specify a Python function to be called at the end of
241 :hooks.cvslog: Specify a Python function to be called at the end of
242 gathering the CVS log. The function is passed a list with the
242 gathering the CVS log. The function is passed a list with the
243 log entries, and can modify the entries in-place, or add or
243 log entries, and can modify the entries in-place, or add or
244 delete them.
244 delete them.
245
245
246 :hooks.cvschangesets: Specify a Python function to be called after
246 :hooks.cvschangesets: Specify a Python function to be called after
247 the changesets are calculated from the CVS log. The
247 the changesets are calculated from the CVS log. The
248 function is passed a list with the changeset entries, and can
248 function is passed a list with the changeset entries, and can
249 modify the changesets in-place, or add or delete them.
249 modify the changesets in-place, or add or delete them.
250
250
251 An additional "debugcvsps" Mercurial command allows the builtin
251 An additional "debugcvsps" Mercurial command allows the builtin
252 changeset merging code to be run without doing a conversion. Its
252 changeset merging code to be run without doing a conversion. Its
253 parameters and output are similar to that of cvsps 2.1. Please see
253 parameters and output are similar to that of cvsps 2.1. Please see
254 the command help for more details.
254 the command help for more details.
255
255
256 Subversion Source
256 Subversion Source
257 #################
257 #################
258
258
259 Subversion source detects classical trunk/branches/tags layouts.
259 Subversion source detects classical trunk/branches/tags layouts.
260 By default, the supplied ``svn://repo/path/`` source URL is
260 By default, the supplied ``svn://repo/path/`` source URL is
261 converted as a single branch. If ``svn://repo/path/trunk`` exists
261 converted as a single branch. If ``svn://repo/path/trunk`` exists
262 it replaces the default branch. If ``svn://repo/path/branches``
262 it replaces the default branch. If ``svn://repo/path/branches``
263 exists, its subdirectories are listed as possible branches. If
263 exists, its subdirectories are listed as possible branches. If
264 ``svn://repo/path/tags`` exists, it is looked for tags referencing
264 ``svn://repo/path/tags`` exists, it is looked for tags referencing
265 converted branches. Default ``trunk``, ``branches`` and ``tags``
265 converted branches. Default ``trunk``, ``branches`` and ``tags``
266 values can be overridden with following options. Set them to paths
266 values can be overridden with following options. Set them to paths
267 relative to the source URL, or leave them blank to disable auto
267 relative to the source URL, or leave them blank to disable auto
268 detection.
268 detection.
269
269
270 The following options can be set with ``--config``:
270 The following options can be set with ``--config``:
271
271
272 :convert.svn.branches: specify the directory containing branches.
272 :convert.svn.branches: specify the directory containing branches.
273 The default is ``branches``.
273 The default is ``branches``.
274
274
275 :convert.svn.tags: specify the directory containing tags. The
275 :convert.svn.tags: specify the directory containing tags. The
276 default is ``tags``.
276 default is ``tags``.
277
277
278 :convert.svn.trunk: specify the name of the trunk branch. The
278 :convert.svn.trunk: specify the name of the trunk branch. The
279 default is ``trunk``.
279 default is ``trunk``.
280
280
281 :convert.localtimezone: use local time (as determined by the TZ
281 :convert.localtimezone: use local time (as determined by the TZ
282 environment variable) for changeset date/times. The default
282 environment variable) for changeset date/times. The default
283 is False (use UTC).
283 is False (use UTC).
284
284
285 Source history can be retrieved starting at a specific revision,
285 Source history can be retrieved starting at a specific revision,
286 instead of being integrally converted. Only single branch
286 instead of being integrally converted. Only single branch
287 conversions are supported.
287 conversions are supported.
288
288
289 :convert.svn.startrev: specify start Subversion revision number.
289 :convert.svn.startrev: specify start Subversion revision number.
290 The default is 0.
290 The default is 0.
291
291
292 Git Source
292 Git Source
293 ##########
293 ##########
294
294
295 The Git importer converts commits from all reachable branches (refs
295 The Git importer converts commits from all reachable branches (refs
296 in refs/heads) and remotes (refs in refs/remotes) to Mercurial.
296 in refs/heads) and remotes (refs in refs/remotes) to Mercurial.
297 Branches are converted to bookmarks with the same name, with the
297 Branches are converted to bookmarks with the same name, with the
298 leading 'refs/heads' stripped. Git submodules are converted to Git
298 leading 'refs/heads' stripped. Git submodules are converted to Git
299 subrepos in Mercurial.
299 subrepos in Mercurial.
300
300
301 The following options can be set with ``--config``:
301 The following options can be set with ``--config``:
302
302
303 :convert.git.similarity: specify how similar files modified in a
303 :convert.git.similarity: specify how similar files modified in a
304 commit must be to be imported as renames or copies, as a
304 commit must be to be imported as renames or copies, as a
305 percentage between ``0`` (disabled) and ``100`` (files must be
305 percentage between ``0`` (disabled) and ``100`` (files must be
306 identical). For example, ``90`` means that a delete/add pair will
306 identical). For example, ``90`` means that a delete/add pair will
307 be imported as a rename if more than 90% of the file hasn't
307 be imported as a rename if more than 90% of the file hasn't
308 changed. The default is ``50``.
308 changed. The default is ``50``.
309
309
310 :convert.git.findcopiesharder: while detecting copies, look at all
310 :convert.git.findcopiesharder: while detecting copies, look at all
311 files in the working copy instead of just changed ones. This
311 files in the working copy instead of just changed ones. This
312 is very expensive for large projects, and is only effective when
312 is very expensive for large projects, and is only effective when
313 ``convert.git.similarity`` is greater than 0. The default is False.
313 ``convert.git.similarity`` is greater than 0. The default is False.
314
314
315 :convert.git.remoteprefix: remote refs are converted as bookmarks with
315 :convert.git.remoteprefix: remote refs are converted as bookmarks with
316 ``convert.git.remoteprefix`` as a prefix followed by a /. The default
316 ``convert.git.remoteprefix`` as a prefix followed by a /. The default
317 is 'remote'.
317 is 'remote'.
318
318
319 Perforce Source
319 Perforce Source
320 ###############
320 ###############
321
321
322 The Perforce (P4) importer can be given a p4 depot path or a
322 The Perforce (P4) importer can be given a p4 depot path or a
323 client specification as source. It will convert all files in the
323 client specification as source. It will convert all files in the
324 source to a flat Mercurial repository, ignoring labels, branches
324 source to a flat Mercurial repository, ignoring labels, branches
325 and integrations. Note that when a depot path is given you then
325 and integrations. Note that when a depot path is given you then
326 usually should specify a target directory, because otherwise the
326 usually should specify a target directory, because otherwise the
327 target may be named ``...-hg``.
327 target may be named ``...-hg``.
328
328
329 It is possible to limit the amount of source history to be
329 The following options can be set with ``--config``:
330 converted by specifying an initial Perforce revision:
330
331 :convert.p4.encoding: specify the encoding to use when decoding standard
332 output of the Perforce command line tool. The default is default system
333 encoding.
331
334
332 :convert.p4.startrev: specify initial Perforce revision (a
335 :convert.p4.startrev: specify initial Perforce revision (a
333 Perforce changelist number).
336 Perforce changelist number).
334
337
335 Mercurial Destination
338 Mercurial Destination
336 #####################
339 #####################
337
340
338 The Mercurial destination will recognize Mercurial subrepositories in the
341 The Mercurial destination will recognize Mercurial subrepositories in the
339 destination directory, and update the .hgsubstate file automatically if the
342 destination directory, and update the .hgsubstate file automatically if the
340 destination subrepositories contain the <dest>/<sub>/.hg/shamap file.
343 destination subrepositories contain the <dest>/<sub>/.hg/shamap file.
341 Converting a repository with subrepositories requires converting a single
344 Converting a repository with subrepositories requires converting a single
342 repository at a time, from the bottom up.
345 repository at a time, from the bottom up.
343
346
344 .. container:: verbose
347 .. container:: verbose
345
348
346 An example showing how to convert a repository with subrepositories::
349 An example showing how to convert a repository with subrepositories::
347
350
348 # so convert knows the type when it sees a non empty destination
351 # so convert knows the type when it sees a non empty destination
349 $ hg init converted
352 $ hg init converted
350
353
351 $ hg convert orig/sub1 converted/sub1
354 $ hg convert orig/sub1 converted/sub1
352 $ hg convert orig/sub2 converted/sub2
355 $ hg convert orig/sub2 converted/sub2
353 $ hg convert orig converted
356 $ hg convert orig converted
354
357
355 The following options are supported:
358 The following options are supported:
356
359
357 :convert.hg.clonebranches: dispatch source branches in separate
360 :convert.hg.clonebranches: dispatch source branches in separate
358 clones. The default is False.
361 clones. The default is False.
359
362
360 :convert.hg.tagsbranch: branch name for tag revisions, defaults to
363 :convert.hg.tagsbranch: branch name for tag revisions, defaults to
361 ``default``.
364 ``default``.
362
365
363 :convert.hg.usebranchnames: preserve branch names. The default is
366 :convert.hg.usebranchnames: preserve branch names. The default is
364 True.
367 True.
365
368
366 :convert.hg.sourcename: records the given string as a 'convert_source' extra
369 :convert.hg.sourcename: records the given string as a 'convert_source' extra
367 value on each commit made in the target repository. The default is None.
370 value on each commit made in the target repository. The default is None.
368
371
369 All Destinations
372 All Destinations
370 ################
373 ################
371
374
372 All destination types accept the following options:
375 All destination types accept the following options:
373
376
374 :convert.skiptags: does not convert tags from the source repo to the target
377 :convert.skiptags: does not convert tags from the source repo to the target
375 repo. The default is False.
378 repo. The default is False.
376 """
379 """
377 return convcmd.convert(ui, src, dest, revmapfile, **opts)
380 return convcmd.convert(ui, src, dest, revmapfile, **opts)
378
381
379 @command('debugsvnlog', [], 'hg debugsvnlog', norepo=True)
382 @command('debugsvnlog', [], 'hg debugsvnlog', norepo=True)
380 def debugsvnlog(ui, **opts):
383 def debugsvnlog(ui, **opts):
381 return subversion.debugsvnlog(ui, **opts)
384 return subversion.debugsvnlog(ui, **opts)
382
385
383 @command('debugcvsps',
386 @command('debugcvsps',
384 [
387 [
385 # Main options shared with cvsps-2.1
388 # Main options shared with cvsps-2.1
386 ('b', 'branches', [], _('only return changes on specified branches')),
389 ('b', 'branches', [], _('only return changes on specified branches')),
387 ('p', 'prefix', '', _('prefix to remove from file names')),
390 ('p', 'prefix', '', _('prefix to remove from file names')),
388 ('r', 'revisions', [],
391 ('r', 'revisions', [],
389 _('only return changes after or between specified tags')),
392 _('only return changes after or between specified tags')),
390 ('u', 'update-cache', None, _("update cvs log cache")),
393 ('u', 'update-cache', None, _("update cvs log cache")),
391 ('x', 'new-cache', None, _("create new cvs log cache")),
394 ('x', 'new-cache', None, _("create new cvs log cache")),
392 ('z', 'fuzz', 60, _('set commit time fuzz in seconds')),
395 ('z', 'fuzz', 60, _('set commit time fuzz in seconds')),
393 ('', 'root', '', _('specify cvsroot')),
396 ('', 'root', '', _('specify cvsroot')),
394 # Options specific to builtin cvsps
397 # Options specific to builtin cvsps
395 ('', 'parents', '', _('show parent changesets')),
398 ('', 'parents', '', _('show parent changesets')),
396 ('', 'ancestors', '', _('show current changeset in ancestor branches')),
399 ('', 'ancestors', '', _('show current changeset in ancestor branches')),
397 # Options that are ignored for compatibility with cvsps-2.1
400 # Options that are ignored for compatibility with cvsps-2.1
398 ('A', 'cvs-direct', None, _('ignored for compatibility')),
401 ('A', 'cvs-direct', None, _('ignored for compatibility')),
399 ],
402 ],
400 _('hg debugcvsps [OPTION]... [PATH]...'),
403 _('hg debugcvsps [OPTION]... [PATH]...'),
401 norepo=True)
404 norepo=True)
402 def debugcvsps(ui, *args, **opts):
405 def debugcvsps(ui, *args, **opts):
403 '''create changeset information from CVS
406 '''create changeset information from CVS
404
407
405 This command is intended as a debugging tool for the CVS to
408 This command is intended as a debugging tool for the CVS to
406 Mercurial converter, and can be used as a direct replacement for
409 Mercurial converter, and can be used as a direct replacement for
407 cvsps.
410 cvsps.
408
411
409 Hg debugcvsps reads the CVS rlog for current directory (or any
412 Hg debugcvsps reads the CVS rlog for current directory (or any
410 named directory) in the CVS repository, and converts the log to a
413 named directory) in the CVS repository, and converts the log to a
411 series of changesets based on matching commit log entries and
414 series of changesets based on matching commit log entries and
412 dates.'''
415 dates.'''
413 return cvsps.debugcvsps(ui, *args, **opts)
416 return cvsps.debugcvsps(ui, *args, **opts)
414
417
415 def kwconverted(ctx, name):
418 def kwconverted(ctx, name):
416 rev = ctx.extra().get('convert_revision', '')
419 rev = ctx.extra().get('convert_revision', '')
417 if rev.startswith('svn:'):
420 if rev.startswith('svn:'):
418 if name == 'svnrev':
421 if name == 'svnrev':
419 return str(subversion.revsplit(rev)[2])
422 return str(subversion.revsplit(rev)[2])
420 elif name == 'svnpath':
423 elif name == 'svnpath':
421 return subversion.revsplit(rev)[1]
424 return subversion.revsplit(rev)[1]
422 elif name == 'svnuuid':
425 elif name == 'svnuuid':
423 return subversion.revsplit(rev)[0]
426 return subversion.revsplit(rev)[0]
424 return rev
427 return rev
425
428
426 def kwsvnrev(repo, ctx, **args):
429 def kwsvnrev(repo, ctx, **args):
427 """:svnrev: String. Converted subversion revision number."""
430 """:svnrev: String. Converted subversion revision number."""
428 return kwconverted(ctx, 'svnrev')
431 return kwconverted(ctx, 'svnrev')
429
432
430 def kwsvnpath(repo, ctx, **args):
433 def kwsvnpath(repo, ctx, **args):
431 """:svnpath: String. Converted subversion revision project path."""
434 """:svnpath: String. Converted subversion revision project path."""
432 return kwconverted(ctx, 'svnpath')
435 return kwconverted(ctx, 'svnpath')
433
436
434 def kwsvnuuid(repo, ctx, **args):
437 def kwsvnuuid(repo, ctx, **args):
435 """:svnuuid: String. Converted subversion revision repository identifier."""
438 """:svnuuid: String. Converted subversion revision repository identifier."""
436 return kwconverted(ctx, 'svnuuid')
439 return kwconverted(ctx, 'svnuuid')
437
440
438 def extsetup(ui):
441 def extsetup(ui):
439 templatekw.keywords['svnrev'] = kwsvnrev
442 templatekw.keywords['svnrev'] = kwsvnrev
440 templatekw.keywords['svnpath'] = kwsvnpath
443 templatekw.keywords['svnpath'] = kwsvnpath
441 templatekw.keywords['svnuuid'] = kwsvnuuid
444 templatekw.keywords['svnuuid'] = kwsvnuuid
442
445
443 # tell hggettext to extract docstrings from these functions:
446 # tell hggettext to extract docstrings from these functions:
444 i18nfunctions = [kwsvnrev, kwsvnpath, kwsvnuuid]
447 i18nfunctions = [kwsvnrev, kwsvnpath, kwsvnuuid]
@@ -1,286 +1,290 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
7
8 from mercurial import util
8 from mercurial import util
9 from mercurial.i18n import _
9 from mercurial.i18n import _
10
10
11 from common import commit, converter_source, checktool, NoRepo
11 from common import commit, converter_source, checktool, NoRepo
12 import marshal
12 import marshal
13 import re
13 import re
14
14
15 def loaditer(f):
15 def loaditer(f):
16 "Yield the dictionary objects generated by p4"
16 "Yield the dictionary objects generated by p4"
17 try:
17 try:
18 while True:
18 while True:
19 d = marshal.load(f)
19 d = marshal.load(f)
20 if not d:
20 if not d:
21 break
21 break
22 yield d
22 yield d
23 except EOFError:
23 except EOFError:
24 pass
24 pass
25
25
26 def decodefilename(filename):
26 def decodefilename(filename):
27 """Perforce escapes special characters @, #, *, or %
27 """Perforce escapes special characters @, #, *, or %
28 with %40, %23, %2A, or %25 respectively
28 with %40, %23, %2A, or %25 respectively
29
29
30 >>> decodefilename('portable-net45%252Bnetcore45%252Bwp8%252BMonoAndroid')
30 >>> decodefilename('portable-net45%252Bnetcore45%252Bwp8%252BMonoAndroid')
31 'portable-net45%2Bnetcore45%2Bwp8%2BMonoAndroid'
31 'portable-net45%2Bnetcore45%2Bwp8%2BMonoAndroid'
32 >>> decodefilename('//Depot/Directory/%2525/%2523/%23%40.%2A')
32 >>> decodefilename('//Depot/Directory/%2525/%2523/%23%40.%2A')
33 '//Depot/Directory/%25/%23/#@.*'
33 '//Depot/Directory/%25/%23/#@.*'
34 """
34 """
35 replacements = [('%2A', '*'), ('%23', '#'), ('%40', '@'), ('%25', '%')]
35 replacements = [('%2A', '*'), ('%23', '#'), ('%40', '@'), ('%25', '%')]
36 for k, v in replacements:
36 for k, v in replacements:
37 filename = filename.replace(k, v)
37 filename = filename.replace(k, v)
38 return filename
38 return filename
39
39
40 class p4_source(converter_source):
40 class p4_source(converter_source):
41 def __init__(self, ui, path, revs=None):
41 def __init__(self, ui, path, revs=None):
42 # avoid import cycle
43 import convcmd
44
42 super(p4_source, self).__init__(ui, path, revs=revs)
45 super(p4_source, self).__init__(ui, path, revs=revs)
43
46
44 if "/" in path and not path.startswith('//'):
47 if "/" in path and not path.startswith('//'):
45 raise NoRepo(_('%s does not look like a P4 repository') % path)
48 raise NoRepo(_('%s does not look like a P4 repository') % path)
46
49
47 checktool('p4', abort=False)
50 checktool('p4', abort=False)
48
51
49 self.p4changes = {}
52 self.p4changes = {}
50 self.heads = {}
53 self.heads = {}
51 self.changeset = {}
54 self.changeset = {}
52 self.files = {}
55 self.files = {}
53 self.copies = {}
56 self.copies = {}
54 self.tags = {}
57 self.tags = {}
55 self.lastbranch = {}
58 self.lastbranch = {}
56 self.parent = {}
59 self.parent = {}
57 self.encoding = "latin_1"
60 self.encoding = self.ui.config('convert', 'p4.encoding',
61 default=convcmd.orig_encoding)
58 self.depotname = {} # mapping from local name to depot name
62 self.depotname = {} # mapping from local name to depot name
59 self.localname = {} # mapping from depot name to local name
63 self.localname = {} # mapping from depot name to local name
60 self.re_type = re.compile(
64 self.re_type = re.compile(
61 "([a-z]+)?(text|binary|symlink|apple|resource|unicode|utf\d+)"
65 "([a-z]+)?(text|binary|symlink|apple|resource|unicode|utf\d+)"
62 "(\+\w+)?$")
66 "(\+\w+)?$")
63 self.re_keywords = re.compile(
67 self.re_keywords = re.compile(
64 r"\$(Id|Header|Date|DateTime|Change|File|Revision|Author)"
68 r"\$(Id|Header|Date|DateTime|Change|File|Revision|Author)"
65 r":[^$\n]*\$")
69 r":[^$\n]*\$")
66 self.re_keywords_old = re.compile("\$(Id|Header):[^$\n]*\$")
70 self.re_keywords_old = re.compile("\$(Id|Header):[^$\n]*\$")
67
71
68 if revs and len(revs) > 1:
72 if revs and len(revs) > 1:
69 raise util.Abort(_("p4 source does not support specifying "
73 raise util.Abort(_("p4 source does not support specifying "
70 "multiple revisions"))
74 "multiple revisions"))
71 self._parse(ui, path)
75 self._parse(ui, path)
72
76
73 def _parse_view(self, path):
77 def _parse_view(self, path):
74 "Read changes affecting the path"
78 "Read changes affecting the path"
75 cmd = 'p4 -G changes -s submitted %s' % util.shellquote(path)
79 cmd = 'p4 -G changes -s submitted %s' % util.shellquote(path)
76 stdout = util.popen(cmd, mode='rb')
80 stdout = util.popen(cmd, mode='rb')
77 for d in loaditer(stdout):
81 for d in loaditer(stdout):
78 c = d.get("change", None)
82 c = d.get("change", None)
79 if c:
83 if c:
80 self.p4changes[c] = True
84 self.p4changes[c] = True
81
85
82 def _parse(self, ui, path):
86 def _parse(self, ui, path):
83 "Prepare list of P4 filenames and revisions to import"
87 "Prepare list of P4 filenames and revisions to import"
84 ui.status(_('reading p4 views\n'))
88 ui.status(_('reading p4 views\n'))
85
89
86 # read client spec or view
90 # read client spec or view
87 if "/" in path:
91 if "/" in path:
88 self._parse_view(path)
92 self._parse_view(path)
89 if path.startswith("//") and path.endswith("/..."):
93 if path.startswith("//") and path.endswith("/..."):
90 views = {path[:-3]:""}
94 views = {path[:-3]:""}
91 else:
95 else:
92 views = {"//": ""}
96 views = {"//": ""}
93 else:
97 else:
94 cmd = 'p4 -G client -o %s' % util.shellquote(path)
98 cmd = 'p4 -G client -o %s' % util.shellquote(path)
95 clientspec = marshal.load(util.popen(cmd, mode='rb'))
99 clientspec = marshal.load(util.popen(cmd, mode='rb'))
96
100
97 views = {}
101 views = {}
98 for client in clientspec:
102 for client in clientspec:
99 if client.startswith("View"):
103 if client.startswith("View"):
100 sview, cview = clientspec[client].split()
104 sview, cview = clientspec[client].split()
101 self._parse_view(sview)
105 self._parse_view(sview)
102 if sview.endswith("...") and cview.endswith("..."):
106 if sview.endswith("...") and cview.endswith("..."):
103 sview = sview[:-3]
107 sview = sview[:-3]
104 cview = cview[:-3]
108 cview = cview[:-3]
105 cview = cview[2:]
109 cview = cview[2:]
106 cview = cview[cview.find("/") + 1:]
110 cview = cview[cview.find("/") + 1:]
107 views[sview] = cview
111 views[sview] = cview
108
112
109 # list of changes that affect our source files
113 # list of changes that affect our source files
110 self.p4changes = self.p4changes.keys()
114 self.p4changes = self.p4changes.keys()
111 self.p4changes.sort(key=int)
115 self.p4changes.sort(key=int)
112
116
113 # list with depot pathnames, longest first
117 # list with depot pathnames, longest first
114 vieworder = views.keys()
118 vieworder = views.keys()
115 vieworder.sort(key=len, reverse=True)
119 vieworder.sort(key=len, reverse=True)
116
120
117 # handle revision limiting
121 # handle revision limiting
118 startrev = self.ui.config('convert', 'p4.startrev', default=0)
122 startrev = self.ui.config('convert', 'p4.startrev', default=0)
119 self.p4changes = [x for x in self.p4changes
123 self.p4changes = [x for x in self.p4changes
120 if ((not startrev or int(x) >= int(startrev)) and
124 if ((not startrev or int(x) >= int(startrev)) and
121 (not self.revs or int(x) <= int(self.revs[0])))]
125 (not self.revs or int(x) <= int(self.revs[0])))]
122
126
123 # now read the full changelists to get the list of file revisions
127 # now read the full changelists to get the list of file revisions
124 ui.status(_('collecting p4 changelists\n'))
128 ui.status(_('collecting p4 changelists\n'))
125 lastid = None
129 lastid = None
126 for change in self.p4changes:
130 for change in self.p4changes:
127 cmd = "p4 -G describe -s %s" % change
131 cmd = "p4 -G describe -s %s" % change
128 stdout = util.popen(cmd, mode='rb')
132 stdout = util.popen(cmd, mode='rb')
129 d = marshal.load(stdout)
133 d = marshal.load(stdout)
130 desc = self.recode(d.get("desc", ""))
134 desc = self.recode(d.get("desc", ""))
131 shortdesc = desc.split("\n", 1)[0]
135 shortdesc = desc.split("\n", 1)[0]
132 t = '%s %s' % (d["change"], repr(shortdesc)[1:-1])
136 t = '%s %s' % (d["change"], repr(shortdesc)[1:-1])
133 ui.status(util.ellipsis(t, 80) + '\n')
137 ui.status(util.ellipsis(t, 80) + '\n')
134
138
135 if lastid:
139 if lastid:
136 parents = [lastid]
140 parents = [lastid]
137 else:
141 else:
138 parents = []
142 parents = []
139
143
140 date = (int(d["time"]), 0) # timezone not set
144 date = (int(d["time"]), 0) # timezone not set
141 c = commit(author=self.recode(d["user"]),
145 c = commit(author=self.recode(d["user"]),
142 date=util.datestr(date, '%Y-%m-%d %H:%M:%S %1%2'),
146 date=util.datestr(date, '%Y-%m-%d %H:%M:%S %1%2'),
143 parents=parents, desc=desc, branch=None,
147 parents=parents, desc=desc, branch=None,
144 extra={"p4": change})
148 extra={"p4": change})
145
149
146 files = []
150 files = []
147 copies = {}
151 copies = {}
148 copiedfiles = []
152 copiedfiles = []
149 i = 0
153 i = 0
150 while ("depotFile%d" % i) in d and ("rev%d" % i) in d:
154 while ("depotFile%d" % i) in d and ("rev%d" % i) in d:
151 oldname = d["depotFile%d" % i]
155 oldname = d["depotFile%d" % i]
152 filename = None
156 filename = None
153 for v in vieworder:
157 for v in vieworder:
154 if oldname.lower().startswith(v.lower()):
158 if oldname.lower().startswith(v.lower()):
155 filename = decodefilename(views[v] + oldname[len(v):])
159 filename = decodefilename(views[v] + oldname[len(v):])
156 break
160 break
157 if filename:
161 if filename:
158 files.append((filename, d["rev%d" % i]))
162 files.append((filename, d["rev%d" % i]))
159 self.depotname[filename] = oldname
163 self.depotname[filename] = oldname
160 if (d.get("action%d" % i) == "move/add"):
164 if (d.get("action%d" % i) == "move/add"):
161 copiedfiles.append(filename)
165 copiedfiles.append(filename)
162 self.localname[oldname] = filename
166 self.localname[oldname] = filename
163 i += 1
167 i += 1
164
168
165 # Collect information about copied files
169 # Collect information about copied files
166 for filename in copiedfiles:
170 for filename in copiedfiles:
167 oldname = self.depotname[filename]
171 oldname = self.depotname[filename]
168
172
169 flcmd = 'p4 -G filelog %s' \
173 flcmd = 'p4 -G filelog %s' \
170 % util.shellquote(oldname)
174 % util.shellquote(oldname)
171 flstdout = util.popen(flcmd, mode='rb')
175 flstdout = util.popen(flcmd, mode='rb')
172
176
173 copiedfilename = None
177 copiedfilename = None
174 for d in loaditer(flstdout):
178 for d in loaditer(flstdout):
175 copiedoldname = None
179 copiedoldname = None
176
180
177 i = 0
181 i = 0
178 while ("change%d" % i) in d:
182 while ("change%d" % i) in d:
179 if (d["change%d" % i] == change and
183 if (d["change%d" % i] == change and
180 d["action%d" % i] == "move/add"):
184 d["action%d" % i] == "move/add"):
181 j = 0
185 j = 0
182 while ("file%d,%d" % (i, j)) in d:
186 while ("file%d,%d" % (i, j)) in d:
183 if d["how%d,%d" % (i, j)] == "moved from":
187 if d["how%d,%d" % (i, j)] == "moved from":
184 copiedoldname = d["file%d,%d" % (i, j)]
188 copiedoldname = d["file%d,%d" % (i, j)]
185 break
189 break
186 j += 1
190 j += 1
187 i += 1
191 i += 1
188
192
189 if copiedoldname and copiedoldname in self.localname:
193 if copiedoldname and copiedoldname in self.localname:
190 copiedfilename = self.localname[copiedoldname]
194 copiedfilename = self.localname[copiedoldname]
191 break
195 break
192
196
193 if copiedfilename:
197 if copiedfilename:
194 copies[filename] = copiedfilename
198 copies[filename] = copiedfilename
195 else:
199 else:
196 ui.warn(_("cannot find source for copied file: %s@%s\n")
200 ui.warn(_("cannot find source for copied file: %s@%s\n")
197 % (filename, change))
201 % (filename, change))
198
202
199 self.changeset[change] = c
203 self.changeset[change] = c
200 self.files[change] = files
204 self.files[change] = files
201 self.copies[change] = copies
205 self.copies[change] = copies
202 lastid = change
206 lastid = change
203
207
204 if lastid:
208 if lastid:
205 self.heads = [lastid]
209 self.heads = [lastid]
206
210
207 def getheads(self):
211 def getheads(self):
208 return self.heads
212 return self.heads
209
213
210 def getfile(self, name, rev):
214 def getfile(self, name, rev):
211 cmd = 'p4 -G print %s' \
215 cmd = 'p4 -G print %s' \
212 % util.shellquote("%s#%s" % (self.depotname[name], rev))
216 % util.shellquote("%s#%s" % (self.depotname[name], rev))
213
217
214 lasterror = None
218 lasterror = None
215 while True:
219 while True:
216 stdout = util.popen(cmd, mode='rb')
220 stdout = util.popen(cmd, mode='rb')
217
221
218 mode = None
222 mode = None
219 contents = []
223 contents = []
220 keywords = None
224 keywords = None
221
225
222 for d in loaditer(stdout):
226 for d in loaditer(stdout):
223 code = d["code"]
227 code = d["code"]
224 data = d.get("data")
228 data = d.get("data")
225
229
226 if code == "error":
230 if code == "error":
227 # if this is the first time error happened
231 # if this is the first time error happened
228 # re-attempt getting the file
232 # re-attempt getting the file
229 if not lasterror:
233 if not lasterror:
230 lasterror = IOError(d["generic"], data)
234 lasterror = IOError(d["generic"], data)
231 # this will exit inner-most for-loop
235 # this will exit inner-most for-loop
232 break
236 break
233 else:
237 else:
234 raise lasterror
238 raise lasterror
235
239
236 elif code == "stat":
240 elif code == "stat":
237 action = d.get("action")
241 action = d.get("action")
238 if action in ["purge", "delete", "move/delete"]:
242 if action in ["purge", "delete", "move/delete"]:
239 return None, None
243 return None, None
240 p4type = self.re_type.match(d["type"])
244 p4type = self.re_type.match(d["type"])
241 if p4type:
245 if p4type:
242 mode = ""
246 mode = ""
243 flags = ((p4type.group(1) or "")
247 flags = ((p4type.group(1) or "")
244 + (p4type.group(3) or ""))
248 + (p4type.group(3) or ""))
245 if "x" in flags:
249 if "x" in flags:
246 mode = "x"
250 mode = "x"
247 if p4type.group(2) == "symlink":
251 if p4type.group(2) == "symlink":
248 mode = "l"
252 mode = "l"
249 if "ko" in flags:
253 if "ko" in flags:
250 keywords = self.re_keywords_old
254 keywords = self.re_keywords_old
251 elif "k" in flags:
255 elif "k" in flags:
252 keywords = self.re_keywords
256 keywords = self.re_keywords
253
257
254 elif code == "text" or code == "binary":
258 elif code == "text" or code == "binary":
255 contents.append(data)
259 contents.append(data)
256
260
257 lasterror = None
261 lasterror = None
258
262
259 if not lasterror:
263 if not lasterror:
260 break
264 break
261
265
262 if mode is None:
266 if mode is None:
263 return None, None
267 return None, None
264
268
265 contents = ''.join(contents)
269 contents = ''.join(contents)
266
270
267 if keywords:
271 if keywords:
268 contents = keywords.sub("$\\1$", contents)
272 contents = keywords.sub("$\\1$", contents)
269 if mode == "l" and contents.endswith("\n"):
273 if mode == "l" and contents.endswith("\n"):
270 contents = contents[:-1]
274 contents = contents[:-1]
271
275
272 return contents, mode
276 return contents, mode
273
277
274 def getchanges(self, rev, full):
278 def getchanges(self, rev, full):
275 if full:
279 if full:
276 raise util.Abort(_("convert from p4 do not support --full"))
280 raise util.Abort(_("convert from p4 do not support --full"))
277 return self.files[rev], self.copies[rev], set()
281 return self.files[rev], self.copies[rev], set()
278
282
279 def getcommit(self, rev):
283 def getcommit(self, rev):
280 return self.changeset[rev]
284 return self.changeset[rev]
281
285
282 def gettags(self):
286 def gettags(self):
283 return self.tags
287 return self.tags
284
288
285 def getchangedfiles(self, rev, i):
289 def getchangedfiles(self, rev, i):
286 return sorted([x[0] for x in self.files[rev]])
290 return sorted([x[0] for x in self.files[rev]])
@@ -1,529 +1,532 b''
1 $ cat >> $HGRCPATH <<EOF
1 $ cat >> $HGRCPATH <<EOF
2 > [extensions]
2 > [extensions]
3 > convert=
3 > convert=
4 > [convert]
4 > [convert]
5 > hg.saverev=False
5 > hg.saverev=False
6 > EOF
6 > EOF
7 $ hg help convert
7 $ hg help convert
8 hg convert [OPTION]... SOURCE [DEST [REVMAP]]
8 hg convert [OPTION]... SOURCE [DEST [REVMAP]]
9
9
10 convert a foreign SCM repository to a Mercurial one.
10 convert a foreign SCM repository to a Mercurial one.
11
11
12 Accepted source formats [identifiers]:
12 Accepted source formats [identifiers]:
13
13
14 - Mercurial [hg]
14 - Mercurial [hg]
15 - CVS [cvs]
15 - CVS [cvs]
16 - Darcs [darcs]
16 - Darcs [darcs]
17 - git [git]
17 - git [git]
18 - Subversion [svn]
18 - Subversion [svn]
19 - Monotone [mtn]
19 - Monotone [mtn]
20 - GNU Arch [gnuarch]
20 - GNU Arch [gnuarch]
21 - Bazaar [bzr]
21 - Bazaar [bzr]
22 - Perforce [p4]
22 - Perforce [p4]
23
23
24 Accepted destination formats [identifiers]:
24 Accepted destination formats [identifiers]:
25
25
26 - Mercurial [hg]
26 - Mercurial [hg]
27 - Subversion [svn] (history on branches is not preserved)
27 - Subversion [svn] (history on branches is not preserved)
28
28
29 If no revision is given, all revisions will be converted. Otherwise,
29 If no revision is given, all revisions will be converted. Otherwise,
30 convert will only import up to the named revision (given in a format
30 convert will only import up to the named revision (given in a format
31 understood by the source).
31 understood by the source).
32
32
33 If no destination directory name is specified, it defaults to the basename
33 If no destination directory name is specified, it defaults to the basename
34 of the source with "-hg" appended. If the destination repository doesn't
34 of the source with "-hg" appended. If the destination repository doesn't
35 exist, it will be created.
35 exist, it will be created.
36
36
37 By default, all sources except Mercurial will use --branchsort. Mercurial
37 By default, all sources except Mercurial will use --branchsort. Mercurial
38 uses --sourcesort to preserve original revision numbers order. Sort modes
38 uses --sourcesort to preserve original revision numbers order. Sort modes
39 have the following effects:
39 have the following effects:
40
40
41 --branchsort convert from parent to child revision when possible, which
41 --branchsort convert from parent to child revision when possible, which
42 means branches are usually converted one after the other.
42 means branches are usually converted one after the other.
43 It generates more compact repositories.
43 It generates more compact repositories.
44 --datesort sort revisions by date. Converted repositories have good-
44 --datesort sort revisions by date. Converted repositories have good-
45 looking changelogs but are often an order of magnitude
45 looking changelogs but are often an order of magnitude
46 larger than the same ones generated by --branchsort.
46 larger than the same ones generated by --branchsort.
47 --sourcesort try to preserve source revisions order, only supported by
47 --sourcesort try to preserve source revisions order, only supported by
48 Mercurial sources.
48 Mercurial sources.
49 --closesort try to move closed revisions as close as possible to parent
49 --closesort try to move closed revisions as close as possible to parent
50 branches, only supported by Mercurial sources.
50 branches, only supported by Mercurial sources.
51
51
52 If "REVMAP" isn't given, it will be put in a default location
52 If "REVMAP" isn't given, it will be put in a default location
53 ("<dest>/.hg/shamap" by default). The "REVMAP" is a simple text file that
53 ("<dest>/.hg/shamap" by default). The "REVMAP" is a simple text file that
54 maps each source commit ID to the destination ID for that revision, like
54 maps each source commit ID to the destination ID for that revision, like
55 so:
55 so:
56
56
57 <source ID> <destination ID>
57 <source ID> <destination ID>
58
58
59 If the file doesn't exist, it's automatically created. It's updated on
59 If the file doesn't exist, it's automatically created. It's updated on
60 each commit copied, so "hg convert" can be interrupted and can be run
60 each commit copied, so "hg convert" can be interrupted and can be run
61 repeatedly to copy new commits.
61 repeatedly to copy new commits.
62
62
63 The authormap is a simple text file that maps each source commit author to
63 The authormap is a simple text file that maps each source commit author to
64 a destination commit author. It is handy for source SCMs that use unix
64 a destination commit author. It is handy for source SCMs that use unix
65 logins to identify authors (e.g.: CVS). One line per author mapping and
65 logins to identify authors (e.g.: CVS). One line per author mapping and
66 the line format is:
66 the line format is:
67
67
68 source author = destination author
68 source author = destination author
69
69
70 Empty lines and lines starting with a "#" are ignored.
70 Empty lines and lines starting with a "#" are ignored.
71
71
72 The filemap is a file that allows filtering and remapping of files and
72 The filemap is a file that allows filtering and remapping of files and
73 directories. Each line can contain one of the following directives:
73 directories. Each line can contain one of the following directives:
74
74
75 include path/to/file-or-dir
75 include path/to/file-or-dir
76
76
77 exclude path/to/file-or-dir
77 exclude path/to/file-or-dir
78
78
79 rename path/to/source path/to/destination
79 rename path/to/source path/to/destination
80
80
81 Comment lines start with "#". A specified path matches if it equals the
81 Comment lines start with "#". A specified path matches if it equals the
82 full relative name of a file or one of its parent directories. The
82 full relative name of a file or one of its parent directories. The
83 "include" or "exclude" directive with the longest matching path applies,
83 "include" or "exclude" directive with the longest matching path applies,
84 so line order does not matter.
84 so line order does not matter.
85
85
86 The "include" directive causes a file, or all files under a directory, to
86 The "include" directive causes a file, or all files under a directory, to
87 be included in the destination repository. The default if there are no
87 be included in the destination repository. The default if there are no
88 "include" statements is to include everything. If there are any "include"
88 "include" statements is to include everything. If there are any "include"
89 statements, nothing else is included. The "exclude" directive causes files
89 statements, nothing else is included. The "exclude" directive causes files
90 or directories to be omitted. The "rename" directive renames a file or
90 or directories to be omitted. The "rename" directive renames a file or
91 directory if it is converted. To rename from a subdirectory into the root
91 directory if it is converted. To rename from a subdirectory into the root
92 of the repository, use "." as the path to rename to.
92 of the repository, use "." as the path to rename to.
93
93
94 "--full" will make sure the converted changesets contain exactly the right
94 "--full" will make sure the converted changesets contain exactly the right
95 files with the right content. It will make a full conversion of all files,
95 files with the right content. It will make a full conversion of all files,
96 not just the ones that have changed. Files that already are correct will
96 not just the ones that have changed. Files that already are correct will
97 not be changed. This can be used to apply filemap changes when converting
97 not be changed. This can be used to apply filemap changes when converting
98 incrementally. This is currently only supported for Mercurial and
98 incrementally. This is currently only supported for Mercurial and
99 Subversion.
99 Subversion.
100
100
101 The splicemap is a file that allows insertion of synthetic history,
101 The splicemap is a file that allows insertion of synthetic history,
102 letting you specify the parents of a revision. This is useful if you want
102 letting you specify the parents of a revision. This is useful if you want
103 to e.g. give a Subversion merge two parents, or graft two disconnected
103 to e.g. give a Subversion merge two parents, or graft two disconnected
104 series of history together. Each entry contains a key, followed by a
104 series of history together. Each entry contains a key, followed by a
105 space, followed by one or two comma-separated values:
105 space, followed by one or two comma-separated values:
106
106
107 key parent1, parent2
107 key parent1, parent2
108
108
109 The key is the revision ID in the source revision control system whose
109 The key is the revision ID in the source revision control system whose
110 parents should be modified (same format as a key in .hg/shamap). The
110 parents should be modified (same format as a key in .hg/shamap). The
111 values are the revision IDs (in either the source or destination revision
111 values are the revision IDs (in either the source or destination revision
112 control system) that should be used as the new parents for that node. For
112 control system) that should be used as the new parents for that node. For
113 example, if you have merged "release-1.0" into "trunk", then you should
113 example, if you have merged "release-1.0" into "trunk", then you should
114 specify the revision on "trunk" as the first parent and the one on the
114 specify the revision on "trunk" as the first parent and the one on the
115 "release-1.0" branch as the second.
115 "release-1.0" branch as the second.
116
116
117 The branchmap is a file that allows you to rename a branch when it is
117 The branchmap is a file that allows you to rename a branch when it is
118 being brought in from whatever external repository. When used in
118 being brought in from whatever external repository. When used in
119 conjunction with a splicemap, it allows for a powerful combination to help
119 conjunction with a splicemap, it allows for a powerful combination to help
120 fix even the most badly mismanaged repositories and turn them into nicely
120 fix even the most badly mismanaged repositories and turn them into nicely
121 structured Mercurial repositories. The branchmap contains lines of the
121 structured Mercurial repositories. The branchmap contains lines of the
122 form:
122 form:
123
123
124 original_branch_name new_branch_name
124 original_branch_name new_branch_name
125
125
126 where "original_branch_name" is the name of the branch in the source
126 where "original_branch_name" is the name of the branch in the source
127 repository, and "new_branch_name" is the name of the branch is the
127 repository, and "new_branch_name" is the name of the branch is the
128 destination repository. No whitespace is allowed in the branch names. This
128 destination repository. No whitespace is allowed in the branch names. This
129 can be used to (for instance) move code in one repository from "default"
129 can be used to (for instance) move code in one repository from "default"
130 to a named branch.
130 to a named branch.
131
131
132 Mercurial Source
132 Mercurial Source
133 ################
133 ################
134
134
135 The Mercurial source recognizes the following configuration options, which
135 The Mercurial source recognizes the following configuration options, which
136 you can set on the command line with "--config":
136 you can set on the command line with "--config":
137
137
138 convert.hg.ignoreerrors
138 convert.hg.ignoreerrors
139 ignore integrity errors when reading. Use it to fix
139 ignore integrity errors when reading. Use it to fix
140 Mercurial repositories with missing revlogs, by converting
140 Mercurial repositories with missing revlogs, by converting
141 from and to Mercurial. Default is False.
141 from and to Mercurial. Default is False.
142 convert.hg.saverev
142 convert.hg.saverev
143 store original revision ID in changeset (forces target IDs
143 store original revision ID in changeset (forces target IDs
144 to change). It takes a boolean argument and defaults to
144 to change). It takes a boolean argument and defaults to
145 False.
145 False.
146 convert.hg.startrev
146 convert.hg.startrev
147 specify the initial Mercurial revision. The default is 0.
147 specify the initial Mercurial revision. The default is 0.
148 convert.hg.revs
148 convert.hg.revs
149 revset specifying the source revisions to convert.
149 revset specifying the source revisions to convert.
150
150
151 CVS Source
151 CVS Source
152 ##########
152 ##########
153
153
154 CVS source will use a sandbox (i.e. a checked-out copy) from CVS to
154 CVS source will use a sandbox (i.e. a checked-out copy) from CVS to
155 indicate the starting point of what will be converted. Direct access to
155 indicate the starting point of what will be converted. Direct access to
156 the repository files is not needed, unless of course the repository is
156 the repository files is not needed, unless of course the repository is
157 ":local:". The conversion uses the top level directory in the sandbox to
157 ":local:". The conversion uses the top level directory in the sandbox to
158 find the CVS repository, and then uses CVS rlog commands to find files to
158 find the CVS repository, and then uses CVS rlog commands to find files to
159 convert. This means that unless a filemap is given, all files under the
159 convert. This means that unless a filemap is given, all files under the
160 starting directory will be converted, and that any directory
160 starting directory will be converted, and that any directory
161 reorganization in the CVS sandbox is ignored.
161 reorganization in the CVS sandbox is ignored.
162
162
163 The following options can be used with "--config":
163 The following options can be used with "--config":
164
164
165 convert.cvsps.cache
165 convert.cvsps.cache
166 Set to False to disable remote log caching, for testing and
166 Set to False to disable remote log caching, for testing and
167 debugging purposes. Default is True.
167 debugging purposes. Default is True.
168 convert.cvsps.fuzz
168 convert.cvsps.fuzz
169 Specify the maximum time (in seconds) that is allowed
169 Specify the maximum time (in seconds) that is allowed
170 between commits with identical user and log message in a
170 between commits with identical user and log message in a
171 single changeset. When very large files were checked in as
171 single changeset. When very large files were checked in as
172 part of a changeset then the default may not be long enough.
172 part of a changeset then the default may not be long enough.
173 The default is 60.
173 The default is 60.
174 convert.cvsps.mergeto
174 convert.cvsps.mergeto
175 Specify a regular expression to which commit log messages
175 Specify a regular expression to which commit log messages
176 are matched. If a match occurs, then the conversion process
176 are matched. If a match occurs, then the conversion process
177 will insert a dummy revision merging the branch on which
177 will insert a dummy revision merging the branch on which
178 this log message occurs to the branch indicated in the
178 this log message occurs to the branch indicated in the
179 regex. Default is "{{mergetobranch ([-\w]+)}}"
179 regex. Default is "{{mergetobranch ([-\w]+)}}"
180 convert.cvsps.mergefrom
180 convert.cvsps.mergefrom
181 Specify a regular expression to which commit log messages
181 Specify a regular expression to which commit log messages
182 are matched. If a match occurs, then the conversion process
182 are matched. If a match occurs, then the conversion process
183 will add the most recent revision on the branch indicated in
183 will add the most recent revision on the branch indicated in
184 the regex as the second parent of the changeset. Default is
184 the regex as the second parent of the changeset. Default is
185 "{{mergefrombranch ([-\w]+)}}"
185 "{{mergefrombranch ([-\w]+)}}"
186 convert.localtimezone
186 convert.localtimezone
187 use local time (as determined by the TZ environment
187 use local time (as determined by the TZ environment
188 variable) for changeset date/times. The default is False
188 variable) for changeset date/times. The default is False
189 (use UTC).
189 (use UTC).
190 hooks.cvslog Specify a Python function to be called at the end of
190 hooks.cvslog Specify a Python function to be called at the end of
191 gathering the CVS log. The function is passed a list with
191 gathering the CVS log. The function is passed a list with
192 the log entries, and can modify the entries in-place, or add
192 the log entries, and can modify the entries in-place, or add
193 or delete them.
193 or delete them.
194 hooks.cvschangesets
194 hooks.cvschangesets
195 Specify a Python function to be called after the changesets
195 Specify a Python function to be called after the changesets
196 are calculated from the CVS log. The function is passed a
196 are calculated from the CVS log. The function is passed a
197 list with the changeset entries, and can modify the
197 list with the changeset entries, and can modify the
198 changesets in-place, or add or delete them.
198 changesets in-place, or add or delete them.
199
199
200 An additional "debugcvsps" Mercurial command allows the builtin changeset
200 An additional "debugcvsps" Mercurial command allows the builtin changeset
201 merging code to be run without doing a conversion. Its parameters and
201 merging code to be run without doing a conversion. Its parameters and
202 output are similar to that of cvsps 2.1. Please see the command help for
202 output are similar to that of cvsps 2.1. Please see the command help for
203 more details.
203 more details.
204
204
205 Subversion Source
205 Subversion Source
206 #################
206 #################
207
207
208 Subversion source detects classical trunk/branches/tags layouts. By
208 Subversion source detects classical trunk/branches/tags layouts. By
209 default, the supplied "svn://repo/path/" source URL is converted as a
209 default, the supplied "svn://repo/path/" source URL is converted as a
210 single branch. If "svn://repo/path/trunk" exists it replaces the default
210 single branch. If "svn://repo/path/trunk" exists it replaces the default
211 branch. If "svn://repo/path/branches" exists, its subdirectories are
211 branch. If "svn://repo/path/branches" exists, its subdirectories are
212 listed as possible branches. If "svn://repo/path/tags" exists, it is
212 listed as possible branches. If "svn://repo/path/tags" exists, it is
213 looked for tags referencing converted branches. Default "trunk",
213 looked for tags referencing converted branches. Default "trunk",
214 "branches" and "tags" values can be overridden with following options. Set
214 "branches" and "tags" values can be overridden with following options. Set
215 them to paths relative to the source URL, or leave them blank to disable
215 them to paths relative to the source URL, or leave them blank to disable
216 auto detection.
216 auto detection.
217
217
218 The following options can be set with "--config":
218 The following options can be set with "--config":
219
219
220 convert.svn.branches
220 convert.svn.branches
221 specify the directory containing branches. The default is
221 specify the directory containing branches. The default is
222 "branches".
222 "branches".
223 convert.svn.tags
223 convert.svn.tags
224 specify the directory containing tags. The default is
224 specify the directory containing tags. The default is
225 "tags".
225 "tags".
226 convert.svn.trunk
226 convert.svn.trunk
227 specify the name of the trunk branch. The default is
227 specify the name of the trunk branch. The default is
228 "trunk".
228 "trunk".
229 convert.localtimezone
229 convert.localtimezone
230 use local time (as determined by the TZ environment
230 use local time (as determined by the TZ environment
231 variable) for changeset date/times. The default is False
231 variable) for changeset date/times. The default is False
232 (use UTC).
232 (use UTC).
233
233
234 Source history can be retrieved starting at a specific revision, instead
234 Source history can be retrieved starting at a specific revision, instead
235 of being integrally converted. Only single branch conversions are
235 of being integrally converted. Only single branch conversions are
236 supported.
236 supported.
237
237
238 convert.svn.startrev
238 convert.svn.startrev
239 specify start Subversion revision number. The default is 0.
239 specify start Subversion revision number. The default is 0.
240
240
241 Git Source
241 Git Source
242 ##########
242 ##########
243
243
244 The Git importer converts commits from all reachable branches (refs in
244 The Git importer converts commits from all reachable branches (refs in
245 refs/heads) and remotes (refs in refs/remotes) to Mercurial. Branches are
245 refs/heads) and remotes (refs in refs/remotes) to Mercurial. Branches are
246 converted to bookmarks with the same name, with the leading 'refs/heads'
246 converted to bookmarks with the same name, with the leading 'refs/heads'
247 stripped. Git submodules are converted to Git subrepos in Mercurial.
247 stripped. Git submodules are converted to Git subrepos in Mercurial.
248
248
249 The following options can be set with "--config":
249 The following options can be set with "--config":
250
250
251 convert.git.similarity
251 convert.git.similarity
252 specify how similar files modified in a commit must be to be
252 specify how similar files modified in a commit must be to be
253 imported as renames or copies, as a percentage between "0"
253 imported as renames or copies, as a percentage between "0"
254 (disabled) and "100" (files must be identical). For example,
254 (disabled) and "100" (files must be identical). For example,
255 "90" means that a delete/add pair will be imported as a
255 "90" means that a delete/add pair will be imported as a
256 rename if more than 90% of the file hasn't changed. The
256 rename if more than 90% of the file hasn't changed. The
257 default is "50".
257 default is "50".
258 convert.git.findcopiesharder
258 convert.git.findcopiesharder
259 while detecting copies, look at all files in the working
259 while detecting copies, look at all files in the working
260 copy instead of just changed ones. This is very expensive
260 copy instead of just changed ones. This is very expensive
261 for large projects, and is only effective when
261 for large projects, and is only effective when
262 "convert.git.similarity" is greater than 0. The default is
262 "convert.git.similarity" is greater than 0. The default is
263 False.
263 False.
264 convert.git.remoteprefix
264 convert.git.remoteprefix
265 remote refs are converted as bookmarks with
265 remote refs are converted as bookmarks with
266 "convert.git.remoteprefix" as a prefix followed by a /. The
266 "convert.git.remoteprefix" as a prefix followed by a /. The
267 default is 'remote'.
267 default is 'remote'.
268
268
269 Perforce Source
269 Perforce Source
270 ###############
270 ###############
271
271
272 The Perforce (P4) importer can be given a p4 depot path or a client
272 The Perforce (P4) importer can be given a p4 depot path or a client
273 specification as source. It will convert all files in the source to a flat
273 specification as source. It will convert all files in the source to a flat
274 Mercurial repository, ignoring labels, branches and integrations. Note
274 Mercurial repository, ignoring labels, branches and integrations. Note
275 that when a depot path is given you then usually should specify a target
275 that when a depot path is given you then usually should specify a target
276 directory, because otherwise the target may be named "...-hg".
276 directory, because otherwise the target may be named "...-hg".
277
277
278 It is possible to limit the amount of source history to be converted by
278 The following options can be set with "--config":
279 specifying an initial Perforce revision:
280
279
280 convert.p4.encoding
281 specify the encoding to use when decoding standard output of
282 the Perforce command line tool. The default is default
283 system encoding.
281 convert.p4.startrev
284 convert.p4.startrev
282 specify initial Perforce revision (a Perforce changelist
285 specify initial Perforce revision (a Perforce changelist
283 number).
286 number).
284
287
285 Mercurial Destination
288 Mercurial Destination
286 #####################
289 #####################
287
290
288 The Mercurial destination will recognize Mercurial subrepositories in the
291 The Mercurial destination will recognize Mercurial subrepositories in the
289 destination directory, and update the .hgsubstate file automatically if
292 destination directory, and update the .hgsubstate file automatically if
290 the destination subrepositories contain the <dest>/<sub>/.hg/shamap file.
293 the destination subrepositories contain the <dest>/<sub>/.hg/shamap file.
291 Converting a repository with subrepositories requires converting a single
294 Converting a repository with subrepositories requires converting a single
292 repository at a time, from the bottom up.
295 repository at a time, from the bottom up.
293
296
294 The following options are supported:
297 The following options are supported:
295
298
296 convert.hg.clonebranches
299 convert.hg.clonebranches
297 dispatch source branches in separate clones. The default is
300 dispatch source branches in separate clones. The default is
298 False.
301 False.
299 convert.hg.tagsbranch
302 convert.hg.tagsbranch
300 branch name for tag revisions, defaults to "default".
303 branch name for tag revisions, defaults to "default".
301 convert.hg.usebranchnames
304 convert.hg.usebranchnames
302 preserve branch names. The default is True.
305 preserve branch names. The default is True.
303 convert.hg.sourcename
306 convert.hg.sourcename
304 records the given string as a 'convert_source' extra value
307 records the given string as a 'convert_source' extra value
305 on each commit made in the target repository. The default is
308 on each commit made in the target repository. The default is
306 None.
309 None.
307
310
308 All Destinations
311 All Destinations
309 ################
312 ################
310
313
311 All destination types accept the following options:
314 All destination types accept the following options:
312
315
313 convert.skiptags
316 convert.skiptags
314 does not convert tags from the source repo to the target
317 does not convert tags from the source repo to the target
315 repo. The default is False.
318 repo. The default is False.
316
319
317 options ([+] can be repeated):
320 options ([+] can be repeated):
318
321
319 -s --source-type TYPE source repository type
322 -s --source-type TYPE source repository type
320 -d --dest-type TYPE destination repository type
323 -d --dest-type TYPE destination repository type
321 -r --rev REV [+] import up to source revision REV
324 -r --rev REV [+] import up to source revision REV
322 -A --authormap FILE remap usernames using this file
325 -A --authormap FILE remap usernames using this file
323 --filemap FILE remap file names using contents of file
326 --filemap FILE remap file names using contents of file
324 --full apply filemap changes by converting all files again
327 --full apply filemap changes by converting all files again
325 --splicemap FILE splice synthesized history into place
328 --splicemap FILE splice synthesized history into place
326 --branchmap FILE change branch names while converting
329 --branchmap FILE change branch names while converting
327 --branchsort try to sort changesets by branches
330 --branchsort try to sort changesets by branches
328 --datesort try to sort changesets by date
331 --datesort try to sort changesets by date
329 --sourcesort preserve source changesets order
332 --sourcesort preserve source changesets order
330 --closesort try to reorder closed revisions
333 --closesort try to reorder closed revisions
331
334
332 (some details hidden, use --verbose to show complete help)
335 (some details hidden, use --verbose to show complete help)
333 $ hg init a
336 $ hg init a
334 $ cd a
337 $ cd a
335 $ echo a > a
338 $ echo a > a
336 $ hg ci -d'0 0' -Ama
339 $ hg ci -d'0 0' -Ama
337 adding a
340 adding a
338 $ hg cp a b
341 $ hg cp a b
339 $ hg ci -d'1 0' -mb
342 $ hg ci -d'1 0' -mb
340 $ hg rm a
343 $ hg rm a
341 $ hg ci -d'2 0' -mc
344 $ hg ci -d'2 0' -mc
342 $ hg mv b a
345 $ hg mv b a
343 $ hg ci -d'3 0' -md
346 $ hg ci -d'3 0' -md
344 $ echo a >> a
347 $ echo a >> a
345 $ hg ci -d'4 0' -me
348 $ hg ci -d'4 0' -me
346 $ cd ..
349 $ cd ..
347 $ hg convert a 2>&1 | grep -v 'subversion python bindings could not be loaded'
350 $ hg convert a 2>&1 | grep -v 'subversion python bindings could not be loaded'
348 assuming destination a-hg
351 assuming destination a-hg
349 initializing destination a-hg repository
352 initializing destination a-hg repository
350 scanning source...
353 scanning source...
351 sorting...
354 sorting...
352 converting...
355 converting...
353 4 a
356 4 a
354 3 b
357 3 b
355 2 c
358 2 c
356 1 d
359 1 d
357 0 e
360 0 e
358 $ hg --cwd a-hg pull ../a
361 $ hg --cwd a-hg pull ../a
359 pulling from ../a
362 pulling from ../a
360 searching for changes
363 searching for changes
361 no changes found
364 no changes found
362
365
363 conversion to existing file should fail
366 conversion to existing file should fail
364
367
365 $ touch bogusfile
368 $ touch bogusfile
366 $ hg convert a bogusfile
369 $ hg convert a bogusfile
367 initializing destination bogusfile repository
370 initializing destination bogusfile repository
368 abort: cannot create new bundle repository
371 abort: cannot create new bundle repository
369 [255]
372 [255]
370
373
371 #if unix-permissions no-root
374 #if unix-permissions no-root
372
375
373 conversion to dir without permissions should fail
376 conversion to dir without permissions should fail
374
377
375 $ mkdir bogusdir
378 $ mkdir bogusdir
376 $ chmod 000 bogusdir
379 $ chmod 000 bogusdir
377
380
378 $ hg convert a bogusdir
381 $ hg convert a bogusdir
379 abort: Permission denied: 'bogusdir'
382 abort: Permission denied: 'bogusdir'
380 [255]
383 [255]
381
384
382 user permissions should succeed
385 user permissions should succeed
383
386
384 $ chmod 700 bogusdir
387 $ chmod 700 bogusdir
385 $ hg convert a bogusdir
388 $ hg convert a bogusdir
386 initializing destination bogusdir repository
389 initializing destination bogusdir repository
387 scanning source...
390 scanning source...
388 sorting...
391 sorting...
389 converting...
392 converting...
390 4 a
393 4 a
391 3 b
394 3 b
392 2 c
395 2 c
393 1 d
396 1 d
394 0 e
397 0 e
395
398
396 #endif
399 #endif
397
400
398 test pre and post conversion actions
401 test pre and post conversion actions
399
402
400 $ echo 'include b' > filemap
403 $ echo 'include b' > filemap
401 $ hg convert --debug --filemap filemap a partialb | \
404 $ hg convert --debug --filemap filemap a partialb | \
402 > grep 'run hg'
405 > grep 'run hg'
403 run hg source pre-conversion action
406 run hg source pre-conversion action
404 run hg sink pre-conversion action
407 run hg sink pre-conversion action
405 run hg sink post-conversion action
408 run hg sink post-conversion action
406 run hg source post-conversion action
409 run hg source post-conversion action
407
410
408 converting empty dir should fail "nicely
411 converting empty dir should fail "nicely
409
412
410 $ mkdir emptydir
413 $ mkdir emptydir
411
414
412 override $PATH to ensure p4 not visible; use $PYTHON in case we're
415 override $PATH to ensure p4 not visible; use $PYTHON in case we're
413 running from a devel copy, not a temp installation
416 running from a devel copy, not a temp installation
414
417
415 $ PATH="$BINDIR" $PYTHON "$BINDIR"/hg convert emptydir
418 $ PATH="$BINDIR" $PYTHON "$BINDIR"/hg convert emptydir
416 assuming destination emptydir-hg
419 assuming destination emptydir-hg
417 initializing destination emptydir-hg repository
420 initializing destination emptydir-hg repository
418 emptydir does not look like a CVS checkout
421 emptydir does not look like a CVS checkout
419 emptydir does not look like a Git repository
422 emptydir does not look like a Git repository
420 emptydir does not look like a Subversion repository
423 emptydir does not look like a Subversion repository
421 emptydir is not a local Mercurial repository
424 emptydir is not a local Mercurial repository
422 emptydir does not look like a darcs repository
425 emptydir does not look like a darcs repository
423 emptydir does not look like a monotone repository
426 emptydir does not look like a monotone repository
424 emptydir does not look like a GNU Arch repository
427 emptydir does not look like a GNU Arch repository
425 emptydir does not look like a Bazaar repository
428 emptydir does not look like a Bazaar repository
426 cannot find required "p4" tool
429 cannot find required "p4" tool
427 abort: emptydir: missing or unsupported repository
430 abort: emptydir: missing or unsupported repository
428 [255]
431 [255]
429
432
430 convert with imaginary source type
433 convert with imaginary source type
431
434
432 $ hg convert --source-type foo a a-foo
435 $ hg convert --source-type foo a a-foo
433 initializing destination a-foo repository
436 initializing destination a-foo repository
434 abort: foo: invalid source repository type
437 abort: foo: invalid source repository type
435 [255]
438 [255]
436
439
437 convert with imaginary sink type
440 convert with imaginary sink type
438
441
439 $ hg convert --dest-type foo a a-foo
442 $ hg convert --dest-type foo a a-foo
440 abort: foo: invalid destination repository type
443 abort: foo: invalid destination repository type
441 [255]
444 [255]
442
445
443 testing: convert must not produce duplicate entries in fncache
446 testing: convert must not produce duplicate entries in fncache
444
447
445 $ hg convert a b
448 $ hg convert a b
446 initializing destination b repository
449 initializing destination b repository
447 scanning source...
450 scanning source...
448 sorting...
451 sorting...
449 converting...
452 converting...
450 4 a
453 4 a
451 3 b
454 3 b
452 2 c
455 2 c
453 1 d
456 1 d
454 0 e
457 0 e
455
458
456 contents of fncache file:
459 contents of fncache file:
457
460
458 $ cat b/.hg/store/fncache | sort
461 $ cat b/.hg/store/fncache | sort
459 data/a.i
462 data/a.i
460 data/b.i
463 data/b.i
461
464
462 test bogus URL
465 test bogus URL
463
466
464 $ hg convert -q bzr+ssh://foobar@selenic.com/baz baz
467 $ hg convert -q bzr+ssh://foobar@selenic.com/baz baz
465 abort: bzr+ssh://foobar@selenic.com/baz: missing or unsupported repository
468 abort: bzr+ssh://foobar@selenic.com/baz: missing or unsupported repository
466 [255]
469 [255]
467
470
468 test revset converted() lookup
471 test revset converted() lookup
469
472
470 $ hg --config convert.hg.saverev=True convert a c
473 $ hg --config convert.hg.saverev=True convert a c
471 initializing destination c repository
474 initializing destination c repository
472 scanning source...
475 scanning source...
473 sorting...
476 sorting...
474 converting...
477 converting...
475 4 a
478 4 a
476 3 b
479 3 b
477 2 c
480 2 c
478 1 d
481 1 d
479 0 e
482 0 e
480 $ echo f > c/f
483 $ echo f > c/f
481 $ hg -R c ci -d'0 0' -Amf
484 $ hg -R c ci -d'0 0' -Amf
482 adding f
485 adding f
483 created new head
486 created new head
484 $ hg -R c log -r "converted(09d945a62ce6)"
487 $ hg -R c log -r "converted(09d945a62ce6)"
485 changeset: 1:98c3dd46a874
488 changeset: 1:98c3dd46a874
486 user: test
489 user: test
487 date: Thu Jan 01 00:00:01 1970 +0000
490 date: Thu Jan 01 00:00:01 1970 +0000
488 summary: b
491 summary: b
489
492
490 $ hg -R c log -r "converted()"
493 $ hg -R c log -r "converted()"
491 changeset: 0:31ed57b2037c
494 changeset: 0:31ed57b2037c
492 user: test
495 user: test
493 date: Thu Jan 01 00:00:00 1970 +0000
496 date: Thu Jan 01 00:00:00 1970 +0000
494 summary: a
497 summary: a
495
498
496 changeset: 1:98c3dd46a874
499 changeset: 1:98c3dd46a874
497 user: test
500 user: test
498 date: Thu Jan 01 00:00:01 1970 +0000
501 date: Thu Jan 01 00:00:01 1970 +0000
499 summary: b
502 summary: b
500
503
501 changeset: 2:3b9ca06ef716
504 changeset: 2:3b9ca06ef716
502 user: test
505 user: test
503 date: Thu Jan 01 00:00:02 1970 +0000
506 date: Thu Jan 01 00:00:02 1970 +0000
504 summary: c
507 summary: c
505
508
506 changeset: 3:4e0debd37cf2
509 changeset: 3:4e0debd37cf2
507 user: test
510 user: test
508 date: Thu Jan 01 00:00:03 1970 +0000
511 date: Thu Jan 01 00:00:03 1970 +0000
509 summary: d
512 summary: d
510
513
511 changeset: 4:9de3bc9349c5
514 changeset: 4:9de3bc9349c5
512 user: test
515 user: test
513 date: Thu Jan 01 00:00:04 1970 +0000
516 date: Thu Jan 01 00:00:04 1970 +0000
514 summary: e
517 summary: e
515
518
516
519
517 test specifying a sourcename
520 test specifying a sourcename
518 $ echo g > a/g
521 $ echo g > a/g
519 $ hg -R a ci -d'0 0' -Amg
522 $ hg -R a ci -d'0 0' -Amg
520 adding g
523 adding g
521 $ hg --config convert.hg.sourcename=mysource --config convert.hg.saverev=True convert a c
524 $ hg --config convert.hg.sourcename=mysource --config convert.hg.saverev=True convert a c
522 scanning source...
525 scanning source...
523 sorting...
526 sorting...
524 converting...
527 converting...
525 0 g
528 0 g
526 $ hg -R c log -r tip --template '{extras % "{extra}\n"}'
529 $ hg -R c log -r tip --template '{extras % "{extra}\n"}'
527 branch=default
530 branch=default
528 convert_revision=a3bc6100aa8ec03e00aaf271f1f50046fb432072
531 convert_revision=a3bc6100aa8ec03e00aaf271f1f50046fb432072
529 convert_source=mysource
532 convert_source=mysource
General Comments 0
You need to be logged in to leave comments. Login now