##// END OF EJS Templates
convert: option to set date and time for svn commits...
Nikita Slyusarev -
r47129:7525e77b default
parent child Browse files
Show More
@@ -1,587 +1,603 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 from __future__ import absolute_import
10 from __future__ import absolute_import
11
11
12 from mercurial.i18n import _
12 from mercurial.i18n import _
13 from mercurial import registrar
13 from mercurial import registrar
14
14
15 from . import (
15 from . import (
16 convcmd,
16 convcmd,
17 cvsps,
17 cvsps,
18 subversion,
18 subversion,
19 )
19 )
20
20
21 cmdtable = {}
21 cmdtable = {}
22 command = registrar.command(cmdtable)
22 command = registrar.command(cmdtable)
23 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
23 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
24 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
24 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
25 # be specifying the version(s) of Mercurial they are tested with, or
25 # be specifying the version(s) of Mercurial they are tested with, or
26 # leave the attribute unspecified.
26 # leave the attribute unspecified.
27 testedwith = b'ships-with-hg-core'
27 testedwith = b'ships-with-hg-core'
28
28
29 # Commands definition was moved elsewhere to ease demandload job.
29 # Commands definition was moved elsewhere to ease demandload job.
30
30
31
31
32 @command(
32 @command(
33 b'convert',
33 b'convert',
34 [
34 [
35 (
35 (
36 b'',
36 b'',
37 b'authors',
37 b'authors',
38 b'',
38 b'',
39 _(
39 _(
40 b'username mapping filename (DEPRECATED) (use --authormap instead)'
40 b'username mapping filename (DEPRECATED) (use --authormap instead)'
41 ),
41 ),
42 _(b'FILE'),
42 _(b'FILE'),
43 ),
43 ),
44 (b's', b'source-type', b'', _(b'source repository type'), _(b'TYPE')),
44 (b's', b'source-type', b'', _(b'source repository type'), _(b'TYPE')),
45 (
45 (
46 b'd',
46 b'd',
47 b'dest-type',
47 b'dest-type',
48 b'',
48 b'',
49 _(b'destination repository type'),
49 _(b'destination repository type'),
50 _(b'TYPE'),
50 _(b'TYPE'),
51 ),
51 ),
52 (b'r', b'rev', [], _(b'import up to source revision REV'), _(b'REV')),
52 (b'r', b'rev', [], _(b'import up to source revision REV'), _(b'REV')),
53 (
53 (
54 b'A',
54 b'A',
55 b'authormap',
55 b'authormap',
56 b'',
56 b'',
57 _(b'remap usernames using this file'),
57 _(b'remap usernames using this file'),
58 _(b'FILE'),
58 _(b'FILE'),
59 ),
59 ),
60 (
60 (
61 b'',
61 b'',
62 b'filemap',
62 b'filemap',
63 b'',
63 b'',
64 _(b'remap file names using contents of file'),
64 _(b'remap file names using contents of file'),
65 _(b'FILE'),
65 _(b'FILE'),
66 ),
66 ),
67 (
67 (
68 b'',
68 b'',
69 b'full',
69 b'full',
70 None,
70 None,
71 _(b'apply filemap changes by converting all files again'),
71 _(b'apply filemap changes by converting all files again'),
72 ),
72 ),
73 (
73 (
74 b'',
74 b'',
75 b'splicemap',
75 b'splicemap',
76 b'',
76 b'',
77 _(b'splice synthesized history into place'),
77 _(b'splice synthesized history into place'),
78 _(b'FILE'),
78 _(b'FILE'),
79 ),
79 ),
80 (
80 (
81 b'',
81 b'',
82 b'branchmap',
82 b'branchmap',
83 b'',
83 b'',
84 _(b'change branch names while converting'),
84 _(b'change branch names while converting'),
85 _(b'FILE'),
85 _(b'FILE'),
86 ),
86 ),
87 (b'', b'branchsort', None, _(b'try to sort changesets by branches')),
87 (b'', b'branchsort', None, _(b'try to sort changesets by branches')),
88 (b'', b'datesort', None, _(b'try to sort changesets by date')),
88 (b'', b'datesort', None, _(b'try to sort changesets by date')),
89 (b'', b'sourcesort', None, _(b'preserve source changesets order')),
89 (b'', b'sourcesort', None, _(b'preserve source changesets order')),
90 (b'', b'closesort', None, _(b'try to reorder closed revisions')),
90 (b'', b'closesort', None, _(b'try to reorder closed revisions')),
91 ],
91 ],
92 _(b'hg convert [OPTION]... SOURCE [DEST [REVMAP]]'),
92 _(b'hg convert [OPTION]... SOURCE [DEST [REVMAP]]'),
93 norepo=True,
93 norepo=True,
94 )
94 )
95 def convert(ui, src, dest=None, revmapfile=None, **opts):
95 def convert(ui, src, dest=None, revmapfile=None, **opts):
96 """convert a foreign SCM repository to a Mercurial one.
96 """convert a foreign SCM repository to a Mercurial one.
97
97
98 Accepted source formats [identifiers]:
98 Accepted source formats [identifiers]:
99
99
100 - Mercurial [hg]
100 - Mercurial [hg]
101 - CVS [cvs]
101 - CVS [cvs]
102 - Darcs [darcs]
102 - Darcs [darcs]
103 - git [git]
103 - git [git]
104 - Subversion [svn]
104 - Subversion [svn]
105 - Monotone [mtn]
105 - Monotone [mtn]
106 - GNU Arch [gnuarch]
106 - GNU Arch [gnuarch]
107 - Bazaar [bzr]
107 - Bazaar [bzr]
108 - Perforce [p4]
108 - Perforce [p4]
109
109
110 Accepted destination formats [identifiers]:
110 Accepted destination formats [identifiers]:
111
111
112 - Mercurial [hg]
112 - Mercurial [hg]
113 - Subversion [svn] (history on branches is not preserved)
113 - Subversion [svn] (history on branches is not preserved)
114
114
115 If no revision is given, all revisions will be converted.
115 If no revision is given, all revisions will be converted.
116 Otherwise, convert will only import up to the named revision
116 Otherwise, convert will only import up to the named revision
117 (given in a format understood by the source).
117 (given in a format understood by the source).
118
118
119 If no destination directory name is specified, it defaults to the
119 If no destination directory name is specified, it defaults to the
120 basename of the source with ``-hg`` appended. If the destination
120 basename of the source with ``-hg`` appended. If the destination
121 repository doesn't exist, it will be created.
121 repository doesn't exist, it will be created.
122
122
123 By default, all sources except Mercurial will use --branchsort.
123 By default, all sources except Mercurial will use --branchsort.
124 Mercurial uses --sourcesort to preserve original revision numbers
124 Mercurial uses --sourcesort to preserve original revision numbers
125 order. Sort modes have the following effects:
125 order. Sort modes have the following effects:
126
126
127 --branchsort convert from parent to child revision when possible,
127 --branchsort convert from parent to child revision when possible,
128 which means branches are usually converted one after
128 which means branches are usually converted one after
129 the other. It generates more compact repositories.
129 the other. It generates more compact repositories.
130
130
131 --datesort sort revisions by date. Converted repositories have
131 --datesort sort revisions by date. Converted repositories have
132 good-looking changelogs but are often an order of
132 good-looking changelogs but are often an order of
133 magnitude larger than the same ones generated by
133 magnitude larger than the same ones generated by
134 --branchsort.
134 --branchsort.
135
135
136 --sourcesort try to preserve source revisions order, only
136 --sourcesort try to preserve source revisions order, only
137 supported by Mercurial sources.
137 supported by Mercurial sources.
138
138
139 --closesort try to move closed revisions as close as possible
139 --closesort try to move closed revisions as close as possible
140 to parent branches, only supported by Mercurial
140 to parent branches, only supported by Mercurial
141 sources.
141 sources.
142
142
143 If ``REVMAP`` isn't given, it will be put in a default location
143 If ``REVMAP`` isn't given, it will be put in a default location
144 (``<dest>/.hg/shamap`` by default). The ``REVMAP`` is a simple
144 (``<dest>/.hg/shamap`` by default). The ``REVMAP`` is a simple
145 text file that maps each source commit ID to the destination ID
145 text file that maps each source commit ID to the destination ID
146 for that revision, like so::
146 for that revision, like so::
147
147
148 <source ID> <destination ID>
148 <source ID> <destination ID>
149
149
150 If the file doesn't exist, it's automatically created. It's
150 If the file doesn't exist, it's automatically created. It's
151 updated on each commit copied, so :hg:`convert` can be interrupted
151 updated on each commit copied, so :hg:`convert` can be interrupted
152 and can be run repeatedly to copy new commits.
152 and can be run repeatedly to copy new commits.
153
153
154 The authormap is a simple text file that maps each source commit
154 The authormap is a simple text file that maps each source commit
155 author to a destination commit author. It is handy for source SCMs
155 author to a destination commit author. It is handy for source SCMs
156 that use unix logins to identify authors (e.g.: CVS). One line per
156 that use unix logins to identify authors (e.g.: CVS). One line per
157 author mapping and the line format is::
157 author mapping and the line format is::
158
158
159 source author = destination author
159 source author = destination author
160
160
161 Empty lines and lines starting with a ``#`` are ignored.
161 Empty lines and lines starting with a ``#`` are ignored.
162
162
163 The filemap is a file that allows filtering and remapping of files
163 The filemap is a file that allows filtering and remapping of files
164 and directories. Each line can contain one of the following
164 and directories. Each line can contain one of the following
165 directives::
165 directives::
166
166
167 include path/to/file-or-dir
167 include path/to/file-or-dir
168
168
169 exclude path/to/file-or-dir
169 exclude path/to/file-or-dir
170
170
171 rename path/to/source path/to/destination
171 rename path/to/source path/to/destination
172
172
173 Comment lines start with ``#``. A specified path matches if it
173 Comment lines start with ``#``. A specified path matches if it
174 equals the full relative name of a file or one of its parent
174 equals the full relative name of a file or one of its parent
175 directories. The ``include`` or ``exclude`` directive with the
175 directories. The ``include`` or ``exclude`` directive with the
176 longest matching path applies, so line order does not matter.
176 longest matching path applies, so line order does not matter.
177
177
178 The ``include`` directive causes a file, or all files under a
178 The ``include`` directive causes a file, or all files under a
179 directory, to be included in the destination repository. The default
179 directory, to be included in the destination repository. The default
180 if there are no ``include`` statements is to include everything.
180 if there are no ``include`` statements is to include everything.
181 If there are any ``include`` statements, nothing else is included.
181 If there are any ``include`` statements, nothing else is included.
182 The ``exclude`` directive causes files or directories to
182 The ``exclude`` directive causes files or directories to
183 be omitted. The ``rename`` directive renames a file or directory if
183 be omitted. The ``rename`` directive renames a file or directory if
184 it is converted. To rename from a subdirectory into the root of
184 it is converted. To rename from a subdirectory into the root of
185 the repository, use ``.`` as the path to rename to.
185 the repository, use ``.`` as the path to rename to.
186
186
187 ``--full`` will make sure the converted changesets contain exactly
187 ``--full`` will make sure the converted changesets contain exactly
188 the right files with the right content. It will make a full
188 the right files with the right content. It will make a full
189 conversion of all files, not just the ones that have
189 conversion of all files, not just the ones that have
190 changed. Files that already are correct will not be changed. This
190 changed. Files that already are correct will not be changed. This
191 can be used to apply filemap changes when converting
191 can be used to apply filemap changes when converting
192 incrementally. This is currently only supported for Mercurial and
192 incrementally. This is currently only supported for Mercurial and
193 Subversion.
193 Subversion.
194
194
195 The splicemap is a file that allows insertion of synthetic
195 The splicemap is a file that allows insertion of synthetic
196 history, letting you specify the parents of a revision. This is
196 history, letting you specify the parents of a revision. This is
197 useful if you want to e.g. give a Subversion merge two parents, or
197 useful if you want to e.g. give a Subversion merge two parents, or
198 graft two disconnected series of history together. Each entry
198 graft two disconnected series of history together. Each entry
199 contains a key, followed by a space, followed by one or two
199 contains a key, followed by a space, followed by one or two
200 comma-separated values::
200 comma-separated values::
201
201
202 key parent1, parent2
202 key parent1, parent2
203
203
204 The key is the revision ID in the source
204 The key is the revision ID in the source
205 revision control system whose parents should be modified (same
205 revision control system whose parents should be modified (same
206 format as a key in .hg/shamap). The values are the revision IDs
206 format as a key in .hg/shamap). The values are the revision IDs
207 (in either the source or destination revision control system) that
207 (in either the source or destination revision control system) that
208 should be used as the new parents for that node. For example, if
208 should be used as the new parents for that node. For example, if
209 you have merged "release-1.0" into "trunk", then you should
209 you have merged "release-1.0" into "trunk", then you should
210 specify the revision on "trunk" as the first parent and the one on
210 specify the revision on "trunk" as the first parent and the one on
211 the "release-1.0" branch as the second.
211 the "release-1.0" branch as the second.
212
212
213 The branchmap is a file that allows you to rename a branch when it is
213 The branchmap is a file that allows you to rename a branch when it is
214 being brought in from whatever external repository. When used in
214 being brought in from whatever external repository. When used in
215 conjunction with a splicemap, it allows for a powerful combination
215 conjunction with a splicemap, it allows for a powerful combination
216 to help fix even the most badly mismanaged repositories and turn them
216 to help fix even the most badly mismanaged repositories and turn them
217 into nicely structured Mercurial repositories. The branchmap contains
217 into nicely structured Mercurial repositories. The branchmap contains
218 lines of the form::
218 lines of the form::
219
219
220 original_branch_name new_branch_name
220 original_branch_name new_branch_name
221
221
222 where "original_branch_name" is the name of the branch in the
222 where "original_branch_name" is the name of the branch in the
223 source repository, and "new_branch_name" is the name of the branch
223 source repository, and "new_branch_name" is the name of the branch
224 is the destination repository. No whitespace is allowed in the new
224 is the destination repository. No whitespace is allowed in the new
225 branch name. This can be used to (for instance) move code in one
225 branch name. This can be used to (for instance) move code in one
226 repository from "default" to a named branch.
226 repository from "default" to a named branch.
227
227
228 Mercurial Source
228 Mercurial Source
229 ################
229 ################
230
230
231 The Mercurial source recognizes the following configuration
231 The Mercurial source recognizes the following configuration
232 options, which you can set on the command line with ``--config``:
232 options, which you can set on the command line with ``--config``:
233
233
234 :convert.hg.ignoreerrors: ignore integrity errors when reading.
234 :convert.hg.ignoreerrors: ignore integrity errors when reading.
235 Use it to fix Mercurial repositories with missing revlogs, by
235 Use it to fix Mercurial repositories with missing revlogs, by
236 converting from and to Mercurial. Default is False.
236 converting from and to Mercurial. Default is False.
237
237
238 :convert.hg.saverev: store original revision ID in changeset
238 :convert.hg.saverev: store original revision ID in changeset
239 (forces target IDs to change). It takes a boolean argument and
239 (forces target IDs to change). It takes a boolean argument and
240 defaults to False.
240 defaults to False.
241
241
242 :convert.hg.startrev: specify the initial Mercurial revision.
242 :convert.hg.startrev: specify the initial Mercurial revision.
243 The default is 0.
243 The default is 0.
244
244
245 :convert.hg.revs: revset specifying the source revisions to convert.
245 :convert.hg.revs: revset specifying the source revisions to convert.
246
246
247 Bazaar Source
247 Bazaar Source
248 #############
248 #############
249
249
250 The following options can be used with ``--config``:
250 The following options can be used with ``--config``:
251
251
252 :convert.bzr.saverev: whether to store the original Bazaar commit ID in
252 :convert.bzr.saverev: whether to store the original Bazaar commit ID in
253 the metadata of the destination commit. The default is True.
253 the metadata of the destination commit. The default is True.
254
254
255 CVS Source
255 CVS Source
256 ##########
256 ##########
257
257
258 CVS source will use a sandbox (i.e. a checked-out copy) from CVS
258 CVS source will use a sandbox (i.e. a checked-out copy) from CVS
259 to indicate the starting point of what will be converted. Direct
259 to indicate the starting point of what will be converted. Direct
260 access to the repository files is not needed, unless of course the
260 access to the repository files is not needed, unless of course the
261 repository is ``:local:``. The conversion uses the top level
261 repository is ``:local:``. The conversion uses the top level
262 directory in the sandbox to find the CVS repository, and then uses
262 directory in the sandbox to find the CVS repository, and then uses
263 CVS rlog commands to find files to convert. This means that unless
263 CVS rlog commands to find files to convert. This means that unless
264 a filemap is given, all files under the starting directory will be
264 a filemap is given, all files under the starting directory will be
265 converted, and that any directory reorganization in the CVS
265 converted, and that any directory reorganization in the CVS
266 sandbox is ignored.
266 sandbox is ignored.
267
267
268 The following options can be used with ``--config``:
268 The following options can be used with ``--config``:
269
269
270 :convert.cvsps.cache: Set to False to disable remote log caching,
270 :convert.cvsps.cache: Set to False to disable remote log caching,
271 for testing and debugging purposes. Default is True.
271 for testing and debugging purposes. Default is True.
272
272
273 :convert.cvsps.fuzz: Specify the maximum time (in seconds) that is
273 :convert.cvsps.fuzz: Specify the maximum time (in seconds) that is
274 allowed between commits with identical user and log message in
274 allowed between commits with identical user and log message in
275 a single changeset. When very large files were checked in as
275 a single changeset. When very large files were checked in as
276 part of a changeset then the default may not be long enough.
276 part of a changeset then the default may not be long enough.
277 The default is 60.
277 The default is 60.
278
278
279 :convert.cvsps.logencoding: Specify encoding name to be used for
279 :convert.cvsps.logencoding: Specify encoding name to be used for
280 transcoding CVS log messages. Multiple encoding names can be
280 transcoding CVS log messages. Multiple encoding names can be
281 specified as a list (see :hg:`help config.Syntax`), but only
281 specified as a list (see :hg:`help config.Syntax`), but only
282 the first acceptable encoding in the list is used per CVS log
282 the first acceptable encoding in the list is used per CVS log
283 entries. This transcoding is executed before cvslog hook below.
283 entries. This transcoding is executed before cvslog hook below.
284
284
285 :convert.cvsps.mergeto: Specify a regular expression to which
285 :convert.cvsps.mergeto: Specify a regular expression to which
286 commit log messages are matched. If a match occurs, then the
286 commit log messages are matched. If a match occurs, then the
287 conversion process will insert a dummy revision merging the
287 conversion process will insert a dummy revision merging the
288 branch on which this log message occurs to the branch
288 branch on which this log message occurs to the branch
289 indicated in the regex. Default is ``{{mergetobranch
289 indicated in the regex. Default is ``{{mergetobranch
290 ([-\\w]+)}}``
290 ([-\\w]+)}}``
291
291
292 :convert.cvsps.mergefrom: Specify a regular expression to which
292 :convert.cvsps.mergefrom: Specify a regular expression to which
293 commit log messages are matched. If a match occurs, then the
293 commit log messages are matched. If a match occurs, then the
294 conversion process will add the most recent revision on the
294 conversion process will add the most recent revision on the
295 branch indicated in the regex as the second parent of the
295 branch indicated in the regex as the second parent of the
296 changeset. Default is ``{{mergefrombranch ([-\\w]+)}}``
296 changeset. Default is ``{{mergefrombranch ([-\\w]+)}}``
297
297
298 :convert.localtimezone: use local time (as determined by the TZ
298 :convert.localtimezone: use local time (as determined by the TZ
299 environment variable) for changeset date/times. The default
299 environment variable) for changeset date/times. The default
300 is False (use UTC).
300 is False (use UTC).
301
301
302 :hooks.cvslog: Specify a Python function to be called at the end of
302 :hooks.cvslog: Specify a Python function to be called at the end of
303 gathering the CVS log. The function is passed a list with the
303 gathering the CVS log. The function is passed a list with the
304 log entries, and can modify the entries in-place, or add or
304 log entries, and can modify the entries in-place, or add or
305 delete them.
305 delete them.
306
306
307 :hooks.cvschangesets: Specify a Python function to be called after
307 :hooks.cvschangesets: Specify a Python function to be called after
308 the changesets are calculated from the CVS log. The
308 the changesets are calculated from the CVS log. The
309 function is passed a list with the changeset entries, and can
309 function is passed a list with the changeset entries, and can
310 modify the changesets in-place, or add or delete them.
310 modify the changesets in-place, or add or delete them.
311
311
312 An additional "debugcvsps" Mercurial command allows the builtin
312 An additional "debugcvsps" Mercurial command allows the builtin
313 changeset merging code to be run without doing a conversion. Its
313 changeset merging code to be run without doing a conversion. Its
314 parameters and output are similar to that of cvsps 2.1. Please see
314 parameters and output are similar to that of cvsps 2.1. Please see
315 the command help for more details.
315 the command help for more details.
316
316
317 Subversion Source
317 Subversion Source
318 #################
318 #################
319
319
320 Subversion source detects classical trunk/branches/tags layouts.
320 Subversion source detects classical trunk/branches/tags layouts.
321 By default, the supplied ``svn://repo/path/`` source URL is
321 By default, the supplied ``svn://repo/path/`` source URL is
322 converted as a single branch. If ``svn://repo/path/trunk`` exists
322 converted as a single branch. If ``svn://repo/path/trunk`` exists
323 it replaces the default branch. If ``svn://repo/path/branches``
323 it replaces the default branch. If ``svn://repo/path/branches``
324 exists, its subdirectories are listed as possible branches. If
324 exists, its subdirectories are listed as possible branches. If
325 ``svn://repo/path/tags`` exists, it is looked for tags referencing
325 ``svn://repo/path/tags`` exists, it is looked for tags referencing
326 converted branches. Default ``trunk``, ``branches`` and ``tags``
326 converted branches. Default ``trunk``, ``branches`` and ``tags``
327 values can be overridden with following options. Set them to paths
327 values can be overridden with following options. Set them to paths
328 relative to the source URL, or leave them blank to disable auto
328 relative to the source URL, or leave them blank to disable auto
329 detection.
329 detection.
330
330
331 The following options can be set with ``--config``:
331 The following options can be set with ``--config``:
332
332
333 :convert.svn.branches: specify the directory containing branches.
333 :convert.svn.branches: specify the directory containing branches.
334 The default is ``branches``.
334 The default is ``branches``.
335
335
336 :convert.svn.tags: specify the directory containing tags. The
336 :convert.svn.tags: specify the directory containing tags. The
337 default is ``tags``.
337 default is ``tags``.
338
338
339 :convert.svn.trunk: specify the name of the trunk branch. The
339 :convert.svn.trunk: specify the name of the trunk branch. The
340 default is ``trunk``.
340 default is ``trunk``.
341
341
342 :convert.localtimezone: use local time (as determined by the TZ
342 :convert.localtimezone: use local time (as determined by the TZ
343 environment variable) for changeset date/times. The default
343 environment variable) for changeset date/times. The default
344 is False (use UTC).
344 is False (use UTC).
345
345
346 Source history can be retrieved starting at a specific revision,
346 Source history can be retrieved starting at a specific revision,
347 instead of being integrally converted. Only single branch
347 instead of being integrally converted. Only single branch
348 conversions are supported.
348 conversions are supported.
349
349
350 :convert.svn.startrev: specify start Subversion revision number.
350 :convert.svn.startrev: specify start Subversion revision number.
351 The default is 0.
351 The default is 0.
352
352
353 Git Source
353 Git Source
354 ##########
354 ##########
355
355
356 The Git importer converts commits from all reachable branches (refs
356 The Git importer converts commits from all reachable branches (refs
357 in refs/heads) and remotes (refs in refs/remotes) to Mercurial.
357 in refs/heads) and remotes (refs in refs/remotes) to Mercurial.
358 Branches are converted to bookmarks with the same name, with the
358 Branches are converted to bookmarks with the same name, with the
359 leading 'refs/heads' stripped. Git submodules are converted to Git
359 leading 'refs/heads' stripped. Git submodules are converted to Git
360 subrepos in Mercurial.
360 subrepos in Mercurial.
361
361
362 The following options can be set with ``--config``:
362 The following options can be set with ``--config``:
363
363
364 :convert.git.similarity: specify how similar files modified in a
364 :convert.git.similarity: specify how similar files modified in a
365 commit must be to be imported as renames or copies, as a
365 commit must be to be imported as renames or copies, as a
366 percentage between ``0`` (disabled) and ``100`` (files must be
366 percentage between ``0`` (disabled) and ``100`` (files must be
367 identical). For example, ``90`` means that a delete/add pair will
367 identical). For example, ``90`` means that a delete/add pair will
368 be imported as a rename if more than 90% of the file hasn't
368 be imported as a rename if more than 90% of the file hasn't
369 changed. The default is ``50``.
369 changed. The default is ``50``.
370
370
371 :convert.git.findcopiesharder: while detecting copies, look at all
371 :convert.git.findcopiesharder: while detecting copies, look at all
372 files in the working copy instead of just changed ones. This
372 files in the working copy instead of just changed ones. This
373 is very expensive for large projects, and is only effective when
373 is very expensive for large projects, and is only effective when
374 ``convert.git.similarity`` is greater than 0. The default is False.
374 ``convert.git.similarity`` is greater than 0. The default is False.
375
375
376 :convert.git.renamelimit: perform rename and copy detection up to this
376 :convert.git.renamelimit: perform rename and copy detection up to this
377 many changed files in a commit. Increasing this will make rename
377 many changed files in a commit. Increasing this will make rename
378 and copy detection more accurate but will significantly slow down
378 and copy detection more accurate but will significantly slow down
379 computation on large projects. The option is only relevant if
379 computation on large projects. The option is only relevant if
380 ``convert.git.similarity`` is greater than 0. The default is
380 ``convert.git.similarity`` is greater than 0. The default is
381 ``400``.
381 ``400``.
382
382
383 :convert.git.committeractions: list of actions to take when processing
383 :convert.git.committeractions: list of actions to take when processing
384 author and committer values.
384 author and committer values.
385
385
386 Git commits have separate author (who wrote the commit) and committer
386 Git commits have separate author (who wrote the commit) and committer
387 (who applied the commit) fields. Not all destinations support separate
387 (who applied the commit) fields. Not all destinations support separate
388 author and committer fields (including Mercurial). This config option
388 author and committer fields (including Mercurial). This config option
389 controls what to do with these author and committer fields during
389 controls what to do with these author and committer fields during
390 conversion.
390 conversion.
391
391
392 A value of ``messagedifferent`` will append a ``committer: ...``
392 A value of ``messagedifferent`` will append a ``committer: ...``
393 line to the commit message if the Git committer is different from the
393 line to the commit message if the Git committer is different from the
394 author. The prefix of that line can be specified using the syntax
394 author. The prefix of that line can be specified using the syntax
395 ``messagedifferent=<prefix>``. e.g. ``messagedifferent=git-committer:``.
395 ``messagedifferent=<prefix>``. e.g. ``messagedifferent=git-committer:``.
396 When a prefix is specified, a space will always be inserted between the
396 When a prefix is specified, a space will always be inserted between the
397 prefix and the value.
397 prefix and the value.
398
398
399 ``messagealways`` behaves like ``messagedifferent`` except it will
399 ``messagealways`` behaves like ``messagedifferent`` except it will
400 always result in a ``committer: ...`` line being appended to the commit
400 always result in a ``committer: ...`` line being appended to the commit
401 message. This value is mutually exclusive with ``messagedifferent``.
401 message. This value is mutually exclusive with ``messagedifferent``.
402
402
403 ``dropcommitter`` will remove references to the committer. Only
403 ``dropcommitter`` will remove references to the committer. Only
404 references to the author will remain. Actions that add references
404 references to the author will remain. Actions that add references
405 to the committer will have no effect when this is set.
405 to the committer will have no effect when this is set.
406
406
407 ``replaceauthor`` will replace the value of the author field with
407 ``replaceauthor`` will replace the value of the author field with
408 the committer. Other actions that add references to the committer
408 the committer. Other actions that add references to the committer
409 will still take effect when this is set.
409 will still take effect when this is set.
410
410
411 The default is ``messagedifferent``.
411 The default is ``messagedifferent``.
412
412
413 :convert.git.extrakeys: list of extra keys from commit metadata to copy to
413 :convert.git.extrakeys: list of extra keys from commit metadata to copy to
414 the destination. Some Git repositories store extra metadata in commits.
414 the destination. Some Git repositories store extra metadata in commits.
415 By default, this non-default metadata will be lost during conversion.
415 By default, this non-default metadata will be lost during conversion.
416 Setting this config option can retain that metadata. Some built-in
416 Setting this config option can retain that metadata. Some built-in
417 keys such as ``parent`` and ``branch`` are not allowed to be copied.
417 keys such as ``parent`` and ``branch`` are not allowed to be copied.
418
418
419 :convert.git.remoteprefix: remote refs are converted as bookmarks with
419 :convert.git.remoteprefix: remote refs are converted as bookmarks with
420 ``convert.git.remoteprefix`` as a prefix followed by a /. The default
420 ``convert.git.remoteprefix`` as a prefix followed by a /. The default
421 is 'remote'.
421 is 'remote'.
422
422
423 :convert.git.saverev: whether to store the original Git commit ID in the
423 :convert.git.saverev: whether to store the original Git commit ID in the
424 metadata of the destination commit. The default is True.
424 metadata of the destination commit. The default is True.
425
425
426 :convert.git.skipsubmodules: does not convert root level .gitmodules files
426 :convert.git.skipsubmodules: does not convert root level .gitmodules files
427 or files with 160000 mode indicating a submodule. Default is False.
427 or files with 160000 mode indicating a submodule. Default is False.
428
428
429 Perforce Source
429 Perforce Source
430 ###############
430 ###############
431
431
432 The Perforce (P4) importer can be given a p4 depot path or a
432 The Perforce (P4) importer can be given a p4 depot path or a
433 client specification as source. It will convert all files in the
433 client specification as source. It will convert all files in the
434 source to a flat Mercurial repository, ignoring labels, branches
434 source to a flat Mercurial repository, ignoring labels, branches
435 and integrations. Note that when a depot path is given you then
435 and integrations. Note that when a depot path is given you then
436 usually should specify a target directory, because otherwise the
436 usually should specify a target directory, because otherwise the
437 target may be named ``...-hg``.
437 target may be named ``...-hg``.
438
438
439 The following options can be set with ``--config``:
439 The following options can be set with ``--config``:
440
440
441 :convert.p4.encoding: specify the encoding to use when decoding standard
441 :convert.p4.encoding: specify the encoding to use when decoding standard
442 output of the Perforce command line tool. The default is default system
442 output of the Perforce command line tool. The default is default system
443 encoding.
443 encoding.
444
444
445 :convert.p4.startrev: specify initial Perforce revision (a
445 :convert.p4.startrev: specify initial Perforce revision (a
446 Perforce changelist number).
446 Perforce changelist number).
447
447
448 Mercurial Destination
448 Mercurial Destination
449 #####################
449 #####################
450
450
451 The Mercurial destination will recognize Mercurial subrepositories in the
451 The Mercurial destination will recognize Mercurial subrepositories in the
452 destination directory, and update the .hgsubstate file automatically if the
452 destination directory, and update the .hgsubstate file automatically if the
453 destination subrepositories contain the <dest>/<sub>/.hg/shamap file.
453 destination subrepositories contain the <dest>/<sub>/.hg/shamap file.
454 Converting a repository with subrepositories requires converting a single
454 Converting a repository with subrepositories requires converting a single
455 repository at a time, from the bottom up.
455 repository at a time, from the bottom up.
456
456
457 .. container:: verbose
457 .. container:: verbose
458
458
459 An example showing how to convert a repository with subrepositories::
459 An example showing how to convert a repository with subrepositories::
460
460
461 # so convert knows the type when it sees a non empty destination
461 # so convert knows the type when it sees a non empty destination
462 $ hg init converted
462 $ hg init converted
463
463
464 $ hg convert orig/sub1 converted/sub1
464 $ hg convert orig/sub1 converted/sub1
465 $ hg convert orig/sub2 converted/sub2
465 $ hg convert orig/sub2 converted/sub2
466 $ hg convert orig converted
466 $ hg convert orig converted
467
467
468 The following options are supported:
468 The following options are supported:
469
469
470 :convert.hg.clonebranches: dispatch source branches in separate
470 :convert.hg.clonebranches: dispatch source branches in separate
471 clones. The default is False.
471 clones. The default is False.
472
472
473 :convert.hg.tagsbranch: branch name for tag revisions, defaults to
473 :convert.hg.tagsbranch: branch name for tag revisions, defaults to
474 ``default``.
474 ``default``.
475
475
476 :convert.hg.usebranchnames: preserve branch names. The default is
476 :convert.hg.usebranchnames: preserve branch names. The default is
477 True.
477 True.
478
478
479 :convert.hg.sourcename: records the given string as a 'convert_source' extra
479 :convert.hg.sourcename: records the given string as a 'convert_source' extra
480 value on each commit made in the target repository. The default is None.
480 value on each commit made in the target repository. The default is None.
481
481
482 :convert.hg.preserve-hash: only works with mercurial sources. Make convert
482 :convert.hg.preserve-hash: only works with mercurial sources. Make convert
483 prevent performance improvement to the list of modified files in commits
483 prevent performance improvement to the list of modified files in commits
484 when such an improvement would cause the hash of a commit to change.
484 when such an improvement would cause the hash of a commit to change.
485 The default is False.
485 The default is False.
486
486
487 All Destinations
487 All Destinations
488 ################
488 ################
489
489
490 All destination types accept the following options:
490 All destination types accept the following options:
491
491
492 :convert.skiptags: does not convert tags from the source repo to the target
492 :convert.skiptags: does not convert tags from the source repo to the target
493 repo. The default is False.
493 repo. The default is False.
494
495 Subversion Destination
496 ######################
497
498 Original commit dates are not preserved by default.
499
500 :convert.svn.dangerous-set-commit-dates: preserve original commit dates,
501 forcefully setting ``svn:date`` revision properties. This option is
502 DANGEROUS and may break some subversion functionality for the resulting
503 repository (e.g. filtering revisions with date ranges in ``svn log``),
504 as original commit dates are not guaranteed to be monotonically
505 increasing.
506
507 For commit dates setting to work destination repository must have
508 ``pre-revprop-change`` hook configured to allow setting of ``svn:date``
509 revision properties. See Subversion documentation for more details.
494 """
510 """
495 return convcmd.convert(ui, src, dest, revmapfile, **opts)
511 return convcmd.convert(ui, src, dest, revmapfile, **opts)
496
512
497
513
498 @command(b'debugsvnlog', [], b'hg debugsvnlog', norepo=True)
514 @command(b'debugsvnlog', [], b'hg debugsvnlog', norepo=True)
499 def debugsvnlog(ui, **opts):
515 def debugsvnlog(ui, **opts):
500 return subversion.debugsvnlog(ui, **opts)
516 return subversion.debugsvnlog(ui, **opts)
501
517
502
518
503 @command(
519 @command(
504 b'debugcvsps',
520 b'debugcvsps',
505 [
521 [
506 # Main options shared with cvsps-2.1
522 # Main options shared with cvsps-2.1
507 (
523 (
508 b'b',
524 b'b',
509 b'branches',
525 b'branches',
510 [],
526 [],
511 _(b'only return changes on specified branches'),
527 _(b'only return changes on specified branches'),
512 ),
528 ),
513 (b'p', b'prefix', b'', _(b'prefix to remove from file names')),
529 (b'p', b'prefix', b'', _(b'prefix to remove from file names')),
514 (
530 (
515 b'r',
531 b'r',
516 b'revisions',
532 b'revisions',
517 [],
533 [],
518 _(b'only return changes after or between specified tags'),
534 _(b'only return changes after or between specified tags'),
519 ),
535 ),
520 (b'u', b'update-cache', None, _(b"update cvs log cache")),
536 (b'u', b'update-cache', None, _(b"update cvs log cache")),
521 (b'x', b'new-cache', None, _(b"create new cvs log cache")),
537 (b'x', b'new-cache', None, _(b"create new cvs log cache")),
522 (b'z', b'fuzz', 60, _(b'set commit time fuzz in seconds')),
538 (b'z', b'fuzz', 60, _(b'set commit time fuzz in seconds')),
523 (b'', b'root', b'', _(b'specify cvsroot')),
539 (b'', b'root', b'', _(b'specify cvsroot')),
524 # Options specific to builtin cvsps
540 # Options specific to builtin cvsps
525 (b'', b'parents', b'', _(b'show parent changesets')),
541 (b'', b'parents', b'', _(b'show parent changesets')),
526 (
542 (
527 b'',
543 b'',
528 b'ancestors',
544 b'ancestors',
529 b'',
545 b'',
530 _(b'show current changeset in ancestor branches'),
546 _(b'show current changeset in ancestor branches'),
531 ),
547 ),
532 # Options that are ignored for compatibility with cvsps-2.1
548 # Options that are ignored for compatibility with cvsps-2.1
533 (b'A', b'cvs-direct', None, _(b'ignored for compatibility')),
549 (b'A', b'cvs-direct', None, _(b'ignored for compatibility')),
534 ],
550 ],
535 _(b'hg debugcvsps [OPTION]... [PATH]...'),
551 _(b'hg debugcvsps [OPTION]... [PATH]...'),
536 norepo=True,
552 norepo=True,
537 )
553 )
538 def debugcvsps(ui, *args, **opts):
554 def debugcvsps(ui, *args, **opts):
539 """create changeset information from CVS
555 """create changeset information from CVS
540
556
541 This command is intended as a debugging tool for the CVS to
557 This command is intended as a debugging tool for the CVS to
542 Mercurial converter, and can be used as a direct replacement for
558 Mercurial converter, and can be used as a direct replacement for
543 cvsps.
559 cvsps.
544
560
545 Hg debugcvsps reads the CVS rlog for current directory (or any
561 Hg debugcvsps reads the CVS rlog for current directory (or any
546 named directory) in the CVS repository, and converts the log to a
562 named directory) in the CVS repository, and converts the log to a
547 series of changesets based on matching commit log entries and
563 series of changesets based on matching commit log entries and
548 dates."""
564 dates."""
549 return cvsps.debugcvsps(ui, *args, **opts)
565 return cvsps.debugcvsps(ui, *args, **opts)
550
566
551
567
552 def kwconverted(context, mapping, name):
568 def kwconverted(context, mapping, name):
553 ctx = context.resource(mapping, b'ctx')
569 ctx = context.resource(mapping, b'ctx')
554 rev = ctx.extra().get(b'convert_revision', b'')
570 rev = ctx.extra().get(b'convert_revision', b'')
555 if rev.startswith(b'svn:'):
571 if rev.startswith(b'svn:'):
556 if name == b'svnrev':
572 if name == b'svnrev':
557 return b"%d" % subversion.revsplit(rev)[2]
573 return b"%d" % subversion.revsplit(rev)[2]
558 elif name == b'svnpath':
574 elif name == b'svnpath':
559 return subversion.revsplit(rev)[1]
575 return subversion.revsplit(rev)[1]
560 elif name == b'svnuuid':
576 elif name == b'svnuuid':
561 return subversion.revsplit(rev)[0]
577 return subversion.revsplit(rev)[0]
562 return rev
578 return rev
563
579
564
580
565 templatekeyword = registrar.templatekeyword()
581 templatekeyword = registrar.templatekeyword()
566
582
567
583
568 @templatekeyword(b'svnrev', requires={b'ctx'})
584 @templatekeyword(b'svnrev', requires={b'ctx'})
569 def kwsvnrev(context, mapping):
585 def kwsvnrev(context, mapping):
570 """String. Converted subversion revision number."""
586 """String. Converted subversion revision number."""
571 return kwconverted(context, mapping, b'svnrev')
587 return kwconverted(context, mapping, b'svnrev')
572
588
573
589
574 @templatekeyword(b'svnpath', requires={b'ctx'})
590 @templatekeyword(b'svnpath', requires={b'ctx'})
575 def kwsvnpath(context, mapping):
591 def kwsvnpath(context, mapping):
576 """String. Converted subversion revision project path."""
592 """String. Converted subversion revision project path."""
577 return kwconverted(context, mapping, b'svnpath')
593 return kwconverted(context, mapping, b'svnpath')
578
594
579
595
580 @templatekeyword(b'svnuuid', requires={b'ctx'})
596 @templatekeyword(b'svnuuid', requires={b'ctx'})
581 def kwsvnuuid(context, mapping):
597 def kwsvnuuid(context, mapping):
582 """String. Converted subversion revision repository identifier."""
598 """String. Converted subversion revision repository identifier."""
583 return kwconverted(context, mapping, b'svnuuid')
599 return kwconverted(context, mapping, b'svnuuid')
584
600
585
601
586 # tell hggettext to extract docstrings from these functions:
602 # tell hggettext to extract docstrings from these functions:
587 i18nfunctions = [kwsvnrev, kwsvnpath, kwsvnuuid]
603 i18nfunctions = [kwsvnrev, kwsvnpath, kwsvnuuid]
@@ -1,1696 +1,1741 b''
1 # Subversion 1.4/1.5 Python API backend
1 # Subversion 1.4/1.5 Python API backend
2 #
2 #
3 # Copyright(C) 2007 Daniel Holth et al
3 # Copyright(C) 2007 Daniel Holth et al
4 from __future__ import absolute_import
4 from __future__ import absolute_import
5
5
6 import codecs
6 import codecs
7 import locale
7 import locale
8 import os
8 import os
9 import re
9 import re
10 import xml.dom.minidom
10 import xml.dom.minidom
11
11
12 from mercurial.i18n import _
12 from mercurial.i18n import _
13 from mercurial.pycompat import open
13 from mercurial.pycompat import open
14 from mercurial import (
14 from mercurial import (
15 encoding,
15 encoding,
16 error,
16 error,
17 pycompat,
17 pycompat,
18 util,
18 util,
19 vfs as vfsmod,
19 vfs as vfsmod,
20 )
20 )
21 from mercurial.utils import (
21 from mercurial.utils import (
22 dateutil,
22 dateutil,
23 procutil,
23 procutil,
24 stringutil,
24 stringutil,
25 )
25 )
26
26
27 from . import common
27 from . import common
28
28
29 pickle = util.pickle
29 pickle = util.pickle
30 stringio = util.stringio
30 stringio = util.stringio
31 propertycache = util.propertycache
31 propertycache = util.propertycache
32 urlerr = util.urlerr
32 urlerr = util.urlerr
33 urlreq = util.urlreq
33 urlreq = util.urlreq
34
34
35 commandline = common.commandline
35 commandline = common.commandline
36 commit = common.commit
36 commit = common.commit
37 converter_sink = common.converter_sink
37 converter_sink = common.converter_sink
38 converter_source = common.converter_source
38 converter_source = common.converter_source
39 decodeargs = common.decodeargs
39 decodeargs = common.decodeargs
40 encodeargs = common.encodeargs
40 encodeargs = common.encodeargs
41 makedatetimestamp = common.makedatetimestamp
41 makedatetimestamp = common.makedatetimestamp
42 mapfile = common.mapfile
42 mapfile = common.mapfile
43 MissingTool = common.MissingTool
43 MissingTool = common.MissingTool
44 NoRepo = common.NoRepo
44 NoRepo = common.NoRepo
45
45
46 # Subversion stuff. Works best with very recent Python SVN bindings
46 # Subversion stuff. Works best with very recent Python SVN bindings
47 # e.g. SVN 1.5 or backports. Thanks to the bzr folks for enhancing
47 # e.g. SVN 1.5 or backports. Thanks to the bzr folks for enhancing
48 # these bindings.
48 # these bindings.
49
49
50 try:
50 try:
51 import svn
51 import svn
52 import svn.client
52 import svn.client
53 import svn.core
53 import svn.core
54 import svn.ra
54 import svn.ra
55 import svn.delta
55 import svn.delta
56 from . import transport
56 from . import transport
57 import warnings
57 import warnings
58
58
59 warnings.filterwarnings(
59 warnings.filterwarnings(
60 'ignore', module='svn.core', category=DeprecationWarning
60 'ignore', module='svn.core', category=DeprecationWarning
61 )
61 )
62 svn.core.SubversionException # trigger import to catch error
62 svn.core.SubversionException # trigger import to catch error
63
63
64 except ImportError:
64 except ImportError:
65 svn = None
65 svn = None
66
66
67
67
68 # In Subversion, paths and URLs are Unicode (encoded as UTF-8), which
68 # In Subversion, paths and URLs are Unicode (encoded as UTF-8), which
69 # Subversion converts from / to native strings when interfacing with the OS.
69 # Subversion converts from / to native strings when interfacing with the OS.
70 # When passing paths and URLs to Subversion, we have to recode them such that
70 # When passing paths and URLs to Subversion, we have to recode them such that
71 # it roundstrips with what Subversion is doing.
71 # it roundstrips with what Subversion is doing.
72
72
73 fsencoding = None
73 fsencoding = None
74
74
75
75
76 def init_fsencoding():
76 def init_fsencoding():
77 global fsencoding, fsencoding_is_utf8
77 global fsencoding, fsencoding_is_utf8
78 if fsencoding is not None:
78 if fsencoding is not None:
79 return
79 return
80 if pycompat.iswindows:
80 if pycompat.iswindows:
81 # On Windows, filenames are Unicode, but we store them using the MBCS
81 # On Windows, filenames are Unicode, but we store them using the MBCS
82 # encoding.
82 # encoding.
83 fsencoding = 'mbcs'
83 fsencoding = 'mbcs'
84 else:
84 else:
85 # This is the encoding used to convert UTF-8 back to natively-encoded
85 # This is the encoding used to convert UTF-8 back to natively-encoded
86 # strings in Subversion 1.14.0 or earlier with APR 1.7.0 or earlier.
86 # strings in Subversion 1.14.0 or earlier with APR 1.7.0 or earlier.
87 with util.with_lc_ctype():
87 with util.with_lc_ctype():
88 fsencoding = locale.nl_langinfo(locale.CODESET) or 'ISO-8859-1'
88 fsencoding = locale.nl_langinfo(locale.CODESET) or 'ISO-8859-1'
89 fsencoding = codecs.lookup(fsencoding).name
89 fsencoding = codecs.lookup(fsencoding).name
90 fsencoding_is_utf8 = fsencoding == codecs.lookup('utf-8').name
90 fsencoding_is_utf8 = fsencoding == codecs.lookup('utf-8').name
91
91
92
92
93 def fs2svn(s):
93 def fs2svn(s):
94 if fsencoding_is_utf8:
94 if fsencoding_is_utf8:
95 return s
95 return s
96 else:
96 else:
97 return s.decode(fsencoding).encode('utf-8')
97 return s.decode(fsencoding).encode('utf-8')
98
98
99
99
100 def formatsvndate(date):
101 return dateutil.datestr(date, b'%Y-%m-%dT%H:%M:%S.000000Z')
102
103
104 def parsesvndate(s):
105 # Example SVN datetime. Includes microseconds.
106 # ISO-8601 conformant
107 # '2007-01-04T17:35:00.902377Z'
108 return dateutil.parsedate(s[:19] + b' UTC', [b'%Y-%m-%dT%H:%M:%S'])
109
110
100 class SvnPathNotFound(Exception):
111 class SvnPathNotFound(Exception):
101 pass
112 pass
102
113
103
114
104 def revsplit(rev):
115 def revsplit(rev):
105 """Parse a revision string and return (uuid, path, revnum).
116 """Parse a revision string and return (uuid, path, revnum).
106 >>> revsplit(b'svn:a2147622-4a9f-4db4-a8d3-13562ff547b2'
117 >>> revsplit(b'svn:a2147622-4a9f-4db4-a8d3-13562ff547b2'
107 ... b'/proj%20B/mytrunk/mytrunk@1')
118 ... b'/proj%20B/mytrunk/mytrunk@1')
108 ('a2147622-4a9f-4db4-a8d3-13562ff547b2', '/proj%20B/mytrunk/mytrunk', 1)
119 ('a2147622-4a9f-4db4-a8d3-13562ff547b2', '/proj%20B/mytrunk/mytrunk', 1)
109 >>> revsplit(b'svn:8af66a51-67f5-4354-b62c-98d67cc7be1d@1')
120 >>> revsplit(b'svn:8af66a51-67f5-4354-b62c-98d67cc7be1d@1')
110 ('', '', 1)
121 ('', '', 1)
111 >>> revsplit(b'@7')
122 >>> revsplit(b'@7')
112 ('', '', 7)
123 ('', '', 7)
113 >>> revsplit(b'7')
124 >>> revsplit(b'7')
114 ('', '', 0)
125 ('', '', 0)
115 >>> revsplit(b'bad')
126 >>> revsplit(b'bad')
116 ('', '', 0)
127 ('', '', 0)
117 """
128 """
118 parts = rev.rsplit(b'@', 1)
129 parts = rev.rsplit(b'@', 1)
119 revnum = 0
130 revnum = 0
120 if len(parts) > 1:
131 if len(parts) > 1:
121 revnum = int(parts[1])
132 revnum = int(parts[1])
122 parts = parts[0].split(b'/', 1)
133 parts = parts[0].split(b'/', 1)
123 uuid = b''
134 uuid = b''
124 mod = b''
135 mod = b''
125 if len(parts) > 1 and parts[0].startswith(b'svn:'):
136 if len(parts) > 1 and parts[0].startswith(b'svn:'):
126 uuid = parts[0][4:]
137 uuid = parts[0][4:]
127 mod = b'/' + parts[1]
138 mod = b'/' + parts[1]
128 return uuid, mod, revnum
139 return uuid, mod, revnum
129
140
130
141
131 def quote(s):
142 def quote(s):
132 # As of svn 1.7, many svn calls expect "canonical" paths. In
143 # As of svn 1.7, many svn calls expect "canonical" paths. In
133 # theory, we should call svn.core.*canonicalize() on all paths
144 # theory, we should call svn.core.*canonicalize() on all paths
134 # before passing them to the API. Instead, we assume the base url
145 # before passing them to the API. Instead, we assume the base url
135 # is canonical and copy the behaviour of svn URL encoding function
146 # is canonical and copy the behaviour of svn URL encoding function
136 # so we can extend it safely with new components. The "safe"
147 # so we can extend it safely with new components. The "safe"
137 # characters were taken from the "svn_uri__char_validity" table in
148 # characters were taken from the "svn_uri__char_validity" table in
138 # libsvn_subr/path.c.
149 # libsvn_subr/path.c.
139 return urlreq.quote(s, b"!$&'()*+,-./:=@_~")
150 return urlreq.quote(s, b"!$&'()*+,-./:=@_~")
140
151
141
152
142 def geturl(path):
153 def geturl(path):
143 """Convert path or URL to a SVN URL, encoded in UTF-8.
154 """Convert path or URL to a SVN URL, encoded in UTF-8.
144
155
145 This can raise UnicodeDecodeError if the path or URL can't be converted to
156 This can raise UnicodeDecodeError if the path or URL can't be converted to
146 unicode using `fsencoding`.
157 unicode using `fsencoding`.
147 """
158 """
148 try:
159 try:
149 return svn.client.url_from_path(
160 return svn.client.url_from_path(
150 svn.core.svn_path_canonicalize(fs2svn(path))
161 svn.core.svn_path_canonicalize(fs2svn(path))
151 )
162 )
152 except svn.core.SubversionException:
163 except svn.core.SubversionException:
153 # svn.client.url_from_path() fails with local repositories
164 # svn.client.url_from_path() fails with local repositories
154 pass
165 pass
155 if os.path.isdir(path):
166 if os.path.isdir(path):
156 path = os.path.normpath(os.path.abspath(path))
167 path = os.path.normpath(os.path.abspath(path))
157 if pycompat.iswindows:
168 if pycompat.iswindows:
158 path = b'/' + util.normpath(path)
169 path = b'/' + util.normpath(path)
159 # Module URL is later compared with the repository URL returned
170 # Module URL is later compared with the repository URL returned
160 # by svn API, which is UTF-8.
171 # by svn API, which is UTF-8.
161 path = fs2svn(path)
172 path = fs2svn(path)
162 path = b'file://%s' % quote(path)
173 path = b'file://%s' % quote(path)
163 return svn.core.svn_path_canonicalize(path)
174 return svn.core.svn_path_canonicalize(path)
164
175
165
176
166 def optrev(number):
177 def optrev(number):
167 optrev = svn.core.svn_opt_revision_t()
178 optrev = svn.core.svn_opt_revision_t()
168 optrev.kind = svn.core.svn_opt_revision_number
179 optrev.kind = svn.core.svn_opt_revision_number
169 optrev.value.number = number
180 optrev.value.number = number
170 return optrev
181 return optrev
171
182
172
183
173 class changedpath(object):
184 class changedpath(object):
174 def __init__(self, p):
185 def __init__(self, p):
175 self.copyfrom_path = p.copyfrom_path
186 self.copyfrom_path = p.copyfrom_path
176 self.copyfrom_rev = p.copyfrom_rev
187 self.copyfrom_rev = p.copyfrom_rev
177 self.action = p.action
188 self.action = p.action
178
189
179
190
180 def get_log_child(
191 def get_log_child(
181 fp,
192 fp,
182 url,
193 url,
183 paths,
194 paths,
184 start,
195 start,
185 end,
196 end,
186 limit=0,
197 limit=0,
187 discover_changed_paths=True,
198 discover_changed_paths=True,
188 strict_node_history=False,
199 strict_node_history=False,
189 ):
200 ):
190 protocol = -1
201 protocol = -1
191
202
192 def receiver(orig_paths, revnum, author, date, message, pool):
203 def receiver(orig_paths, revnum, author, date, message, pool):
193 paths = {}
204 paths = {}
194 if orig_paths is not None:
205 if orig_paths is not None:
195 for k, v in pycompat.iteritems(orig_paths):
206 for k, v in pycompat.iteritems(orig_paths):
196 paths[k] = changedpath(v)
207 paths[k] = changedpath(v)
197 pickle.dump((paths, revnum, author, date, message), fp, protocol)
208 pickle.dump((paths, revnum, author, date, message), fp, protocol)
198
209
199 try:
210 try:
200 # Use an ra of our own so that our parent can consume
211 # Use an ra of our own so that our parent can consume
201 # our results without confusing the server.
212 # our results without confusing the server.
202 t = transport.SvnRaTransport(url=url)
213 t = transport.SvnRaTransport(url=url)
203 svn.ra.get_log(
214 svn.ra.get_log(
204 t.ra,
215 t.ra,
205 paths,
216 paths,
206 start,
217 start,
207 end,
218 end,
208 limit,
219 limit,
209 discover_changed_paths,
220 discover_changed_paths,
210 strict_node_history,
221 strict_node_history,
211 receiver,
222 receiver,
212 )
223 )
213 except IOError:
224 except IOError:
214 # Caller may interrupt the iteration
225 # Caller may interrupt the iteration
215 pickle.dump(None, fp, protocol)
226 pickle.dump(None, fp, protocol)
216 except Exception as inst:
227 except Exception as inst:
217 pickle.dump(stringutil.forcebytestr(inst), fp, protocol)
228 pickle.dump(stringutil.forcebytestr(inst), fp, protocol)
218 else:
229 else:
219 pickle.dump(None, fp, protocol)
230 pickle.dump(None, fp, protocol)
220 fp.flush()
231 fp.flush()
221 # With large history, cleanup process goes crazy and suddenly
232 # With large history, cleanup process goes crazy and suddenly
222 # consumes *huge* amount of memory. The output file being closed,
233 # consumes *huge* amount of memory. The output file being closed,
223 # there is no need for clean termination.
234 # there is no need for clean termination.
224 os._exit(0)
235 os._exit(0)
225
236
226
237
227 def debugsvnlog(ui, **opts):
238 def debugsvnlog(ui, **opts):
228 """Fetch SVN log in a subprocess and channel them back to parent to
239 """Fetch SVN log in a subprocess and channel them back to parent to
229 avoid memory collection issues.
240 avoid memory collection issues.
230 """
241 """
231 with util.with_lc_ctype():
242 with util.with_lc_ctype():
232 if svn is None:
243 if svn is None:
233 raise error.Abort(
244 raise error.Abort(
234 _(b'debugsvnlog could not load Subversion python bindings')
245 _(b'debugsvnlog could not load Subversion python bindings')
235 )
246 )
236
247
237 args = decodeargs(ui.fin.read())
248 args = decodeargs(ui.fin.read())
238 get_log_child(ui.fout, *args)
249 get_log_child(ui.fout, *args)
239
250
240
251
241 class logstream(object):
252 class logstream(object):
242 """Interruptible revision log iterator."""
253 """Interruptible revision log iterator."""
243
254
244 def __init__(self, stdout):
255 def __init__(self, stdout):
245 self._stdout = stdout
256 self._stdout = stdout
246
257
247 def __iter__(self):
258 def __iter__(self):
248 while True:
259 while True:
249 try:
260 try:
250 entry = pickle.load(self._stdout)
261 entry = pickle.load(self._stdout)
251 except EOFError:
262 except EOFError:
252 raise error.Abort(
263 raise error.Abort(
253 _(
264 _(
254 b'Mercurial failed to run itself, check'
265 b'Mercurial failed to run itself, check'
255 b' hg executable is in PATH'
266 b' hg executable is in PATH'
256 )
267 )
257 )
268 )
258 try:
269 try:
259 orig_paths, revnum, author, date, message = entry
270 orig_paths, revnum, author, date, message = entry
260 except (TypeError, ValueError):
271 except (TypeError, ValueError):
261 if entry is None:
272 if entry is None:
262 break
273 break
263 raise error.Abort(_(b"log stream exception '%s'") % entry)
274 raise error.Abort(_(b"log stream exception '%s'") % entry)
264 yield entry
275 yield entry
265
276
266 def close(self):
277 def close(self):
267 if self._stdout:
278 if self._stdout:
268 self._stdout.close()
279 self._stdout.close()
269 self._stdout = None
280 self._stdout = None
270
281
271
282
272 class directlogstream(list):
283 class directlogstream(list):
273 """Direct revision log iterator.
284 """Direct revision log iterator.
274 This can be used for debugging and development but it will probably leak
285 This can be used for debugging and development but it will probably leak
275 memory and is not suitable for real conversions."""
286 memory and is not suitable for real conversions."""
276
287
277 def __init__(
288 def __init__(
278 self,
289 self,
279 url,
290 url,
280 paths,
291 paths,
281 start,
292 start,
282 end,
293 end,
283 limit=0,
294 limit=0,
284 discover_changed_paths=True,
295 discover_changed_paths=True,
285 strict_node_history=False,
296 strict_node_history=False,
286 ):
297 ):
287 def receiver(orig_paths, revnum, author, date, message, pool):
298 def receiver(orig_paths, revnum, author, date, message, pool):
288 paths = {}
299 paths = {}
289 if orig_paths is not None:
300 if orig_paths is not None:
290 for k, v in pycompat.iteritems(orig_paths):
301 for k, v in pycompat.iteritems(orig_paths):
291 paths[k] = changedpath(v)
302 paths[k] = changedpath(v)
292 self.append((paths, revnum, author, date, message))
303 self.append((paths, revnum, author, date, message))
293
304
294 # Use an ra of our own so that our parent can consume
305 # Use an ra of our own so that our parent can consume
295 # our results without confusing the server.
306 # our results without confusing the server.
296 t = transport.SvnRaTransport(url=url)
307 t = transport.SvnRaTransport(url=url)
297 svn.ra.get_log(
308 svn.ra.get_log(
298 t.ra,
309 t.ra,
299 paths,
310 paths,
300 start,
311 start,
301 end,
312 end,
302 limit,
313 limit,
303 discover_changed_paths,
314 discover_changed_paths,
304 strict_node_history,
315 strict_node_history,
305 receiver,
316 receiver,
306 )
317 )
307
318
308 def close(self):
319 def close(self):
309 pass
320 pass
310
321
311
322
312 # Check to see if the given path is a local Subversion repo. Verify this by
323 # Check to see if the given path is a local Subversion repo. Verify this by
313 # looking for several svn-specific files and directories in the given
324 # looking for several svn-specific files and directories in the given
314 # directory.
325 # directory.
315 def filecheck(ui, path, proto):
326 def filecheck(ui, path, proto):
316 for x in (b'locks', b'hooks', b'format', b'db'):
327 for x in (b'locks', b'hooks', b'format', b'db'):
317 if not os.path.exists(os.path.join(path, x)):
328 if not os.path.exists(os.path.join(path, x)):
318 return False
329 return False
319 return True
330 return True
320
331
321
332
322 # Check to see if a given path is the root of an svn repo over http. We verify
333 # Check to see if a given path is the root of an svn repo over http. We verify
323 # this by requesting a version-controlled URL we know can't exist and looking
334 # this by requesting a version-controlled URL we know can't exist and looking
324 # for the svn-specific "not found" XML.
335 # for the svn-specific "not found" XML.
325 def httpcheck(ui, path, proto):
336 def httpcheck(ui, path, proto):
326 try:
337 try:
327 opener = urlreq.buildopener()
338 opener = urlreq.buildopener()
328 rsp = opener.open(
339 rsp = opener.open(
329 pycompat.strurl(b'%s://%s/!svn/ver/0/.svn' % (proto, path)), b'rb'
340 pycompat.strurl(b'%s://%s/!svn/ver/0/.svn' % (proto, path)), b'rb'
330 )
341 )
331 data = rsp.read()
342 data = rsp.read()
332 except urlerr.httperror as inst:
343 except urlerr.httperror as inst:
333 if inst.code != 404:
344 if inst.code != 404:
334 # Except for 404 we cannot know for sure this is not an svn repo
345 # Except for 404 we cannot know for sure this is not an svn repo
335 ui.warn(
346 ui.warn(
336 _(
347 _(
337 b'svn: cannot probe remote repository, assume it could '
348 b'svn: cannot probe remote repository, assume it could '
338 b'be a subversion repository. Use --source-type if you '
349 b'be a subversion repository. Use --source-type if you '
339 b'know better.\n'
350 b'know better.\n'
340 )
351 )
341 )
352 )
342 return True
353 return True
343 data = inst.fp.read()
354 data = inst.fp.read()
344 except Exception:
355 except Exception:
345 # Could be urlerr.urlerror if the URL is invalid or anything else.
356 # Could be urlerr.urlerror if the URL is invalid or anything else.
346 return False
357 return False
347 return b'<m:human-readable errcode="160013">' in data
358 return b'<m:human-readable errcode="160013">' in data
348
359
349
360
350 protomap = {
361 protomap = {
351 b'http': httpcheck,
362 b'http': httpcheck,
352 b'https': httpcheck,
363 b'https': httpcheck,
353 b'file': filecheck,
364 b'file': filecheck,
354 }
365 }
355
366
356
367
357 class NonUtf8PercentEncodedBytes(Exception):
368 class NonUtf8PercentEncodedBytes(Exception):
358 pass
369 pass
359
370
360
371
361 # Subversion paths are Unicode. Since the percent-decoding is done on
372 # Subversion paths are Unicode. Since the percent-decoding is done on
362 # UTF-8-encoded strings, percent-encoded bytes are interpreted as UTF-8.
373 # UTF-8-encoded strings, percent-encoded bytes are interpreted as UTF-8.
363 def url2pathname_like_subversion(unicodepath):
374 def url2pathname_like_subversion(unicodepath):
364 if pycompat.ispy3:
375 if pycompat.ispy3:
365 # On Python 3, we have to pass unicode to urlreq.url2pathname().
376 # On Python 3, we have to pass unicode to urlreq.url2pathname().
366 # Percent-decoded bytes get decoded using UTF-8 and the 'replace' error
377 # Percent-decoded bytes get decoded using UTF-8 and the 'replace' error
367 # handler.
378 # handler.
368 unicodepath = urlreq.url2pathname(unicodepath)
379 unicodepath = urlreq.url2pathname(unicodepath)
369 if u'\N{REPLACEMENT CHARACTER}' in unicodepath:
380 if u'\N{REPLACEMENT CHARACTER}' in unicodepath:
370 raise NonUtf8PercentEncodedBytes
381 raise NonUtf8PercentEncodedBytes
371 else:
382 else:
372 return unicodepath
383 return unicodepath
373 else:
384 else:
374 # If we passed unicode on Python 2, it would be converted using the
385 # If we passed unicode on Python 2, it would be converted using the
375 # latin-1 encoding. Therefore, we pass UTF-8-encoded bytes.
386 # latin-1 encoding. Therefore, we pass UTF-8-encoded bytes.
376 unicodepath = urlreq.url2pathname(unicodepath.encode('utf-8'))
387 unicodepath = urlreq.url2pathname(unicodepath.encode('utf-8'))
377 try:
388 try:
378 return unicodepath.decode('utf-8')
389 return unicodepath.decode('utf-8')
379 except UnicodeDecodeError:
390 except UnicodeDecodeError:
380 raise NonUtf8PercentEncodedBytes
391 raise NonUtf8PercentEncodedBytes
381
392
382
393
383 def issvnurl(ui, url):
394 def issvnurl(ui, url):
384 try:
395 try:
385 proto, path = url.split(b'://', 1)
396 proto, path = url.split(b'://', 1)
386 if proto == b'file':
397 if proto == b'file':
387 if (
398 if (
388 pycompat.iswindows
399 pycompat.iswindows
389 and path[:1] == b'/'
400 and path[:1] == b'/'
390 and path[1:2].isalpha()
401 and path[1:2].isalpha()
391 and path[2:6].lower() == b'%3a/'
402 and path[2:6].lower() == b'%3a/'
392 ):
403 ):
393 path = path[:2] + b':/' + path[6:]
404 path = path[:2] + b':/' + path[6:]
394 try:
405 try:
395 unicodepath = path.decode(fsencoding)
406 unicodepath = path.decode(fsencoding)
396 except UnicodeDecodeError:
407 except UnicodeDecodeError:
397 ui.warn(
408 ui.warn(
398 _(
409 _(
399 b'Subversion requires that file URLs can be converted '
410 b'Subversion requires that file URLs can be converted '
400 b'to Unicode using the current locale encoding (%s)\n'
411 b'to Unicode using the current locale encoding (%s)\n'
401 )
412 )
402 % pycompat.sysbytes(fsencoding)
413 % pycompat.sysbytes(fsencoding)
403 )
414 )
404 return False
415 return False
405 try:
416 try:
406 unicodepath = url2pathname_like_subversion(unicodepath)
417 unicodepath = url2pathname_like_subversion(unicodepath)
407 except NonUtf8PercentEncodedBytes:
418 except NonUtf8PercentEncodedBytes:
408 ui.warn(
419 ui.warn(
409 _(
420 _(
410 b'Subversion does not support non-UTF-8 '
421 b'Subversion does not support non-UTF-8 '
411 b'percent-encoded bytes in file URLs\n'
422 b'percent-encoded bytes in file URLs\n'
412 )
423 )
413 )
424 )
414 return False
425 return False
415 # Below, we approximate how Subversion checks the path. On Unix, we
426 # Below, we approximate how Subversion checks the path. On Unix, we
416 # should therefore convert the path to bytes using `fsencoding`
427 # should therefore convert the path to bytes using `fsencoding`
417 # (like Subversion does). On Windows, the right thing would
428 # (like Subversion does). On Windows, the right thing would
418 # actually be to leave the path as unicode. For now, we restrict
429 # actually be to leave the path as unicode. For now, we restrict
419 # the path to MBCS.
430 # the path to MBCS.
420 path = unicodepath.encode(fsencoding)
431 path = unicodepath.encode(fsencoding)
421 except ValueError:
432 except ValueError:
422 proto = b'file'
433 proto = b'file'
423 path = os.path.abspath(url)
434 path = os.path.abspath(url)
424 try:
435 try:
425 path.decode(fsencoding)
436 path.decode(fsencoding)
426 except UnicodeDecodeError:
437 except UnicodeDecodeError:
427 ui.warn(
438 ui.warn(
428 _(
439 _(
429 b'Subversion requires that paths can be converted to '
440 b'Subversion requires that paths can be converted to '
430 b'Unicode using the current locale encoding (%s)\n'
441 b'Unicode using the current locale encoding (%s)\n'
431 )
442 )
432 % pycompat.sysbytes(fsencoding)
443 % pycompat.sysbytes(fsencoding)
433 )
444 )
434 return False
445 return False
435 if proto == b'file':
446 if proto == b'file':
436 path = util.pconvert(path)
447 path = util.pconvert(path)
437 elif proto in (b'http', 'https'):
448 elif proto in (b'http', 'https'):
438 if not encoding.isasciistr(path):
449 if not encoding.isasciistr(path):
439 ui.warn(
450 ui.warn(
440 _(
451 _(
441 b"Subversion sources don't support non-ASCII characters in "
452 b"Subversion sources don't support non-ASCII characters in "
442 b"HTTP(S) URLs. Please percent-encode them.\n"
453 b"HTTP(S) URLs. Please percent-encode them.\n"
443 )
454 )
444 )
455 )
445 return False
456 return False
446 check = protomap.get(proto, lambda *args: False)
457 check = protomap.get(proto, lambda *args: False)
447 while b'/' in path:
458 while b'/' in path:
448 if check(ui, path, proto):
459 if check(ui, path, proto):
449 return True
460 return True
450 path = path.rsplit(b'/', 1)[0]
461 path = path.rsplit(b'/', 1)[0]
451 return False
462 return False
452
463
453
464
454 # SVN conversion code stolen from bzr-svn and tailor
465 # SVN conversion code stolen from bzr-svn and tailor
455 #
466 #
456 # Subversion looks like a versioned filesystem, branches structures
467 # Subversion looks like a versioned filesystem, branches structures
457 # are defined by conventions and not enforced by the tool. First,
468 # are defined by conventions and not enforced by the tool. First,
458 # we define the potential branches (modules) as "trunk" and "branches"
469 # we define the potential branches (modules) as "trunk" and "branches"
459 # children directories. Revisions are then identified by their
470 # children directories. Revisions are then identified by their
460 # module and revision number (and a repository identifier).
471 # module and revision number (and a repository identifier).
461 #
472 #
462 # The revision graph is really a tree (or a forest). By default, a
473 # The revision graph is really a tree (or a forest). By default, a
463 # revision parent is the previous revision in the same module. If the
474 # revision parent is the previous revision in the same module. If the
464 # module directory is copied/moved from another module then the
475 # module directory is copied/moved from another module then the
465 # revision is the module root and its parent the source revision in
476 # revision is the module root and its parent the source revision in
466 # the parent module. A revision has at most one parent.
477 # the parent module. A revision has at most one parent.
467 #
478 #
468 class svn_source(converter_source):
479 class svn_source(converter_source):
469 def __init__(self, ui, repotype, url, revs=None):
480 def __init__(self, ui, repotype, url, revs=None):
470 super(svn_source, self).__init__(ui, repotype, url, revs=revs)
481 super(svn_source, self).__init__(ui, repotype, url, revs=revs)
471
482
472 init_fsencoding()
483 init_fsencoding()
473 if not (
484 if not (
474 url.startswith(b'svn://')
485 url.startswith(b'svn://')
475 or url.startswith(b'svn+ssh://')
486 or url.startswith(b'svn+ssh://')
476 or (
487 or (
477 os.path.exists(url)
488 os.path.exists(url)
478 and os.path.exists(os.path.join(url, b'.svn'))
489 and os.path.exists(os.path.join(url, b'.svn'))
479 )
490 )
480 or issvnurl(ui, url)
491 or issvnurl(ui, url)
481 ):
492 ):
482 raise NoRepo(
493 raise NoRepo(
483 _(b"%s does not look like a Subversion repository") % url
494 _(b"%s does not look like a Subversion repository") % url
484 )
495 )
485 if svn is None:
496 if svn is None:
486 raise MissingTool(_(b'could not load Subversion python bindings'))
497 raise MissingTool(_(b'could not load Subversion python bindings'))
487
498
488 try:
499 try:
489 version = svn.core.SVN_VER_MAJOR, svn.core.SVN_VER_MINOR
500 version = svn.core.SVN_VER_MAJOR, svn.core.SVN_VER_MINOR
490 if version < (1, 4):
501 if version < (1, 4):
491 raise MissingTool(
502 raise MissingTool(
492 _(
503 _(
493 b'Subversion python bindings %d.%d found, '
504 b'Subversion python bindings %d.%d found, '
494 b'1.4 or later required'
505 b'1.4 or later required'
495 )
506 )
496 % version
507 % version
497 )
508 )
498 except AttributeError:
509 except AttributeError:
499 raise MissingTool(
510 raise MissingTool(
500 _(
511 _(
501 b'Subversion python bindings are too old, 1.4 '
512 b'Subversion python bindings are too old, 1.4 '
502 b'or later required'
513 b'or later required'
503 )
514 )
504 )
515 )
505
516
506 self.lastrevs = {}
517 self.lastrevs = {}
507
518
508 latest = None
519 latest = None
509 try:
520 try:
510 # Support file://path@rev syntax. Useful e.g. to convert
521 # Support file://path@rev syntax. Useful e.g. to convert
511 # deleted branches.
522 # deleted branches.
512 at = url.rfind(b'@')
523 at = url.rfind(b'@')
513 if at >= 0:
524 if at >= 0:
514 latest = int(url[at + 1 :])
525 latest = int(url[at + 1 :])
515 url = url[:at]
526 url = url[:at]
516 except ValueError:
527 except ValueError:
517 pass
528 pass
518 self.url = geturl(url)
529 self.url = geturl(url)
519 self.encoding = b'UTF-8' # Subversion is always nominal UTF-8
530 self.encoding = b'UTF-8' # Subversion is always nominal UTF-8
520 try:
531 try:
521 with util.with_lc_ctype():
532 with util.with_lc_ctype():
522 self.transport = transport.SvnRaTransport(url=self.url)
533 self.transport = transport.SvnRaTransport(url=self.url)
523 self.ra = self.transport.ra
534 self.ra = self.transport.ra
524 self.ctx = self.transport.client
535 self.ctx = self.transport.client
525 self.baseurl = svn.ra.get_repos_root(self.ra)
536 self.baseurl = svn.ra.get_repos_root(self.ra)
526 # Module is either empty or a repository path starting with
537 # Module is either empty or a repository path starting with
527 # a slash and not ending with a slash.
538 # a slash and not ending with a slash.
528 self.module = urlreq.unquote(self.url[len(self.baseurl) :])
539 self.module = urlreq.unquote(self.url[len(self.baseurl) :])
529 self.prevmodule = None
540 self.prevmodule = None
530 self.rootmodule = self.module
541 self.rootmodule = self.module
531 self.commits = {}
542 self.commits = {}
532 self.paths = {}
543 self.paths = {}
533 self.uuid = svn.ra.get_uuid(self.ra)
544 self.uuid = svn.ra.get_uuid(self.ra)
534 except svn.core.SubversionException:
545 except svn.core.SubversionException:
535 ui.traceback()
546 ui.traceback()
536 svnversion = b'%d.%d.%d' % (
547 svnversion = b'%d.%d.%d' % (
537 svn.core.SVN_VER_MAJOR,
548 svn.core.SVN_VER_MAJOR,
538 svn.core.SVN_VER_MINOR,
549 svn.core.SVN_VER_MINOR,
539 svn.core.SVN_VER_MICRO,
550 svn.core.SVN_VER_MICRO,
540 )
551 )
541 raise NoRepo(
552 raise NoRepo(
542 _(
553 _(
543 b"%s does not look like a Subversion repository "
554 b"%s does not look like a Subversion repository "
544 b"to libsvn version %s"
555 b"to libsvn version %s"
545 )
556 )
546 % (self.url, svnversion)
557 % (self.url, svnversion)
547 )
558 )
548
559
549 if revs:
560 if revs:
550 if len(revs) > 1:
561 if len(revs) > 1:
551 raise error.Abort(
562 raise error.Abort(
552 _(
563 _(
553 b'subversion source does not support '
564 b'subversion source does not support '
554 b'specifying multiple revisions'
565 b'specifying multiple revisions'
555 )
566 )
556 )
567 )
557 try:
568 try:
558 latest = int(revs[0])
569 latest = int(revs[0])
559 except ValueError:
570 except ValueError:
560 raise error.Abort(
571 raise error.Abort(
561 _(b'svn: revision %s is not an integer') % revs[0]
572 _(b'svn: revision %s is not an integer') % revs[0]
562 )
573 )
563
574
564 trunkcfg = self.ui.config(b'convert', b'svn.trunk')
575 trunkcfg = self.ui.config(b'convert', b'svn.trunk')
565 if trunkcfg is None:
576 if trunkcfg is None:
566 trunkcfg = b'trunk'
577 trunkcfg = b'trunk'
567 self.trunkname = trunkcfg.strip(b'/')
578 self.trunkname = trunkcfg.strip(b'/')
568 self.startrev = self.ui.config(b'convert', b'svn.startrev')
579 self.startrev = self.ui.config(b'convert', b'svn.startrev')
569 try:
580 try:
570 self.startrev = int(self.startrev)
581 self.startrev = int(self.startrev)
571 if self.startrev < 0:
582 if self.startrev < 0:
572 self.startrev = 0
583 self.startrev = 0
573 except ValueError:
584 except ValueError:
574 raise error.Abort(
585 raise error.Abort(
575 _(b'svn: start revision %s is not an integer') % self.startrev
586 _(b'svn: start revision %s is not an integer') % self.startrev
576 )
587 )
577
588
578 try:
589 try:
579 with util.with_lc_ctype():
590 with util.with_lc_ctype():
580 self.head = self.latest(self.module, latest)
591 self.head = self.latest(self.module, latest)
581 except SvnPathNotFound:
592 except SvnPathNotFound:
582 self.head = None
593 self.head = None
583 if not self.head:
594 if not self.head:
584 raise error.Abort(
595 raise error.Abort(
585 _(b'no revision found in module %s') % self.module
596 _(b'no revision found in module %s') % self.module
586 )
597 )
587 self.last_changed = self.revnum(self.head)
598 self.last_changed = self.revnum(self.head)
588
599
589 self._changescache = (None, None)
600 self._changescache = (None, None)
590
601
591 if os.path.exists(os.path.join(url, b'.svn/entries')):
602 if os.path.exists(os.path.join(url, b'.svn/entries')):
592 self.wc = url
603 self.wc = url
593 else:
604 else:
594 self.wc = None
605 self.wc = None
595 self.convertfp = None
606 self.convertfp = None
596
607
597 def before(self):
608 def before(self):
598 self.with_lc_ctype = util.with_lc_ctype()
609 self.with_lc_ctype = util.with_lc_ctype()
599 self.with_lc_ctype.__enter__()
610 self.with_lc_ctype.__enter__()
600
611
601 def after(self):
612 def after(self):
602 self.with_lc_ctype.__exit__(None, None, None)
613 self.with_lc_ctype.__exit__(None, None, None)
603
614
604 def setrevmap(self, revmap):
615 def setrevmap(self, revmap):
605 lastrevs = {}
616 lastrevs = {}
606 for revid in revmap:
617 for revid in revmap:
607 uuid, module, revnum = revsplit(revid)
618 uuid, module, revnum = revsplit(revid)
608 lastrevnum = lastrevs.setdefault(module, revnum)
619 lastrevnum = lastrevs.setdefault(module, revnum)
609 if revnum > lastrevnum:
620 if revnum > lastrevnum:
610 lastrevs[module] = revnum
621 lastrevs[module] = revnum
611 self.lastrevs = lastrevs
622 self.lastrevs = lastrevs
612
623
613 def exists(self, path, optrev):
624 def exists(self, path, optrev):
614 try:
625 try:
615 svn.client.ls(
626 svn.client.ls(
616 self.url.rstrip(b'/') + b'/' + quote(path),
627 self.url.rstrip(b'/') + b'/' + quote(path),
617 optrev,
628 optrev,
618 False,
629 False,
619 self.ctx,
630 self.ctx,
620 )
631 )
621 return True
632 return True
622 except svn.core.SubversionException:
633 except svn.core.SubversionException:
623 return False
634 return False
624
635
625 def getheads(self):
636 def getheads(self):
626 def isdir(path, revnum):
637 def isdir(path, revnum):
627 kind = self._checkpath(path, revnum)
638 kind = self._checkpath(path, revnum)
628 return kind == svn.core.svn_node_dir
639 return kind == svn.core.svn_node_dir
629
640
630 def getcfgpath(name, rev):
641 def getcfgpath(name, rev):
631 cfgpath = self.ui.config(b'convert', b'svn.' + name)
642 cfgpath = self.ui.config(b'convert', b'svn.' + name)
632 if cfgpath is not None and cfgpath.strip() == b'':
643 if cfgpath is not None and cfgpath.strip() == b'':
633 return None
644 return None
634 path = (cfgpath or name).strip(b'/')
645 path = (cfgpath or name).strip(b'/')
635 if not self.exists(path, rev):
646 if not self.exists(path, rev):
636 if self.module.endswith(path) and name == b'trunk':
647 if self.module.endswith(path) and name == b'trunk':
637 # we are converting from inside this directory
648 # we are converting from inside this directory
638 return None
649 return None
639 if cfgpath:
650 if cfgpath:
640 raise error.Abort(
651 raise error.Abort(
641 _(b'expected %s to be at %r, but not found')
652 _(b'expected %s to be at %r, but not found')
642 % (name, path)
653 % (name, path)
643 )
654 )
644 return None
655 return None
645 self.ui.note(
656 self.ui.note(
646 _(b'found %s at %r\n') % (name, pycompat.bytestr(path))
657 _(b'found %s at %r\n') % (name, pycompat.bytestr(path))
647 )
658 )
648 return path
659 return path
649
660
650 rev = optrev(self.last_changed)
661 rev = optrev(self.last_changed)
651 oldmodule = b''
662 oldmodule = b''
652 trunk = getcfgpath(b'trunk', rev)
663 trunk = getcfgpath(b'trunk', rev)
653 self.tags = getcfgpath(b'tags', rev)
664 self.tags = getcfgpath(b'tags', rev)
654 branches = getcfgpath(b'branches', rev)
665 branches = getcfgpath(b'branches', rev)
655
666
656 # If the project has a trunk or branches, we will extract heads
667 # If the project has a trunk or branches, we will extract heads
657 # from them. We keep the project root otherwise.
668 # from them. We keep the project root otherwise.
658 if trunk:
669 if trunk:
659 oldmodule = self.module or b''
670 oldmodule = self.module or b''
660 self.module += b'/' + trunk
671 self.module += b'/' + trunk
661 self.head = self.latest(self.module, self.last_changed)
672 self.head = self.latest(self.module, self.last_changed)
662 if not self.head:
673 if not self.head:
663 raise error.Abort(
674 raise error.Abort(
664 _(b'no revision found in module %s') % self.module
675 _(b'no revision found in module %s') % self.module
665 )
676 )
666
677
667 # First head in the list is the module's head
678 # First head in the list is the module's head
668 self.heads = [self.head]
679 self.heads = [self.head]
669 if self.tags is not None:
680 if self.tags is not None:
670 self.tags = b'%s/%s' % (oldmodule, (self.tags or b'tags'))
681 self.tags = b'%s/%s' % (oldmodule, (self.tags or b'tags'))
671
682
672 # Check if branches bring a few more heads to the list
683 # Check if branches bring a few more heads to the list
673 if branches:
684 if branches:
674 rpath = self.url.strip(b'/')
685 rpath = self.url.strip(b'/')
675 branchnames = svn.client.ls(
686 branchnames = svn.client.ls(
676 rpath + b'/' + quote(branches), rev, False, self.ctx
687 rpath + b'/' + quote(branches), rev, False, self.ctx
677 )
688 )
678 for branch in sorted(branchnames):
689 for branch in sorted(branchnames):
679 module = b'%s/%s/%s' % (oldmodule, branches, branch)
690 module = b'%s/%s/%s' % (oldmodule, branches, branch)
680 if not isdir(module, self.last_changed):
691 if not isdir(module, self.last_changed):
681 continue
692 continue
682 brevid = self.latest(module, self.last_changed)
693 brevid = self.latest(module, self.last_changed)
683 if not brevid:
694 if not brevid:
684 self.ui.note(_(b'ignoring empty branch %s\n') % branch)
695 self.ui.note(_(b'ignoring empty branch %s\n') % branch)
685 continue
696 continue
686 self.ui.note(
697 self.ui.note(
687 _(b'found branch %s at %d\n')
698 _(b'found branch %s at %d\n')
688 % (branch, self.revnum(brevid))
699 % (branch, self.revnum(brevid))
689 )
700 )
690 self.heads.append(brevid)
701 self.heads.append(brevid)
691
702
692 if self.startrev and self.heads:
703 if self.startrev and self.heads:
693 if len(self.heads) > 1:
704 if len(self.heads) > 1:
694 raise error.Abort(
705 raise error.Abort(
695 _(
706 _(
696 b'svn: start revision is not supported '
707 b'svn: start revision is not supported '
697 b'with more than one branch'
708 b'with more than one branch'
698 )
709 )
699 )
710 )
700 revnum = self.revnum(self.heads[0])
711 revnum = self.revnum(self.heads[0])
701 if revnum < self.startrev:
712 if revnum < self.startrev:
702 raise error.Abort(
713 raise error.Abort(
703 _(b'svn: no revision found after start revision %d')
714 _(b'svn: no revision found after start revision %d')
704 % self.startrev
715 % self.startrev
705 )
716 )
706
717
707 return self.heads
718 return self.heads
708
719
709 def _getchanges(self, rev, full):
720 def _getchanges(self, rev, full):
710 (paths, parents) = self.paths[rev]
721 (paths, parents) = self.paths[rev]
711 copies = {}
722 copies = {}
712 if parents:
723 if parents:
713 files, self.removed, copies = self.expandpaths(rev, paths, parents)
724 files, self.removed, copies = self.expandpaths(rev, paths, parents)
714 if full or not parents:
725 if full or not parents:
715 # Perform a full checkout on roots
726 # Perform a full checkout on roots
716 uuid, module, revnum = revsplit(rev)
727 uuid, module, revnum = revsplit(rev)
717 entries = svn.client.ls(
728 entries = svn.client.ls(
718 self.baseurl + quote(module), optrev(revnum), True, self.ctx
729 self.baseurl + quote(module), optrev(revnum), True, self.ctx
719 )
730 )
720 files = [
731 files = [
721 n
732 n
722 for n, e in pycompat.iteritems(entries)
733 for n, e in pycompat.iteritems(entries)
723 if e.kind == svn.core.svn_node_file
734 if e.kind == svn.core.svn_node_file
724 ]
735 ]
725 self.removed = set()
736 self.removed = set()
726
737
727 files.sort()
738 files.sort()
728 files = pycompat.ziplist(files, [rev] * len(files))
739 files = pycompat.ziplist(files, [rev] * len(files))
729 return (files, copies)
740 return (files, copies)
730
741
731 def getchanges(self, rev, full):
742 def getchanges(self, rev, full):
732 # reuse cache from getchangedfiles
743 # reuse cache from getchangedfiles
733 if self._changescache[0] == rev and not full:
744 if self._changescache[0] == rev and not full:
734 (files, copies) = self._changescache[1]
745 (files, copies) = self._changescache[1]
735 else:
746 else:
736 (files, copies) = self._getchanges(rev, full)
747 (files, copies) = self._getchanges(rev, full)
737 # caller caches the result, so free it here to release memory
748 # caller caches the result, so free it here to release memory
738 del self.paths[rev]
749 del self.paths[rev]
739 return (files, copies, set())
750 return (files, copies, set())
740
751
741 def getchangedfiles(self, rev, i):
752 def getchangedfiles(self, rev, i):
742 # called from filemap - cache computed values for reuse in getchanges
753 # called from filemap - cache computed values for reuse in getchanges
743 (files, copies) = self._getchanges(rev, False)
754 (files, copies) = self._getchanges(rev, False)
744 self._changescache = (rev, (files, copies))
755 self._changescache = (rev, (files, copies))
745 return [f[0] for f in files]
756 return [f[0] for f in files]
746
757
747 def getcommit(self, rev):
758 def getcommit(self, rev):
748 if rev not in self.commits:
759 if rev not in self.commits:
749 uuid, module, revnum = revsplit(rev)
760 uuid, module, revnum = revsplit(rev)
750 self.module = module
761 self.module = module
751 self.reparent(module)
762 self.reparent(module)
752 # We assume that:
763 # We assume that:
753 # - requests for revisions after "stop" come from the
764 # - requests for revisions after "stop" come from the
754 # revision graph backward traversal. Cache all of them
765 # revision graph backward traversal. Cache all of them
755 # down to stop, they will be used eventually.
766 # down to stop, they will be used eventually.
756 # - requests for revisions before "stop" come to get
767 # - requests for revisions before "stop" come to get
757 # isolated branches parents. Just fetch what is needed.
768 # isolated branches parents. Just fetch what is needed.
758 stop = self.lastrevs.get(module, 0)
769 stop = self.lastrevs.get(module, 0)
759 if revnum < stop:
770 if revnum < stop:
760 stop = revnum + 1
771 stop = revnum + 1
761 self._fetch_revisions(revnum, stop)
772 self._fetch_revisions(revnum, stop)
762 if rev not in self.commits:
773 if rev not in self.commits:
763 raise error.Abort(_(b'svn: revision %s not found') % revnum)
774 raise error.Abort(_(b'svn: revision %s not found') % revnum)
764 revcommit = self.commits[rev]
775 revcommit = self.commits[rev]
765 # caller caches the result, so free it here to release memory
776 # caller caches the result, so free it here to release memory
766 del self.commits[rev]
777 del self.commits[rev]
767 return revcommit
778 return revcommit
768
779
769 def checkrevformat(self, revstr, mapname=b'splicemap'):
780 def checkrevformat(self, revstr, mapname=b'splicemap'):
770 """ fails if revision format does not match the correct format"""
781 """ fails if revision format does not match the correct format"""
771 if not re.match(
782 if not re.match(
772 br'svn:[0-9a-f]{8,8}-[0-9a-f]{4,4}-'
783 br'svn:[0-9a-f]{8,8}-[0-9a-f]{4,4}-'
773 br'[0-9a-f]{4,4}-[0-9a-f]{4,4}-[0-9a-f]'
784 br'[0-9a-f]{4,4}-[0-9a-f]{4,4}-[0-9a-f]'
774 br'{12,12}(.*)@[0-9]+$',
785 br'{12,12}(.*)@[0-9]+$',
775 revstr,
786 revstr,
776 ):
787 ):
777 raise error.Abort(
788 raise error.Abort(
778 _(b'%s entry %s is not a valid revision identifier')
789 _(b'%s entry %s is not a valid revision identifier')
779 % (mapname, revstr)
790 % (mapname, revstr)
780 )
791 )
781
792
782 def numcommits(self):
793 def numcommits(self):
783 return int(self.head.rsplit(b'@', 1)[1]) - self.startrev
794 return int(self.head.rsplit(b'@', 1)[1]) - self.startrev
784
795
785 def gettags(self):
796 def gettags(self):
786 tags = {}
797 tags = {}
787 if self.tags is None:
798 if self.tags is None:
788 return tags
799 return tags
789
800
790 # svn tags are just a convention, project branches left in a
801 # svn tags are just a convention, project branches left in a
791 # 'tags' directory. There is no other relationship than
802 # 'tags' directory. There is no other relationship than
792 # ancestry, which is expensive to discover and makes them hard
803 # ancestry, which is expensive to discover and makes them hard
793 # to update incrementally. Worse, past revisions may be
804 # to update incrementally. Worse, past revisions may be
794 # referenced by tags far away in the future, requiring a deep
805 # referenced by tags far away in the future, requiring a deep
795 # history traversal on every calculation. Current code
806 # history traversal on every calculation. Current code
796 # performs a single backward traversal, tracking moves within
807 # performs a single backward traversal, tracking moves within
797 # the tags directory (tag renaming) and recording a new tag
808 # the tags directory (tag renaming) and recording a new tag
798 # everytime a project is copied from outside the tags
809 # everytime a project is copied from outside the tags
799 # directory. It also lists deleted tags, this behaviour may
810 # directory. It also lists deleted tags, this behaviour may
800 # change in the future.
811 # change in the future.
801 pendings = []
812 pendings = []
802 tagspath = self.tags
813 tagspath = self.tags
803 start = svn.ra.get_latest_revnum(self.ra)
814 start = svn.ra.get_latest_revnum(self.ra)
804 stream = self._getlog([self.tags], start, self.startrev)
815 stream = self._getlog([self.tags], start, self.startrev)
805 try:
816 try:
806 for entry in stream:
817 for entry in stream:
807 origpaths, revnum, author, date, message = entry
818 origpaths, revnum, author, date, message = entry
808 if not origpaths:
819 if not origpaths:
809 origpaths = []
820 origpaths = []
810 copies = [
821 copies = [
811 (e.copyfrom_path, e.copyfrom_rev, p)
822 (e.copyfrom_path, e.copyfrom_rev, p)
812 for p, e in pycompat.iteritems(origpaths)
823 for p, e in pycompat.iteritems(origpaths)
813 if e.copyfrom_path
824 if e.copyfrom_path
814 ]
825 ]
815 # Apply moves/copies from more specific to general
826 # Apply moves/copies from more specific to general
816 copies.sort(reverse=True)
827 copies.sort(reverse=True)
817
828
818 srctagspath = tagspath
829 srctagspath = tagspath
819 if copies and copies[-1][2] == tagspath:
830 if copies and copies[-1][2] == tagspath:
820 # Track tags directory moves
831 # Track tags directory moves
821 srctagspath = copies.pop()[0]
832 srctagspath = copies.pop()[0]
822
833
823 for source, sourcerev, dest in copies:
834 for source, sourcerev, dest in copies:
824 if not dest.startswith(tagspath + b'/'):
835 if not dest.startswith(tagspath + b'/'):
825 continue
836 continue
826 for tag in pendings:
837 for tag in pendings:
827 if tag[0].startswith(dest):
838 if tag[0].startswith(dest):
828 tagpath = source + tag[0][len(dest) :]
839 tagpath = source + tag[0][len(dest) :]
829 tag[:2] = [tagpath, sourcerev]
840 tag[:2] = [tagpath, sourcerev]
830 break
841 break
831 else:
842 else:
832 pendings.append([source, sourcerev, dest])
843 pendings.append([source, sourcerev, dest])
833
844
834 # Filter out tags with children coming from different
845 # Filter out tags with children coming from different
835 # parts of the repository like:
846 # parts of the repository like:
836 # /tags/tag.1 (from /trunk:10)
847 # /tags/tag.1 (from /trunk:10)
837 # /tags/tag.1/foo (from /branches/foo:12)
848 # /tags/tag.1/foo (from /branches/foo:12)
838 # Here/tags/tag.1 discarded as well as its children.
849 # Here/tags/tag.1 discarded as well as its children.
839 # It happens with tools like cvs2svn. Such tags cannot
850 # It happens with tools like cvs2svn. Such tags cannot
840 # be represented in mercurial.
851 # be represented in mercurial.
841 addeds = {
852 addeds = {
842 p: e.copyfrom_path
853 p: e.copyfrom_path
843 for p, e in pycompat.iteritems(origpaths)
854 for p, e in pycompat.iteritems(origpaths)
844 if e.action == b'A' and e.copyfrom_path
855 if e.action == b'A' and e.copyfrom_path
845 }
856 }
846 badroots = set()
857 badroots = set()
847 for destroot in addeds:
858 for destroot in addeds:
848 for source, sourcerev, dest in pendings:
859 for source, sourcerev, dest in pendings:
849 if not dest.startswith(
860 if not dest.startswith(
850 destroot + b'/'
861 destroot + b'/'
851 ) or source.startswith(addeds[destroot] + b'/'):
862 ) or source.startswith(addeds[destroot] + b'/'):
852 continue
863 continue
853 badroots.add(destroot)
864 badroots.add(destroot)
854 break
865 break
855
866
856 for badroot in badroots:
867 for badroot in badroots:
857 pendings = [
868 pendings = [
858 p
869 p
859 for p in pendings
870 for p in pendings
860 if p[2] != badroot
871 if p[2] != badroot
861 and not p[2].startswith(badroot + b'/')
872 and not p[2].startswith(badroot + b'/')
862 ]
873 ]
863
874
864 # Tell tag renamings from tag creations
875 # Tell tag renamings from tag creations
865 renamings = []
876 renamings = []
866 for source, sourcerev, dest in pendings:
877 for source, sourcerev, dest in pendings:
867 tagname = dest.split(b'/')[-1]
878 tagname = dest.split(b'/')[-1]
868 if source.startswith(srctagspath):
879 if source.startswith(srctagspath):
869 renamings.append([source, sourcerev, tagname])
880 renamings.append([source, sourcerev, tagname])
870 continue
881 continue
871 if tagname in tags:
882 if tagname in tags:
872 # Keep the latest tag value
883 # Keep the latest tag value
873 continue
884 continue
874 # From revision may be fake, get one with changes
885 # From revision may be fake, get one with changes
875 try:
886 try:
876 tagid = self.latest(source, sourcerev)
887 tagid = self.latest(source, sourcerev)
877 if tagid and tagname not in tags:
888 if tagid and tagname not in tags:
878 tags[tagname] = tagid
889 tags[tagname] = tagid
879 except SvnPathNotFound:
890 except SvnPathNotFound:
880 # It happens when we are following directories
891 # It happens when we are following directories
881 # we assumed were copied with their parents
892 # we assumed were copied with their parents
882 # but were really created in the tag
893 # but were really created in the tag
883 # directory.
894 # directory.
884 pass
895 pass
885 pendings = renamings
896 pendings = renamings
886 tagspath = srctagspath
897 tagspath = srctagspath
887 finally:
898 finally:
888 stream.close()
899 stream.close()
889 return tags
900 return tags
890
901
891 def converted(self, rev, destrev):
902 def converted(self, rev, destrev):
892 if not self.wc:
903 if not self.wc:
893 return
904 return
894 if self.convertfp is None:
905 if self.convertfp is None:
895 self.convertfp = open(
906 self.convertfp = open(
896 os.path.join(self.wc, b'.svn', b'hg-shamap'), b'ab'
907 os.path.join(self.wc, b'.svn', b'hg-shamap'), b'ab'
897 )
908 )
898 self.convertfp.write(
909 self.convertfp.write(
899 util.tonativeeol(b'%s %d\n' % (destrev, self.revnum(rev)))
910 util.tonativeeol(b'%s %d\n' % (destrev, self.revnum(rev)))
900 )
911 )
901 self.convertfp.flush()
912 self.convertfp.flush()
902
913
903 def revid(self, revnum, module=None):
914 def revid(self, revnum, module=None):
904 return b'svn:%s%s@%d' % (self.uuid, module or self.module, revnum)
915 return b'svn:%s%s@%d' % (self.uuid, module or self.module, revnum)
905
916
906 def revnum(self, rev):
917 def revnum(self, rev):
907 return int(rev.split(b'@')[-1])
918 return int(rev.split(b'@')[-1])
908
919
909 def latest(self, path, stop=None):
920 def latest(self, path, stop=None):
910 """Find the latest revid affecting path, up to stop revision
921 """Find the latest revid affecting path, up to stop revision
911 number. If stop is None, default to repository latest
922 number. If stop is None, default to repository latest
912 revision. It may return a revision in a different module,
923 revision. It may return a revision in a different module,
913 since a branch may be moved without a change being
924 since a branch may be moved without a change being
914 reported. Return None if computed module does not belong to
925 reported. Return None if computed module does not belong to
915 rootmodule subtree.
926 rootmodule subtree.
916 """
927 """
917
928
918 def findchanges(path, start, stop=None):
929 def findchanges(path, start, stop=None):
919 stream = self._getlog([path], start, stop or 1)
930 stream = self._getlog([path], start, stop or 1)
920 try:
931 try:
921 for entry in stream:
932 for entry in stream:
922 paths, revnum, author, date, message = entry
933 paths, revnum, author, date, message = entry
923 if stop is None and paths:
934 if stop is None and paths:
924 # We do not know the latest changed revision,
935 # We do not know the latest changed revision,
925 # keep the first one with changed paths.
936 # keep the first one with changed paths.
926 break
937 break
927 if stop is not None and revnum <= stop:
938 if stop is not None and revnum <= stop:
928 break
939 break
929
940
930 for p in paths:
941 for p in paths:
931 if not path.startswith(p) or not paths[p].copyfrom_path:
942 if not path.startswith(p) or not paths[p].copyfrom_path:
932 continue
943 continue
933 newpath = paths[p].copyfrom_path + path[len(p) :]
944 newpath = paths[p].copyfrom_path + path[len(p) :]
934 self.ui.debug(
945 self.ui.debug(
935 b"branch renamed from %s to %s at %d\n"
946 b"branch renamed from %s to %s at %d\n"
936 % (path, newpath, revnum)
947 % (path, newpath, revnum)
937 )
948 )
938 path = newpath
949 path = newpath
939 break
950 break
940 if not paths:
951 if not paths:
941 revnum = None
952 revnum = None
942 return revnum, path
953 return revnum, path
943 finally:
954 finally:
944 stream.close()
955 stream.close()
945
956
946 if not path.startswith(self.rootmodule):
957 if not path.startswith(self.rootmodule):
947 # Requests on foreign branches may be forbidden at server level
958 # Requests on foreign branches may be forbidden at server level
948 self.ui.debug(b'ignoring foreign branch %r\n' % path)
959 self.ui.debug(b'ignoring foreign branch %r\n' % path)
949 return None
960 return None
950
961
951 if stop is None:
962 if stop is None:
952 stop = svn.ra.get_latest_revnum(self.ra)
963 stop = svn.ra.get_latest_revnum(self.ra)
953 try:
964 try:
954 prevmodule = self.reparent(b'')
965 prevmodule = self.reparent(b'')
955 dirent = svn.ra.stat(self.ra, path.strip(b'/'), stop)
966 dirent = svn.ra.stat(self.ra, path.strip(b'/'), stop)
956 self.reparent(prevmodule)
967 self.reparent(prevmodule)
957 except svn.core.SubversionException:
968 except svn.core.SubversionException:
958 dirent = None
969 dirent = None
959 if not dirent:
970 if not dirent:
960 raise SvnPathNotFound(
971 raise SvnPathNotFound(
961 _(b'%s not found up to revision %d') % (path, stop)
972 _(b'%s not found up to revision %d') % (path, stop)
962 )
973 )
963
974
964 # stat() gives us the previous revision on this line of
975 # stat() gives us the previous revision on this line of
965 # development, but it might be in *another module*. Fetch the
976 # development, but it might be in *another module*. Fetch the
966 # log and detect renames down to the latest revision.
977 # log and detect renames down to the latest revision.
967 revnum, realpath = findchanges(path, stop, dirent.created_rev)
978 revnum, realpath = findchanges(path, stop, dirent.created_rev)
968 if revnum is None:
979 if revnum is None:
969 # Tools like svnsync can create empty revision, when
980 # Tools like svnsync can create empty revision, when
970 # synchronizing only a subtree for instance. These empty
981 # synchronizing only a subtree for instance. These empty
971 # revisions created_rev still have their original values
982 # revisions created_rev still have their original values
972 # despite all changes having disappeared and can be
983 # despite all changes having disappeared and can be
973 # returned by ra.stat(), at least when stating the root
984 # returned by ra.stat(), at least when stating the root
974 # module. In that case, do not trust created_rev and scan
985 # module. In that case, do not trust created_rev and scan
975 # the whole history.
986 # the whole history.
976 revnum, realpath = findchanges(path, stop)
987 revnum, realpath = findchanges(path, stop)
977 if revnum is None:
988 if revnum is None:
978 self.ui.debug(b'ignoring empty branch %r\n' % realpath)
989 self.ui.debug(b'ignoring empty branch %r\n' % realpath)
979 return None
990 return None
980
991
981 if not realpath.startswith(self.rootmodule):
992 if not realpath.startswith(self.rootmodule):
982 self.ui.debug(b'ignoring foreign branch %r\n' % realpath)
993 self.ui.debug(b'ignoring foreign branch %r\n' % realpath)
983 return None
994 return None
984 return self.revid(revnum, realpath)
995 return self.revid(revnum, realpath)
985
996
986 def reparent(self, module):
997 def reparent(self, module):
987 """Reparent the svn transport and return the previous parent."""
998 """Reparent the svn transport and return the previous parent."""
988 if self.prevmodule == module:
999 if self.prevmodule == module:
989 return module
1000 return module
990 svnurl = self.baseurl + quote(module)
1001 svnurl = self.baseurl + quote(module)
991 prevmodule = self.prevmodule
1002 prevmodule = self.prevmodule
992 if prevmodule is None:
1003 if prevmodule is None:
993 prevmodule = b''
1004 prevmodule = b''
994 self.ui.debug(b"reparent to %s\n" % svnurl)
1005 self.ui.debug(b"reparent to %s\n" % svnurl)
995 svn.ra.reparent(self.ra, svnurl)
1006 svn.ra.reparent(self.ra, svnurl)
996 self.prevmodule = module
1007 self.prevmodule = module
997 return prevmodule
1008 return prevmodule
998
1009
999 def expandpaths(self, rev, paths, parents):
1010 def expandpaths(self, rev, paths, parents):
1000 changed, removed = set(), set()
1011 changed, removed = set(), set()
1001 copies = {}
1012 copies = {}
1002
1013
1003 new_module, revnum = revsplit(rev)[1:]
1014 new_module, revnum = revsplit(rev)[1:]
1004 if new_module != self.module:
1015 if new_module != self.module:
1005 self.module = new_module
1016 self.module = new_module
1006 self.reparent(self.module)
1017 self.reparent(self.module)
1007
1018
1008 progress = self.ui.makeprogress(
1019 progress = self.ui.makeprogress(
1009 _(b'scanning paths'), unit=_(b'paths'), total=len(paths)
1020 _(b'scanning paths'), unit=_(b'paths'), total=len(paths)
1010 )
1021 )
1011 for i, (path, ent) in enumerate(paths):
1022 for i, (path, ent) in enumerate(paths):
1012 progress.update(i, item=path)
1023 progress.update(i, item=path)
1013 entrypath = self.getrelpath(path)
1024 entrypath = self.getrelpath(path)
1014
1025
1015 kind = self._checkpath(entrypath, revnum)
1026 kind = self._checkpath(entrypath, revnum)
1016 if kind == svn.core.svn_node_file:
1027 if kind == svn.core.svn_node_file:
1017 changed.add(self.recode(entrypath))
1028 changed.add(self.recode(entrypath))
1018 if not ent.copyfrom_path or not parents:
1029 if not ent.copyfrom_path or not parents:
1019 continue
1030 continue
1020 # Copy sources not in parent revisions cannot be
1031 # Copy sources not in parent revisions cannot be
1021 # represented, ignore their origin for now
1032 # represented, ignore their origin for now
1022 pmodule, prevnum = revsplit(parents[0])[1:]
1033 pmodule, prevnum = revsplit(parents[0])[1:]
1023 if ent.copyfrom_rev < prevnum:
1034 if ent.copyfrom_rev < prevnum:
1024 continue
1035 continue
1025 copyfrom_path = self.getrelpath(ent.copyfrom_path, pmodule)
1036 copyfrom_path = self.getrelpath(ent.copyfrom_path, pmodule)
1026 if not copyfrom_path:
1037 if not copyfrom_path:
1027 continue
1038 continue
1028 self.ui.debug(
1039 self.ui.debug(
1029 b"copied to %s from %s@%d\n"
1040 b"copied to %s from %s@%d\n"
1030 % (entrypath, copyfrom_path, ent.copyfrom_rev)
1041 % (entrypath, copyfrom_path, ent.copyfrom_rev)
1031 )
1042 )
1032 copies[self.recode(entrypath)] = self.recode(copyfrom_path)
1043 copies[self.recode(entrypath)] = self.recode(copyfrom_path)
1033 elif kind == 0: # gone, but had better be a deleted *file*
1044 elif kind == 0: # gone, but had better be a deleted *file*
1034 self.ui.debug(b"gone from %d\n" % ent.copyfrom_rev)
1045 self.ui.debug(b"gone from %d\n" % ent.copyfrom_rev)
1035 pmodule, prevnum = revsplit(parents[0])[1:]
1046 pmodule, prevnum = revsplit(parents[0])[1:]
1036 parentpath = pmodule + b"/" + entrypath
1047 parentpath = pmodule + b"/" + entrypath
1037 fromkind = self._checkpath(entrypath, prevnum, pmodule)
1048 fromkind = self._checkpath(entrypath, prevnum, pmodule)
1038
1049
1039 if fromkind == svn.core.svn_node_file:
1050 if fromkind == svn.core.svn_node_file:
1040 removed.add(self.recode(entrypath))
1051 removed.add(self.recode(entrypath))
1041 elif fromkind == svn.core.svn_node_dir:
1052 elif fromkind == svn.core.svn_node_dir:
1042 oroot = parentpath.strip(b'/')
1053 oroot = parentpath.strip(b'/')
1043 nroot = path.strip(b'/')
1054 nroot = path.strip(b'/')
1044 children = self._iterfiles(oroot, prevnum)
1055 children = self._iterfiles(oroot, prevnum)
1045 for childpath in children:
1056 for childpath in children:
1046 childpath = childpath.replace(oroot, nroot)
1057 childpath = childpath.replace(oroot, nroot)
1047 childpath = self.getrelpath(b"/" + childpath, pmodule)
1058 childpath = self.getrelpath(b"/" + childpath, pmodule)
1048 if childpath:
1059 if childpath:
1049 removed.add(self.recode(childpath))
1060 removed.add(self.recode(childpath))
1050 else:
1061 else:
1051 self.ui.debug(
1062 self.ui.debug(
1052 b'unknown path in revision %d: %s\n' % (revnum, path)
1063 b'unknown path in revision %d: %s\n' % (revnum, path)
1053 )
1064 )
1054 elif kind == svn.core.svn_node_dir:
1065 elif kind == svn.core.svn_node_dir:
1055 if ent.action == b'M':
1066 if ent.action == b'M':
1056 # If the directory just had a prop change,
1067 # If the directory just had a prop change,
1057 # then we shouldn't need to look for its children.
1068 # then we shouldn't need to look for its children.
1058 continue
1069 continue
1059 if ent.action == b'R' and parents:
1070 if ent.action == b'R' and parents:
1060 # If a directory is replacing a file, mark the previous
1071 # If a directory is replacing a file, mark the previous
1061 # file as deleted
1072 # file as deleted
1062 pmodule, prevnum = revsplit(parents[0])[1:]
1073 pmodule, prevnum = revsplit(parents[0])[1:]
1063 pkind = self._checkpath(entrypath, prevnum, pmodule)
1074 pkind = self._checkpath(entrypath, prevnum, pmodule)
1064 if pkind == svn.core.svn_node_file:
1075 if pkind == svn.core.svn_node_file:
1065 removed.add(self.recode(entrypath))
1076 removed.add(self.recode(entrypath))
1066 elif pkind == svn.core.svn_node_dir:
1077 elif pkind == svn.core.svn_node_dir:
1067 # We do not know what files were kept or removed,
1078 # We do not know what files were kept or removed,
1068 # mark them all as changed.
1079 # mark them all as changed.
1069 for childpath in self._iterfiles(pmodule, prevnum):
1080 for childpath in self._iterfiles(pmodule, prevnum):
1070 childpath = self.getrelpath(b"/" + childpath)
1081 childpath = self.getrelpath(b"/" + childpath)
1071 if childpath:
1082 if childpath:
1072 changed.add(self.recode(childpath))
1083 changed.add(self.recode(childpath))
1073
1084
1074 for childpath in self._iterfiles(path, revnum):
1085 for childpath in self._iterfiles(path, revnum):
1075 childpath = self.getrelpath(b"/" + childpath)
1086 childpath = self.getrelpath(b"/" + childpath)
1076 if childpath:
1087 if childpath:
1077 changed.add(self.recode(childpath))
1088 changed.add(self.recode(childpath))
1078
1089
1079 # Handle directory copies
1090 # Handle directory copies
1080 if not ent.copyfrom_path or not parents:
1091 if not ent.copyfrom_path or not parents:
1081 continue
1092 continue
1082 # Copy sources not in parent revisions cannot be
1093 # Copy sources not in parent revisions cannot be
1083 # represented, ignore their origin for now
1094 # represented, ignore their origin for now
1084 pmodule, prevnum = revsplit(parents[0])[1:]
1095 pmodule, prevnum = revsplit(parents[0])[1:]
1085 if ent.copyfrom_rev < prevnum:
1096 if ent.copyfrom_rev < prevnum:
1086 continue
1097 continue
1087 copyfrompath = self.getrelpath(ent.copyfrom_path, pmodule)
1098 copyfrompath = self.getrelpath(ent.copyfrom_path, pmodule)
1088 if not copyfrompath:
1099 if not copyfrompath:
1089 continue
1100 continue
1090 self.ui.debug(
1101 self.ui.debug(
1091 b"mark %s came from %s:%d\n"
1102 b"mark %s came from %s:%d\n"
1092 % (path, copyfrompath, ent.copyfrom_rev)
1103 % (path, copyfrompath, ent.copyfrom_rev)
1093 )
1104 )
1094 children = self._iterfiles(ent.copyfrom_path, ent.copyfrom_rev)
1105 children = self._iterfiles(ent.copyfrom_path, ent.copyfrom_rev)
1095 for childpath in children:
1106 for childpath in children:
1096 childpath = self.getrelpath(b"/" + childpath, pmodule)
1107 childpath = self.getrelpath(b"/" + childpath, pmodule)
1097 if not childpath:
1108 if not childpath:
1098 continue
1109 continue
1099 copytopath = path + childpath[len(copyfrompath) :]
1110 copytopath = path + childpath[len(copyfrompath) :]
1100 copytopath = self.getrelpath(copytopath)
1111 copytopath = self.getrelpath(copytopath)
1101 copies[self.recode(copytopath)] = self.recode(childpath)
1112 copies[self.recode(copytopath)] = self.recode(childpath)
1102
1113
1103 progress.complete()
1114 progress.complete()
1104 changed.update(removed)
1115 changed.update(removed)
1105 return (list(changed), removed, copies)
1116 return (list(changed), removed, copies)
1106
1117
1107 def _fetch_revisions(self, from_revnum, to_revnum):
1118 def _fetch_revisions(self, from_revnum, to_revnum):
1108 if from_revnum < to_revnum:
1119 if from_revnum < to_revnum:
1109 from_revnum, to_revnum = to_revnum, from_revnum
1120 from_revnum, to_revnum = to_revnum, from_revnum
1110
1121
1111 self.child_cset = None
1122 self.child_cset = None
1112
1123
1113 def parselogentry(orig_paths, revnum, author, date, message):
1124 def parselogentry(orig_paths, revnum, author, date, message):
1114 """Return the parsed commit object or None, and True if
1125 """Return the parsed commit object or None, and True if
1115 the revision is a branch root.
1126 the revision is a branch root.
1116 """
1127 """
1117 self.ui.debug(
1128 self.ui.debug(
1118 b"parsing revision %d (%d changes)\n"
1129 b"parsing revision %d (%d changes)\n"
1119 % (revnum, len(orig_paths))
1130 % (revnum, len(orig_paths))
1120 )
1131 )
1121
1132
1122 branched = False
1133 branched = False
1123 rev = self.revid(revnum)
1134 rev = self.revid(revnum)
1124 # branch log might return entries for a parent we already have
1135 # branch log might return entries for a parent we already have
1125
1136
1126 if rev in self.commits or revnum < to_revnum:
1137 if rev in self.commits or revnum < to_revnum:
1127 return None, branched
1138 return None, branched
1128
1139
1129 parents = []
1140 parents = []
1130 # check whether this revision is the start of a branch or part
1141 # check whether this revision is the start of a branch or part
1131 # of a branch renaming
1142 # of a branch renaming
1132 orig_paths = sorted(pycompat.iteritems(orig_paths))
1143 orig_paths = sorted(pycompat.iteritems(orig_paths))
1133 root_paths = [
1144 root_paths = [
1134 (p, e) for p, e in orig_paths if self.module.startswith(p)
1145 (p, e) for p, e in orig_paths if self.module.startswith(p)
1135 ]
1146 ]
1136 if root_paths:
1147 if root_paths:
1137 path, ent = root_paths[-1]
1148 path, ent = root_paths[-1]
1138 if ent.copyfrom_path:
1149 if ent.copyfrom_path:
1139 branched = True
1150 branched = True
1140 newpath = ent.copyfrom_path + self.module[len(path) :]
1151 newpath = ent.copyfrom_path + self.module[len(path) :]
1141 # ent.copyfrom_rev may not be the actual last revision
1152 # ent.copyfrom_rev may not be the actual last revision
1142 previd = self.latest(newpath, ent.copyfrom_rev)
1153 previd = self.latest(newpath, ent.copyfrom_rev)
1143 if previd is not None:
1154 if previd is not None:
1144 prevmodule, prevnum = revsplit(previd)[1:]
1155 prevmodule, prevnum = revsplit(previd)[1:]
1145 if prevnum >= self.startrev:
1156 if prevnum >= self.startrev:
1146 parents = [previd]
1157 parents = [previd]
1147 self.ui.note(
1158 self.ui.note(
1148 _(b'found parent of branch %s at %d: %s\n')
1159 _(b'found parent of branch %s at %d: %s\n')
1149 % (self.module, prevnum, prevmodule)
1160 % (self.module, prevnum, prevmodule)
1150 )
1161 )
1151 else:
1162 else:
1152 self.ui.debug(b"no copyfrom path, don't know what to do.\n")
1163 self.ui.debug(b"no copyfrom path, don't know what to do.\n")
1153
1164
1154 paths = []
1165 paths = []
1155 # filter out unrelated paths
1166 # filter out unrelated paths
1156 for path, ent in orig_paths:
1167 for path, ent in orig_paths:
1157 if self.getrelpath(path) is None:
1168 if self.getrelpath(path) is None:
1158 continue
1169 continue
1159 paths.append((path, ent))
1170 paths.append((path, ent))
1160
1171
1161 # Example SVN datetime. Includes microseconds.
1172 date = parsesvndate(date)
1162 # ISO-8601 conformant
1163 # '2007-01-04T17:35:00.902377Z'
1164 date = dateutil.parsedate(
1165 date[:19] + b" UTC", [b"%Y-%m-%dT%H:%M:%S"]
1166 )
1167 if self.ui.configbool(b'convert', b'localtimezone'):
1173 if self.ui.configbool(b'convert', b'localtimezone'):
1168 date = makedatetimestamp(date[0])
1174 date = makedatetimestamp(date[0])
1169
1175
1170 if message:
1176 if message:
1171 log = self.recode(message)
1177 log = self.recode(message)
1172 else:
1178 else:
1173 log = b''
1179 log = b''
1174
1180
1175 if author:
1181 if author:
1176 author = self.recode(author)
1182 author = self.recode(author)
1177 else:
1183 else:
1178 author = b''
1184 author = b''
1179
1185
1180 try:
1186 try:
1181 branch = self.module.split(b"/")[-1]
1187 branch = self.module.split(b"/")[-1]
1182 if branch == self.trunkname:
1188 if branch == self.trunkname:
1183 branch = None
1189 branch = None
1184 except IndexError:
1190 except IndexError:
1185 branch = None
1191 branch = None
1186
1192
1187 cset = commit(
1193 cset = commit(
1188 author=author,
1194 author=author,
1189 date=dateutil.datestr(date, b'%Y-%m-%d %H:%M:%S %1%2'),
1195 date=dateutil.datestr(date, b'%Y-%m-%d %H:%M:%S %1%2'),
1190 desc=log,
1196 desc=log,
1191 parents=parents,
1197 parents=parents,
1192 branch=branch,
1198 branch=branch,
1193 rev=rev,
1199 rev=rev,
1194 )
1200 )
1195
1201
1196 self.commits[rev] = cset
1202 self.commits[rev] = cset
1197 # The parents list is *shared* among self.paths and the
1203 # The parents list is *shared* among self.paths and the
1198 # commit object. Both will be updated below.
1204 # commit object. Both will be updated below.
1199 self.paths[rev] = (paths, cset.parents)
1205 self.paths[rev] = (paths, cset.parents)
1200 if self.child_cset and not self.child_cset.parents:
1206 if self.child_cset and not self.child_cset.parents:
1201 self.child_cset.parents[:] = [rev]
1207 self.child_cset.parents[:] = [rev]
1202 self.child_cset = cset
1208 self.child_cset = cset
1203 return cset, branched
1209 return cset, branched
1204
1210
1205 self.ui.note(
1211 self.ui.note(
1206 _(b'fetching revision log for "%s" from %d to %d\n')
1212 _(b'fetching revision log for "%s" from %d to %d\n')
1207 % (self.module, from_revnum, to_revnum)
1213 % (self.module, from_revnum, to_revnum)
1208 )
1214 )
1209
1215
1210 try:
1216 try:
1211 firstcset = None
1217 firstcset = None
1212 lastonbranch = False
1218 lastonbranch = False
1213 stream = self._getlog([self.module], from_revnum, to_revnum)
1219 stream = self._getlog([self.module], from_revnum, to_revnum)
1214 try:
1220 try:
1215 for entry in stream:
1221 for entry in stream:
1216 paths, revnum, author, date, message = entry
1222 paths, revnum, author, date, message = entry
1217 if revnum < self.startrev:
1223 if revnum < self.startrev:
1218 lastonbranch = True
1224 lastonbranch = True
1219 break
1225 break
1220 if not paths:
1226 if not paths:
1221 self.ui.debug(b'revision %d has no entries\n' % revnum)
1227 self.ui.debug(b'revision %d has no entries\n' % revnum)
1222 # If we ever leave the loop on an empty
1228 # If we ever leave the loop on an empty
1223 # revision, do not try to get a parent branch
1229 # revision, do not try to get a parent branch
1224 lastonbranch = lastonbranch or revnum == 0
1230 lastonbranch = lastonbranch or revnum == 0
1225 continue
1231 continue
1226 cset, lastonbranch = parselogentry(
1232 cset, lastonbranch = parselogentry(
1227 paths, revnum, author, date, message
1233 paths, revnum, author, date, message
1228 )
1234 )
1229 if cset:
1235 if cset:
1230 firstcset = cset
1236 firstcset = cset
1231 if lastonbranch:
1237 if lastonbranch:
1232 break
1238 break
1233 finally:
1239 finally:
1234 stream.close()
1240 stream.close()
1235
1241
1236 if not lastonbranch and firstcset and not firstcset.parents:
1242 if not lastonbranch and firstcset and not firstcset.parents:
1237 # The first revision of the sequence (the last fetched one)
1243 # The first revision of the sequence (the last fetched one)
1238 # has invalid parents if not a branch root. Find the parent
1244 # has invalid parents if not a branch root. Find the parent
1239 # revision now, if any.
1245 # revision now, if any.
1240 try:
1246 try:
1241 firstrevnum = self.revnum(firstcset.rev)
1247 firstrevnum = self.revnum(firstcset.rev)
1242 if firstrevnum > 1:
1248 if firstrevnum > 1:
1243 latest = self.latest(self.module, firstrevnum - 1)
1249 latest = self.latest(self.module, firstrevnum - 1)
1244 if latest:
1250 if latest:
1245 firstcset.parents.append(latest)
1251 firstcset.parents.append(latest)
1246 except SvnPathNotFound:
1252 except SvnPathNotFound:
1247 pass
1253 pass
1248 except svn.core.SubversionException as xxx_todo_changeme:
1254 except svn.core.SubversionException as xxx_todo_changeme:
1249 (inst, num) = xxx_todo_changeme.args
1255 (inst, num) = xxx_todo_changeme.args
1250 if num == svn.core.SVN_ERR_FS_NO_SUCH_REVISION:
1256 if num == svn.core.SVN_ERR_FS_NO_SUCH_REVISION:
1251 raise error.Abort(
1257 raise error.Abort(
1252 _(b'svn: branch has no revision %s') % to_revnum
1258 _(b'svn: branch has no revision %s') % to_revnum
1253 )
1259 )
1254 raise
1260 raise
1255
1261
1256 def getfile(self, file, rev):
1262 def getfile(self, file, rev):
1257 # TODO: ra.get_file transmits the whole file instead of diffs.
1263 # TODO: ra.get_file transmits the whole file instead of diffs.
1258 if file in self.removed:
1264 if file in self.removed:
1259 return None, None
1265 return None, None
1260 try:
1266 try:
1261 new_module, revnum = revsplit(rev)[1:]
1267 new_module, revnum = revsplit(rev)[1:]
1262 if self.module != new_module:
1268 if self.module != new_module:
1263 self.module = new_module
1269 self.module = new_module
1264 self.reparent(self.module)
1270 self.reparent(self.module)
1265 io = stringio()
1271 io = stringio()
1266 info = svn.ra.get_file(self.ra, file, revnum, io)
1272 info = svn.ra.get_file(self.ra, file, revnum, io)
1267 data = io.getvalue()
1273 data = io.getvalue()
1268 # ra.get_file() seems to keep a reference on the input buffer
1274 # ra.get_file() seems to keep a reference on the input buffer
1269 # preventing collection. Release it explicitly.
1275 # preventing collection. Release it explicitly.
1270 io.close()
1276 io.close()
1271 if isinstance(info, list):
1277 if isinstance(info, list):
1272 info = info[-1]
1278 info = info[-1]
1273 mode = (b"svn:executable" in info) and b'x' or b''
1279 mode = (b"svn:executable" in info) and b'x' or b''
1274 mode = (b"svn:special" in info) and b'l' or mode
1280 mode = (b"svn:special" in info) and b'l' or mode
1275 except svn.core.SubversionException as e:
1281 except svn.core.SubversionException as e:
1276 notfound = (
1282 notfound = (
1277 svn.core.SVN_ERR_FS_NOT_FOUND,
1283 svn.core.SVN_ERR_FS_NOT_FOUND,
1278 svn.core.SVN_ERR_RA_DAV_PATH_NOT_FOUND,
1284 svn.core.SVN_ERR_RA_DAV_PATH_NOT_FOUND,
1279 )
1285 )
1280 if e.apr_err in notfound: # File not found
1286 if e.apr_err in notfound: # File not found
1281 return None, None
1287 return None, None
1282 raise
1288 raise
1283 if mode == b'l':
1289 if mode == b'l':
1284 link_prefix = b"link "
1290 link_prefix = b"link "
1285 if data.startswith(link_prefix):
1291 if data.startswith(link_prefix):
1286 data = data[len(link_prefix) :]
1292 data = data[len(link_prefix) :]
1287 return data, mode
1293 return data, mode
1288
1294
1289 def _iterfiles(self, path, revnum):
1295 def _iterfiles(self, path, revnum):
1290 """Enumerate all files in path at revnum, recursively."""
1296 """Enumerate all files in path at revnum, recursively."""
1291 path = path.strip(b'/')
1297 path = path.strip(b'/')
1292 pool = svn.core.Pool()
1298 pool = svn.core.Pool()
1293 rpath = b'/'.join([self.baseurl, quote(path)]).strip(b'/')
1299 rpath = b'/'.join([self.baseurl, quote(path)]).strip(b'/')
1294 entries = svn.client.ls(rpath, optrev(revnum), True, self.ctx, pool)
1300 entries = svn.client.ls(rpath, optrev(revnum), True, self.ctx, pool)
1295 if path:
1301 if path:
1296 path += b'/'
1302 path += b'/'
1297 return (
1303 return (
1298 (path + p)
1304 (path + p)
1299 for p, e in pycompat.iteritems(entries)
1305 for p, e in pycompat.iteritems(entries)
1300 if e.kind == svn.core.svn_node_file
1306 if e.kind == svn.core.svn_node_file
1301 )
1307 )
1302
1308
1303 def getrelpath(self, path, module=None):
1309 def getrelpath(self, path, module=None):
1304 if module is None:
1310 if module is None:
1305 module = self.module
1311 module = self.module
1306 # Given the repository url of this wc, say
1312 # Given the repository url of this wc, say
1307 # "http://server/plone/CMFPlone/branches/Plone-2_0-branch"
1313 # "http://server/plone/CMFPlone/branches/Plone-2_0-branch"
1308 # extract the "entry" portion (a relative path) from what
1314 # extract the "entry" portion (a relative path) from what
1309 # svn log --xml says, i.e.
1315 # svn log --xml says, i.e.
1310 # "/CMFPlone/branches/Plone-2_0-branch/tests/PloneTestCase.py"
1316 # "/CMFPlone/branches/Plone-2_0-branch/tests/PloneTestCase.py"
1311 # that is to say "tests/PloneTestCase.py"
1317 # that is to say "tests/PloneTestCase.py"
1312 if path.startswith(module):
1318 if path.startswith(module):
1313 relative = path.rstrip(b'/')[len(module) :]
1319 relative = path.rstrip(b'/')[len(module) :]
1314 if relative.startswith(b'/'):
1320 if relative.startswith(b'/'):
1315 return relative[1:]
1321 return relative[1:]
1316 elif relative == b'':
1322 elif relative == b'':
1317 return relative
1323 return relative
1318
1324
1319 # The path is outside our tracked tree...
1325 # The path is outside our tracked tree...
1320 self.ui.debug(
1326 self.ui.debug(
1321 b'%r is not under %r, ignoring\n'
1327 b'%r is not under %r, ignoring\n'
1322 % (pycompat.bytestr(path), pycompat.bytestr(module))
1328 % (pycompat.bytestr(path), pycompat.bytestr(module))
1323 )
1329 )
1324 return None
1330 return None
1325
1331
1326 def _checkpath(self, path, revnum, module=None):
1332 def _checkpath(self, path, revnum, module=None):
1327 if module is not None:
1333 if module is not None:
1328 prevmodule = self.reparent(b'')
1334 prevmodule = self.reparent(b'')
1329 path = module + b'/' + path
1335 path = module + b'/' + path
1330 try:
1336 try:
1331 # ra.check_path does not like leading slashes very much, it leads
1337 # ra.check_path does not like leading slashes very much, it leads
1332 # to PROPFIND subversion errors
1338 # to PROPFIND subversion errors
1333 return svn.ra.check_path(self.ra, path.strip(b'/'), revnum)
1339 return svn.ra.check_path(self.ra, path.strip(b'/'), revnum)
1334 finally:
1340 finally:
1335 if module is not None:
1341 if module is not None:
1336 self.reparent(prevmodule)
1342 self.reparent(prevmodule)
1337
1343
1338 def _getlog(
1344 def _getlog(
1339 self,
1345 self,
1340 paths,
1346 paths,
1341 start,
1347 start,
1342 end,
1348 end,
1343 limit=0,
1349 limit=0,
1344 discover_changed_paths=True,
1350 discover_changed_paths=True,
1345 strict_node_history=False,
1351 strict_node_history=False,
1346 ):
1352 ):
1347 # Normalize path names, svn >= 1.5 only wants paths relative to
1353 # Normalize path names, svn >= 1.5 only wants paths relative to
1348 # supplied URL
1354 # supplied URL
1349 relpaths = []
1355 relpaths = []
1350 for p in paths:
1356 for p in paths:
1351 if not p.startswith(b'/'):
1357 if not p.startswith(b'/'):
1352 p = self.module + b'/' + p
1358 p = self.module + b'/' + p
1353 relpaths.append(p.strip(b'/'))
1359 relpaths.append(p.strip(b'/'))
1354 args = [
1360 args = [
1355 self.baseurl,
1361 self.baseurl,
1356 relpaths,
1362 relpaths,
1357 start,
1363 start,
1358 end,
1364 end,
1359 limit,
1365 limit,
1360 discover_changed_paths,
1366 discover_changed_paths,
1361 strict_node_history,
1367 strict_node_history,
1362 ]
1368 ]
1363 # developer config: convert.svn.debugsvnlog
1369 # developer config: convert.svn.debugsvnlog
1364 if not self.ui.configbool(b'convert', b'svn.debugsvnlog'):
1370 if not self.ui.configbool(b'convert', b'svn.debugsvnlog'):
1365 return directlogstream(*args)
1371 return directlogstream(*args)
1366 arg = encodeargs(args)
1372 arg = encodeargs(args)
1367 hgexe = procutil.hgexecutable()
1373 hgexe = procutil.hgexecutable()
1368 cmd = b'%s debugsvnlog' % procutil.shellquote(hgexe)
1374 cmd = b'%s debugsvnlog' % procutil.shellquote(hgexe)
1369 stdin, stdout = procutil.popen2(cmd)
1375 stdin, stdout = procutil.popen2(cmd)
1370 stdin.write(arg)
1376 stdin.write(arg)
1371 try:
1377 try:
1372 stdin.close()
1378 stdin.close()
1373 except IOError:
1379 except IOError:
1374 raise error.Abort(
1380 raise error.Abort(
1375 _(
1381 _(
1376 b'Mercurial failed to run itself, check'
1382 b'Mercurial failed to run itself, check'
1377 b' hg executable is in PATH'
1383 b' hg executable is in PATH'
1378 )
1384 )
1379 )
1385 )
1380 return logstream(stdout)
1386 return logstream(stdout)
1381
1387
1382
1388
1383 pre_revprop_change = b'''#!/bin/sh
1389 pre_revprop_change_template = b'''#!/bin/sh
1384
1390
1385 REPOS="$1"
1391 REPOS="$1"
1386 REV="$2"
1392 REV="$2"
1387 USER="$3"
1393 USER="$3"
1388 PROPNAME="$4"
1394 PROPNAME="$4"
1389 ACTION="$5"
1395 ACTION="$5"
1390
1396
1391 if [ "$ACTION" = "M" -a "$PROPNAME" = "svn:log" ]; then exit 0; fi
1397 %(rules)s
1392 if [ "$ACTION" = "A" -a "$PROPNAME" = "hg:convert-branch" ]; then exit 0; fi
1393 if [ "$ACTION" = "A" -a "$PROPNAME" = "hg:convert-rev" ]; then exit 0; fi
1394
1398
1395 echo "Changing prohibited revision property" >&2
1399 echo "Changing prohibited revision property" >&2
1396 exit 1
1400 exit 1
1397 '''
1401 '''
1398
1402
1399
1403
1404 def gen_pre_revprop_change_hook(prop_actions_allowed):
1405 rules = []
1406 for action, propname in prop_actions_allowed:
1407 rules.append(
1408 (
1409 b'if [ "$ACTION" = "%s" -a "$PROPNAME" = "%s" ]; '
1410 b'then exit 0; fi'
1411 )
1412 % (action, propname)
1413 )
1414 return pre_revprop_change_template % {b'rules': b'\n'.join(rules)}
1415
1416
1400 class svn_sink(converter_sink, commandline):
1417 class svn_sink(converter_sink, commandline):
1401 commit_re = re.compile(br'Committed revision (\d+).', re.M)
1418 commit_re = re.compile(br'Committed revision (\d+).', re.M)
1402 uuid_re = re.compile(br'Repository UUID:\s*(\S+)', re.M)
1419 uuid_re = re.compile(br'Repository UUID:\s*(\S+)', re.M)
1403
1420
1404 def prerun(self):
1421 def prerun(self):
1405 if self.wc:
1422 if self.wc:
1406 os.chdir(self.wc)
1423 os.chdir(self.wc)
1407
1424
1408 def postrun(self):
1425 def postrun(self):
1409 if self.wc:
1426 if self.wc:
1410 os.chdir(self.cwd)
1427 os.chdir(self.cwd)
1411
1428
1412 def join(self, name):
1429 def join(self, name):
1413 return os.path.join(self.wc, b'.svn', name)
1430 return os.path.join(self.wc, b'.svn', name)
1414
1431
1415 def revmapfile(self):
1432 def revmapfile(self):
1416 return self.join(b'hg-shamap')
1433 return self.join(b'hg-shamap')
1417
1434
1418 def authorfile(self):
1435 def authorfile(self):
1419 return self.join(b'hg-authormap')
1436 return self.join(b'hg-authormap')
1420
1437
1421 def __init__(self, ui, repotype, path):
1438 def __init__(self, ui, repotype, path):
1422
1439
1423 converter_sink.__init__(self, ui, repotype, path)
1440 converter_sink.__init__(self, ui, repotype, path)
1424 commandline.__init__(self, ui, b'svn')
1441 commandline.__init__(self, ui, b'svn')
1425 self.delete = []
1442 self.delete = []
1426 self.setexec = []
1443 self.setexec = []
1427 self.delexec = []
1444 self.delexec = []
1428 self.copies = []
1445 self.copies = []
1429 self.wc = None
1446 self.wc = None
1430 self.cwd = encoding.getcwd()
1447 self.cwd = encoding.getcwd()
1431
1448
1432 created = False
1449 created = False
1433 if os.path.isfile(os.path.join(path, b'.svn', b'entries')):
1450 if os.path.isfile(os.path.join(path, b'.svn', b'entries')):
1434 self.wc = os.path.realpath(path)
1451 self.wc = os.path.realpath(path)
1435 self.run0(b'update')
1452 self.run0(b'update')
1436 else:
1453 else:
1437 if not re.search(br'^(file|http|https|svn|svn\+ssh)://', path):
1454 if not re.search(br'^(file|http|https|svn|svn\+ssh)://', path):
1438 path = os.path.realpath(path)
1455 path = os.path.realpath(path)
1439 if os.path.isdir(os.path.dirname(path)):
1456 if os.path.isdir(os.path.dirname(path)):
1440 if not os.path.exists(
1457 if not os.path.exists(
1441 os.path.join(path, b'db', b'fs-type')
1458 os.path.join(path, b'db', b'fs-type')
1442 ):
1459 ):
1443 ui.status(
1460 ui.status(
1444 _(b"initializing svn repository '%s'\n")
1461 _(b"initializing svn repository '%s'\n")
1445 % os.path.basename(path)
1462 % os.path.basename(path)
1446 )
1463 )
1447 commandline(ui, b'svnadmin').run0(b'create', path)
1464 commandline(ui, b'svnadmin').run0(b'create', path)
1448 created = path
1465 created = path
1449 path = util.normpath(path)
1466 path = util.normpath(path)
1450 if not path.startswith(b'/'):
1467 if not path.startswith(b'/'):
1451 path = b'/' + path
1468 path = b'/' + path
1452 path = b'file://' + path
1469 path = b'file://' + path
1453
1470
1454 wcpath = os.path.join(
1471 wcpath = os.path.join(
1455 encoding.getcwd(), os.path.basename(path) + b'-wc'
1472 encoding.getcwd(), os.path.basename(path) + b'-wc'
1456 )
1473 )
1457 ui.status(
1474 ui.status(
1458 _(b"initializing svn working copy '%s'\n")
1475 _(b"initializing svn working copy '%s'\n")
1459 % os.path.basename(wcpath)
1476 % os.path.basename(wcpath)
1460 )
1477 )
1461 self.run0(b'checkout', path, wcpath)
1478 self.run0(b'checkout', path, wcpath)
1462
1479
1463 self.wc = wcpath
1480 self.wc = wcpath
1464 self.opener = vfsmod.vfs(self.wc)
1481 self.opener = vfsmod.vfs(self.wc)
1465 self.wopener = vfsmod.vfs(self.wc)
1482 self.wopener = vfsmod.vfs(self.wc)
1466 self.childmap = mapfile(ui, self.join(b'hg-childmap'))
1483 self.childmap = mapfile(ui, self.join(b'hg-childmap'))
1467 if util.checkexec(self.wc):
1484 if util.checkexec(self.wc):
1468 self.is_exec = util.isexec
1485 self.is_exec = util.isexec
1469 else:
1486 else:
1470 self.is_exec = None
1487 self.is_exec = None
1471
1488
1472 if created:
1489 if created:
1490 prop_actions_allowed = [
1491 (b'M', b'svn:log'),
1492 (b'A', b'hg:convert-branch'),
1493 (b'A', b'hg:convert-rev'),
1494 ]
1495
1496 if self.ui.configbool(
1497 b'convert', b'svn.dangerous-set-commit-dates'
1498 ):
1499 prop_actions_allowed.append((b'M', b'svn:date'))
1500
1473 hook = os.path.join(created, b'hooks', b'pre-revprop-change')
1501 hook = os.path.join(created, b'hooks', b'pre-revprop-change')
1474 fp = open(hook, b'wb')
1502 fp = open(hook, b'wb')
1475 fp.write(pre_revprop_change)
1503 fp.write(gen_pre_revprop_change_hook(prop_actions_allowed))
1476 fp.close()
1504 fp.close()
1477 util.setflags(hook, False, True)
1505 util.setflags(hook, False, True)
1478
1506
1479 output = self.run0(b'info')
1507 output = self.run0(b'info')
1480 self.uuid = self.uuid_re.search(output).group(1).strip()
1508 self.uuid = self.uuid_re.search(output).group(1).strip()
1481
1509
1482 def wjoin(self, *names):
1510 def wjoin(self, *names):
1483 return os.path.join(self.wc, *names)
1511 return os.path.join(self.wc, *names)
1484
1512
1485 @propertycache
1513 @propertycache
1486 def manifest(self):
1514 def manifest(self):
1487 # As of svn 1.7, the "add" command fails when receiving
1515 # As of svn 1.7, the "add" command fails when receiving
1488 # already tracked entries, so we have to track and filter them
1516 # already tracked entries, so we have to track and filter them
1489 # ourselves.
1517 # ourselves.
1490 m = set()
1518 m = set()
1491 output = self.run0(b'ls', recursive=True, xml=True)
1519 output = self.run0(b'ls', recursive=True, xml=True)
1492 doc = xml.dom.minidom.parseString(output)
1520 doc = xml.dom.minidom.parseString(output)
1493 for e in doc.getElementsByTagName('entry'):
1521 for e in doc.getElementsByTagName('entry'):
1494 for n in e.childNodes:
1522 for n in e.childNodes:
1495 if n.nodeType != n.ELEMENT_NODE or n.tagName != 'name':
1523 if n.nodeType != n.ELEMENT_NODE or n.tagName != 'name':
1496 continue
1524 continue
1497 name = ''.join(
1525 name = ''.join(
1498 c.data for c in n.childNodes if c.nodeType == c.TEXT_NODE
1526 c.data for c in n.childNodes if c.nodeType == c.TEXT_NODE
1499 )
1527 )
1500 # Entries are compared with names coming from
1528 # Entries are compared with names coming from
1501 # mercurial, so bytes with undefined encoding. Our
1529 # mercurial, so bytes with undefined encoding. Our
1502 # best bet is to assume they are in local
1530 # best bet is to assume they are in local
1503 # encoding. They will be passed to command line calls
1531 # encoding. They will be passed to command line calls
1504 # later anyway, so they better be.
1532 # later anyway, so they better be.
1505 m.add(encoding.unitolocal(name))
1533 m.add(encoding.unitolocal(name))
1506 break
1534 break
1507 return m
1535 return m
1508
1536
1509 def putfile(self, filename, flags, data):
1537 def putfile(self, filename, flags, data):
1510 if b'l' in flags:
1538 if b'l' in flags:
1511 self.wopener.symlink(data, filename)
1539 self.wopener.symlink(data, filename)
1512 else:
1540 else:
1513 try:
1541 try:
1514 if os.path.islink(self.wjoin(filename)):
1542 if os.path.islink(self.wjoin(filename)):
1515 os.unlink(filename)
1543 os.unlink(filename)
1516 except OSError:
1544 except OSError:
1517 pass
1545 pass
1518
1546
1519 if self.is_exec:
1547 if self.is_exec:
1520 # We need to check executability of the file before the change,
1548 # We need to check executability of the file before the change,
1521 # because `vfs.write` is able to reset exec bit.
1549 # because `vfs.write` is able to reset exec bit.
1522 wasexec = False
1550 wasexec = False
1523 if os.path.exists(self.wjoin(filename)):
1551 if os.path.exists(self.wjoin(filename)):
1524 wasexec = self.is_exec(self.wjoin(filename))
1552 wasexec = self.is_exec(self.wjoin(filename))
1525
1553
1526 self.wopener.write(filename, data)
1554 self.wopener.write(filename, data)
1527
1555
1528 if self.is_exec:
1556 if self.is_exec:
1529 if wasexec:
1557 if wasexec:
1530 if b'x' not in flags:
1558 if b'x' not in flags:
1531 self.delexec.append(filename)
1559 self.delexec.append(filename)
1532 else:
1560 else:
1533 if b'x' in flags:
1561 if b'x' in flags:
1534 self.setexec.append(filename)
1562 self.setexec.append(filename)
1535 util.setflags(self.wjoin(filename), False, b'x' in flags)
1563 util.setflags(self.wjoin(filename), False, b'x' in flags)
1536
1564
1537 def _copyfile(self, source, dest):
1565 def _copyfile(self, source, dest):
1538 # SVN's copy command pukes if the destination file exists, but
1566 # SVN's copy command pukes if the destination file exists, but
1539 # our copyfile method expects to record a copy that has
1567 # our copyfile method expects to record a copy that has
1540 # already occurred. Cross the semantic gap.
1568 # already occurred. Cross the semantic gap.
1541 wdest = self.wjoin(dest)
1569 wdest = self.wjoin(dest)
1542 exists = os.path.lexists(wdest)
1570 exists = os.path.lexists(wdest)
1543 if exists:
1571 if exists:
1544 fd, tempname = pycompat.mkstemp(
1572 fd, tempname = pycompat.mkstemp(
1545 prefix=b'hg-copy-', dir=os.path.dirname(wdest)
1573 prefix=b'hg-copy-', dir=os.path.dirname(wdest)
1546 )
1574 )
1547 os.close(fd)
1575 os.close(fd)
1548 os.unlink(tempname)
1576 os.unlink(tempname)
1549 os.rename(wdest, tempname)
1577 os.rename(wdest, tempname)
1550 try:
1578 try:
1551 self.run0(b'copy', source, dest)
1579 self.run0(b'copy', source, dest)
1552 finally:
1580 finally:
1553 self.manifest.add(dest)
1581 self.manifest.add(dest)
1554 if exists:
1582 if exists:
1555 try:
1583 try:
1556 os.unlink(wdest)
1584 os.unlink(wdest)
1557 except OSError:
1585 except OSError:
1558 pass
1586 pass
1559 os.rename(tempname, wdest)
1587 os.rename(tempname, wdest)
1560
1588
1561 def dirs_of(self, files):
1589 def dirs_of(self, files):
1562 dirs = set()
1590 dirs = set()
1563 for f in files:
1591 for f in files:
1564 if os.path.isdir(self.wjoin(f)):
1592 if os.path.isdir(self.wjoin(f)):
1565 dirs.add(f)
1593 dirs.add(f)
1566 i = len(f)
1594 i = len(f)
1567 for i in iter(lambda: f.rfind(b'/', 0, i), -1):
1595 for i in iter(lambda: f.rfind(b'/', 0, i), -1):
1568 dirs.add(f[:i])
1596 dirs.add(f[:i])
1569 return dirs
1597 return dirs
1570
1598
1571 def add_dirs(self, files):
1599 def add_dirs(self, files):
1572 add_dirs = [
1600 add_dirs = [
1573 d for d in sorted(self.dirs_of(files)) if d not in self.manifest
1601 d for d in sorted(self.dirs_of(files)) if d not in self.manifest
1574 ]
1602 ]
1575 if add_dirs:
1603 if add_dirs:
1576 self.manifest.update(add_dirs)
1604 self.manifest.update(add_dirs)
1577 self.xargs(add_dirs, b'add', non_recursive=True, quiet=True)
1605 self.xargs(add_dirs, b'add', non_recursive=True, quiet=True)
1578 return add_dirs
1606 return add_dirs
1579
1607
1580 def add_files(self, files):
1608 def add_files(self, files):
1581 files = [f for f in files if f not in self.manifest]
1609 files = [f for f in files if f not in self.manifest]
1582 if files:
1610 if files:
1583 self.manifest.update(files)
1611 self.manifest.update(files)
1584 self.xargs(files, b'add', quiet=True)
1612 self.xargs(files, b'add', quiet=True)
1585 return files
1613 return files
1586
1614
1587 def addchild(self, parent, child):
1615 def addchild(self, parent, child):
1588 self.childmap[parent] = child
1616 self.childmap[parent] = child
1589
1617
1590 def revid(self, rev):
1618 def revid(self, rev):
1591 return b"svn:%s@%s" % (self.uuid, rev)
1619 return b"svn:%s@%s" % (self.uuid, rev)
1592
1620
1593 def putcommit(
1621 def putcommit(
1594 self, files, copies, parents, commit, source, revmap, full, cleanp2
1622 self, files, copies, parents, commit, source, revmap, full, cleanp2
1595 ):
1623 ):
1596 for parent in parents:
1624 for parent in parents:
1597 try:
1625 try:
1598 return self.revid(self.childmap[parent])
1626 return self.revid(self.childmap[parent])
1599 except KeyError:
1627 except KeyError:
1600 pass
1628 pass
1601
1629
1602 # Apply changes to working copy
1630 # Apply changes to working copy
1603 for f, v in files:
1631 for f, v in files:
1604 data, mode = source.getfile(f, v)
1632 data, mode = source.getfile(f, v)
1605 if data is None:
1633 if data is None:
1606 self.delete.append(f)
1634 self.delete.append(f)
1607 else:
1635 else:
1608 self.putfile(f, mode, data)
1636 self.putfile(f, mode, data)
1609 if f in copies:
1637 if f in copies:
1610 self.copies.append([copies[f], f])
1638 self.copies.append([copies[f], f])
1611 if full:
1639 if full:
1612 self.delete.extend(sorted(self.manifest.difference(files)))
1640 self.delete.extend(sorted(self.manifest.difference(files)))
1613 files = [f[0] for f in files]
1641 files = [f[0] for f in files]
1614
1642
1615 entries = set(self.delete)
1643 entries = set(self.delete)
1616 files = frozenset(files)
1644 files = frozenset(files)
1617 entries.update(self.add_dirs(files.difference(entries)))
1645 entries.update(self.add_dirs(files.difference(entries)))
1618 if self.copies:
1646 if self.copies:
1619 for s, d in self.copies:
1647 for s, d in self.copies:
1620 self._copyfile(s, d)
1648 self._copyfile(s, d)
1621 self.copies = []
1649 self.copies = []
1622 if self.delete:
1650 if self.delete:
1623 self.xargs(self.delete, b'delete')
1651 self.xargs(self.delete, b'delete')
1624 for f in self.delete:
1652 for f in self.delete:
1625 self.manifest.remove(f)
1653 self.manifest.remove(f)
1626 self.delete = []
1654 self.delete = []
1627 entries.update(self.add_files(files.difference(entries)))
1655 entries.update(self.add_files(files.difference(entries)))
1628 if self.delexec:
1656 if self.delexec:
1629 self.xargs(self.delexec, b'propdel', b'svn:executable')
1657 self.xargs(self.delexec, b'propdel', b'svn:executable')
1630 self.delexec = []
1658 self.delexec = []
1631 if self.setexec:
1659 if self.setexec:
1632 self.xargs(self.setexec, b'propset', b'svn:executable', b'*')
1660 self.xargs(self.setexec, b'propset', b'svn:executable', b'*')
1633 self.setexec = []
1661 self.setexec = []
1634
1662
1635 fd, messagefile = pycompat.mkstemp(prefix=b'hg-convert-')
1663 fd, messagefile = pycompat.mkstemp(prefix=b'hg-convert-')
1636 fp = os.fdopen(fd, 'wb')
1664 fp = os.fdopen(fd, 'wb')
1637 fp.write(util.tonativeeol(commit.desc))
1665 fp.write(util.tonativeeol(commit.desc))
1638 fp.close()
1666 fp.close()
1639 try:
1667 try:
1640 output = self.run0(
1668 output = self.run0(
1641 b'commit',
1669 b'commit',
1642 username=stringutil.shortuser(commit.author),
1670 username=stringutil.shortuser(commit.author),
1643 file=messagefile,
1671 file=messagefile,
1644 encoding=b'utf-8',
1672 encoding=b'utf-8',
1645 )
1673 )
1646 try:
1674 try:
1647 rev = self.commit_re.search(output).group(1)
1675 rev = self.commit_re.search(output).group(1)
1648 except AttributeError:
1676 except AttributeError:
1649 if not files:
1677 if not files:
1650 return parents[0] if parents else b'None'
1678 return parents[0] if parents else b'None'
1651 self.ui.warn(_(b'unexpected svn output:\n'))
1679 self.ui.warn(_(b'unexpected svn output:\n'))
1652 self.ui.warn(output)
1680 self.ui.warn(output)
1653 raise error.Abort(_(b'unable to cope with svn output'))
1681 raise error.Abort(_(b'unable to cope with svn output'))
1654 if commit.rev:
1682 if commit.rev:
1655 self.run(
1683 self.run(
1656 b'propset',
1684 b'propset',
1657 b'hg:convert-rev',
1685 b'hg:convert-rev',
1658 commit.rev,
1686 commit.rev,
1659 revprop=True,
1687 revprop=True,
1660 revision=rev,
1688 revision=rev,
1661 )
1689 )
1662 if commit.branch and commit.branch != b'default':
1690 if commit.branch and commit.branch != b'default':
1663 self.run(
1691 self.run(
1664 b'propset',
1692 b'propset',
1665 b'hg:convert-branch',
1693 b'hg:convert-branch',
1666 commit.branch,
1694 commit.branch,
1667 revprop=True,
1695 revprop=True,
1668 revision=rev,
1696 revision=rev,
1669 )
1697 )
1698
1699 if self.ui.configbool(
1700 b'convert', b'svn.dangerous-set-commit-dates'
1701 ):
1702 # Subverson always uses UTC to represent date and time
1703 date = dateutil.parsedate(commit.date)
1704 date = (date[0], 0)
1705
1706 # The only way to set date and time for svn commit is to use propset after commit is done
1707 self.run(
1708 b'propset',
1709 b'svn:date',
1710 formatsvndate(date),
1711 revprop=True,
1712 revision=rev,
1713 )
1714
1670 for parent in parents:
1715 for parent in parents:
1671 self.addchild(parent, rev)
1716 self.addchild(parent, rev)
1672 return self.revid(rev)
1717 return self.revid(rev)
1673 finally:
1718 finally:
1674 os.unlink(messagefile)
1719 os.unlink(messagefile)
1675
1720
1676 def puttags(self, tags):
1721 def puttags(self, tags):
1677 self.ui.warn(_(b'writing Subversion tags is not yet implemented\n'))
1722 self.ui.warn(_(b'writing Subversion tags is not yet implemented\n'))
1678 return None, None
1723 return None, None
1679
1724
1680 def hascommitfrommap(self, rev):
1725 def hascommitfrommap(self, rev):
1681 # We trust that revisions referenced in a map still is present
1726 # We trust that revisions referenced in a map still is present
1682 # TODO: implement something better if necessary and feasible
1727 # TODO: implement something better if necessary and feasible
1683 return True
1728 return True
1684
1729
1685 def hascommitforsplicemap(self, rev):
1730 def hascommitforsplicemap(self, rev):
1686 # This is not correct as one can convert to an existing subversion
1731 # This is not correct as one can convert to an existing subversion
1687 # repository and childmap would not list all revisions. Too bad.
1732 # repository and childmap would not list all revisions. Too bad.
1688 if rev in self.childmap:
1733 if rev in self.childmap:
1689 return True
1734 return True
1690 raise error.Abort(
1735 raise error.Abort(
1691 _(
1736 _(
1692 b'splice map revision %s not found in subversion '
1737 b'splice map revision %s not found in subversion '
1693 b'child map (revision lookups are not implemented)'
1738 b'child map (revision lookups are not implemented)'
1694 )
1739 )
1695 % rev
1740 % rev
1696 )
1741 )
@@ -1,2594 +1,2599 b''
1 # configitems.py - centralized declaration of configuration option
1 # configitems.py - centralized declaration of configuration option
2 #
2 #
3 # Copyright 2017 Pierre-Yves David <pierre-yves.david@octobus.net>
3 # Copyright 2017 Pierre-Yves David <pierre-yves.david@octobus.net>
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 __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import functools
10 import functools
11 import re
11 import re
12
12
13 from . import (
13 from . import (
14 encoding,
14 encoding,
15 error,
15 error,
16 )
16 )
17
17
18
18
19 def loadconfigtable(ui, extname, configtable):
19 def loadconfigtable(ui, extname, configtable):
20 """update config item known to the ui with the extension ones"""
20 """update config item known to the ui with the extension ones"""
21 for section, items in sorted(configtable.items()):
21 for section, items in sorted(configtable.items()):
22 knownitems = ui._knownconfig.setdefault(section, itemregister())
22 knownitems = ui._knownconfig.setdefault(section, itemregister())
23 knownkeys = set(knownitems)
23 knownkeys = set(knownitems)
24 newkeys = set(items)
24 newkeys = set(items)
25 for key in sorted(knownkeys & newkeys):
25 for key in sorted(knownkeys & newkeys):
26 msg = b"extension '%s' overwrite config item '%s.%s'"
26 msg = b"extension '%s' overwrite config item '%s.%s'"
27 msg %= (extname, section, key)
27 msg %= (extname, section, key)
28 ui.develwarn(msg, config=b'warn-config')
28 ui.develwarn(msg, config=b'warn-config')
29
29
30 knownitems.update(items)
30 knownitems.update(items)
31
31
32
32
33 class configitem(object):
33 class configitem(object):
34 """represent a known config item
34 """represent a known config item
35
35
36 :section: the official config section where to find this item,
36 :section: the official config section where to find this item,
37 :name: the official name within the section,
37 :name: the official name within the section,
38 :default: default value for this item,
38 :default: default value for this item,
39 :alias: optional list of tuples as alternatives,
39 :alias: optional list of tuples as alternatives,
40 :generic: this is a generic definition, match name using regular expression.
40 :generic: this is a generic definition, match name using regular expression.
41 """
41 """
42
42
43 def __init__(
43 def __init__(
44 self,
44 self,
45 section,
45 section,
46 name,
46 name,
47 default=None,
47 default=None,
48 alias=(),
48 alias=(),
49 generic=False,
49 generic=False,
50 priority=0,
50 priority=0,
51 experimental=False,
51 experimental=False,
52 ):
52 ):
53 self.section = section
53 self.section = section
54 self.name = name
54 self.name = name
55 self.default = default
55 self.default = default
56 self.alias = list(alias)
56 self.alias = list(alias)
57 self.generic = generic
57 self.generic = generic
58 self.priority = priority
58 self.priority = priority
59 self.experimental = experimental
59 self.experimental = experimental
60 self._re = None
60 self._re = None
61 if generic:
61 if generic:
62 self._re = re.compile(self.name)
62 self._re = re.compile(self.name)
63
63
64
64
65 class itemregister(dict):
65 class itemregister(dict):
66 """A specialized dictionary that can handle wild-card selection"""
66 """A specialized dictionary that can handle wild-card selection"""
67
67
68 def __init__(self):
68 def __init__(self):
69 super(itemregister, self).__init__()
69 super(itemregister, self).__init__()
70 self._generics = set()
70 self._generics = set()
71
71
72 def update(self, other):
72 def update(self, other):
73 super(itemregister, self).update(other)
73 super(itemregister, self).update(other)
74 self._generics.update(other._generics)
74 self._generics.update(other._generics)
75
75
76 def __setitem__(self, key, item):
76 def __setitem__(self, key, item):
77 super(itemregister, self).__setitem__(key, item)
77 super(itemregister, self).__setitem__(key, item)
78 if item.generic:
78 if item.generic:
79 self._generics.add(item)
79 self._generics.add(item)
80
80
81 def get(self, key):
81 def get(self, key):
82 baseitem = super(itemregister, self).get(key)
82 baseitem = super(itemregister, self).get(key)
83 if baseitem is not None and not baseitem.generic:
83 if baseitem is not None and not baseitem.generic:
84 return baseitem
84 return baseitem
85
85
86 # search for a matching generic item
86 # search for a matching generic item
87 generics = sorted(self._generics, key=(lambda x: (x.priority, x.name)))
87 generics = sorted(self._generics, key=(lambda x: (x.priority, x.name)))
88 for item in generics:
88 for item in generics:
89 # we use 'match' instead of 'search' to make the matching simpler
89 # we use 'match' instead of 'search' to make the matching simpler
90 # for people unfamiliar with regular expression. Having the match
90 # for people unfamiliar with regular expression. Having the match
91 # rooted to the start of the string will produce less surprising
91 # rooted to the start of the string will produce less surprising
92 # result for user writing simple regex for sub-attribute.
92 # result for user writing simple regex for sub-attribute.
93 #
93 #
94 # For example using "color\..*" match produces an unsurprising
94 # For example using "color\..*" match produces an unsurprising
95 # result, while using search could suddenly match apparently
95 # result, while using search could suddenly match apparently
96 # unrelated configuration that happens to contains "color."
96 # unrelated configuration that happens to contains "color."
97 # anywhere. This is a tradeoff where we favor requiring ".*" on
97 # anywhere. This is a tradeoff where we favor requiring ".*" on
98 # some match to avoid the need to prefix most pattern with "^".
98 # some match to avoid the need to prefix most pattern with "^".
99 # The "^" seems more error prone.
99 # The "^" seems more error prone.
100 if item._re.match(key):
100 if item._re.match(key):
101 return item
101 return item
102
102
103 return None
103 return None
104
104
105
105
106 coreitems = {}
106 coreitems = {}
107
107
108
108
109 def _register(configtable, *args, **kwargs):
109 def _register(configtable, *args, **kwargs):
110 item = configitem(*args, **kwargs)
110 item = configitem(*args, **kwargs)
111 section = configtable.setdefault(item.section, itemregister())
111 section = configtable.setdefault(item.section, itemregister())
112 if item.name in section:
112 if item.name in section:
113 msg = b"duplicated config item registration for '%s.%s'"
113 msg = b"duplicated config item registration for '%s.%s'"
114 raise error.ProgrammingError(msg % (item.section, item.name))
114 raise error.ProgrammingError(msg % (item.section, item.name))
115 section[item.name] = item
115 section[item.name] = item
116
116
117
117
118 # special value for case where the default is derived from other values
118 # special value for case where the default is derived from other values
119 dynamicdefault = object()
119 dynamicdefault = object()
120
120
121 # Registering actual config items
121 # Registering actual config items
122
122
123
123
124 def getitemregister(configtable):
124 def getitemregister(configtable):
125 f = functools.partial(_register, configtable)
125 f = functools.partial(_register, configtable)
126 # export pseudo enum as configitem.*
126 # export pseudo enum as configitem.*
127 f.dynamicdefault = dynamicdefault
127 f.dynamicdefault = dynamicdefault
128 return f
128 return f
129
129
130
130
131 coreconfigitem = getitemregister(coreitems)
131 coreconfigitem = getitemregister(coreitems)
132
132
133
133
134 def _registerdiffopts(section, configprefix=b''):
134 def _registerdiffopts(section, configprefix=b''):
135 coreconfigitem(
135 coreconfigitem(
136 section,
136 section,
137 configprefix + b'nodates',
137 configprefix + b'nodates',
138 default=False,
138 default=False,
139 )
139 )
140 coreconfigitem(
140 coreconfigitem(
141 section,
141 section,
142 configprefix + b'showfunc',
142 configprefix + b'showfunc',
143 default=False,
143 default=False,
144 )
144 )
145 coreconfigitem(
145 coreconfigitem(
146 section,
146 section,
147 configprefix + b'unified',
147 configprefix + b'unified',
148 default=None,
148 default=None,
149 )
149 )
150 coreconfigitem(
150 coreconfigitem(
151 section,
151 section,
152 configprefix + b'git',
152 configprefix + b'git',
153 default=False,
153 default=False,
154 )
154 )
155 coreconfigitem(
155 coreconfigitem(
156 section,
156 section,
157 configprefix + b'ignorews',
157 configprefix + b'ignorews',
158 default=False,
158 default=False,
159 )
159 )
160 coreconfigitem(
160 coreconfigitem(
161 section,
161 section,
162 configprefix + b'ignorewsamount',
162 configprefix + b'ignorewsamount',
163 default=False,
163 default=False,
164 )
164 )
165 coreconfigitem(
165 coreconfigitem(
166 section,
166 section,
167 configprefix + b'ignoreblanklines',
167 configprefix + b'ignoreblanklines',
168 default=False,
168 default=False,
169 )
169 )
170 coreconfigitem(
170 coreconfigitem(
171 section,
171 section,
172 configprefix + b'ignorewseol',
172 configprefix + b'ignorewseol',
173 default=False,
173 default=False,
174 )
174 )
175 coreconfigitem(
175 coreconfigitem(
176 section,
176 section,
177 configprefix + b'nobinary',
177 configprefix + b'nobinary',
178 default=False,
178 default=False,
179 )
179 )
180 coreconfigitem(
180 coreconfigitem(
181 section,
181 section,
182 configprefix + b'noprefix',
182 configprefix + b'noprefix',
183 default=False,
183 default=False,
184 )
184 )
185 coreconfigitem(
185 coreconfigitem(
186 section,
186 section,
187 configprefix + b'word-diff',
187 configprefix + b'word-diff',
188 default=False,
188 default=False,
189 )
189 )
190
190
191
191
192 coreconfigitem(
192 coreconfigitem(
193 b'alias',
193 b'alias',
194 b'.*',
194 b'.*',
195 default=dynamicdefault,
195 default=dynamicdefault,
196 generic=True,
196 generic=True,
197 )
197 )
198 coreconfigitem(
198 coreconfigitem(
199 b'auth',
199 b'auth',
200 b'cookiefile',
200 b'cookiefile',
201 default=None,
201 default=None,
202 )
202 )
203 _registerdiffopts(section=b'annotate')
203 _registerdiffopts(section=b'annotate')
204 # bookmarks.pushing: internal hack for discovery
204 # bookmarks.pushing: internal hack for discovery
205 coreconfigitem(
205 coreconfigitem(
206 b'bookmarks',
206 b'bookmarks',
207 b'pushing',
207 b'pushing',
208 default=list,
208 default=list,
209 )
209 )
210 # bundle.mainreporoot: internal hack for bundlerepo
210 # bundle.mainreporoot: internal hack for bundlerepo
211 coreconfigitem(
211 coreconfigitem(
212 b'bundle',
212 b'bundle',
213 b'mainreporoot',
213 b'mainreporoot',
214 default=b'',
214 default=b'',
215 )
215 )
216 coreconfigitem(
216 coreconfigitem(
217 b'censor',
217 b'censor',
218 b'policy',
218 b'policy',
219 default=b'abort',
219 default=b'abort',
220 experimental=True,
220 experimental=True,
221 )
221 )
222 coreconfigitem(
222 coreconfigitem(
223 b'chgserver',
223 b'chgserver',
224 b'idletimeout',
224 b'idletimeout',
225 default=3600,
225 default=3600,
226 )
226 )
227 coreconfigitem(
227 coreconfigitem(
228 b'chgserver',
228 b'chgserver',
229 b'skiphash',
229 b'skiphash',
230 default=False,
230 default=False,
231 )
231 )
232 coreconfigitem(
232 coreconfigitem(
233 b'cmdserver',
233 b'cmdserver',
234 b'log',
234 b'log',
235 default=None,
235 default=None,
236 )
236 )
237 coreconfigitem(
237 coreconfigitem(
238 b'cmdserver',
238 b'cmdserver',
239 b'max-log-files',
239 b'max-log-files',
240 default=7,
240 default=7,
241 )
241 )
242 coreconfigitem(
242 coreconfigitem(
243 b'cmdserver',
243 b'cmdserver',
244 b'max-log-size',
244 b'max-log-size',
245 default=b'1 MB',
245 default=b'1 MB',
246 )
246 )
247 coreconfigitem(
247 coreconfigitem(
248 b'cmdserver',
248 b'cmdserver',
249 b'max-repo-cache',
249 b'max-repo-cache',
250 default=0,
250 default=0,
251 experimental=True,
251 experimental=True,
252 )
252 )
253 coreconfigitem(
253 coreconfigitem(
254 b'cmdserver',
254 b'cmdserver',
255 b'message-encodings',
255 b'message-encodings',
256 default=list,
256 default=list,
257 )
257 )
258 coreconfigitem(
258 coreconfigitem(
259 b'cmdserver',
259 b'cmdserver',
260 b'track-log',
260 b'track-log',
261 default=lambda: [b'chgserver', b'cmdserver', b'repocache'],
261 default=lambda: [b'chgserver', b'cmdserver', b'repocache'],
262 )
262 )
263 coreconfigitem(
263 coreconfigitem(
264 b'cmdserver',
264 b'cmdserver',
265 b'shutdown-on-interrupt',
265 b'shutdown-on-interrupt',
266 default=True,
266 default=True,
267 )
267 )
268 coreconfigitem(
268 coreconfigitem(
269 b'color',
269 b'color',
270 b'.*',
270 b'.*',
271 default=None,
271 default=None,
272 generic=True,
272 generic=True,
273 )
273 )
274 coreconfigitem(
274 coreconfigitem(
275 b'color',
275 b'color',
276 b'mode',
276 b'mode',
277 default=b'auto',
277 default=b'auto',
278 )
278 )
279 coreconfigitem(
279 coreconfigitem(
280 b'color',
280 b'color',
281 b'pagermode',
281 b'pagermode',
282 default=dynamicdefault,
282 default=dynamicdefault,
283 )
283 )
284 coreconfigitem(
284 coreconfigitem(
285 b'command-templates',
285 b'command-templates',
286 b'graphnode',
286 b'graphnode',
287 default=None,
287 default=None,
288 alias=[(b'ui', b'graphnodetemplate')],
288 alias=[(b'ui', b'graphnodetemplate')],
289 )
289 )
290 coreconfigitem(
290 coreconfigitem(
291 b'command-templates',
291 b'command-templates',
292 b'log',
292 b'log',
293 default=None,
293 default=None,
294 alias=[(b'ui', b'logtemplate')],
294 alias=[(b'ui', b'logtemplate')],
295 )
295 )
296 coreconfigitem(
296 coreconfigitem(
297 b'command-templates',
297 b'command-templates',
298 b'mergemarker',
298 b'mergemarker',
299 default=(
299 default=(
300 b'{node|short} '
300 b'{node|short} '
301 b'{ifeq(tags, "tip", "", '
301 b'{ifeq(tags, "tip", "", '
302 b'ifeq(tags, "", "", "{tags} "))}'
302 b'ifeq(tags, "", "", "{tags} "))}'
303 b'{if(bookmarks, "{bookmarks} ")}'
303 b'{if(bookmarks, "{bookmarks} ")}'
304 b'{ifeq(branch, "default", "", "{branch} ")}'
304 b'{ifeq(branch, "default", "", "{branch} ")}'
305 b'- {author|user}: {desc|firstline}'
305 b'- {author|user}: {desc|firstline}'
306 ),
306 ),
307 alias=[(b'ui', b'mergemarkertemplate')],
307 alias=[(b'ui', b'mergemarkertemplate')],
308 )
308 )
309 coreconfigitem(
309 coreconfigitem(
310 b'command-templates',
310 b'command-templates',
311 b'pre-merge-tool-output',
311 b'pre-merge-tool-output',
312 default=None,
312 default=None,
313 alias=[(b'ui', b'pre-merge-tool-output-template')],
313 alias=[(b'ui', b'pre-merge-tool-output-template')],
314 )
314 )
315 coreconfigitem(
315 coreconfigitem(
316 b'command-templates',
316 b'command-templates',
317 b'oneline-summary',
317 b'oneline-summary',
318 default=None,
318 default=None,
319 )
319 )
320 coreconfigitem(
320 coreconfigitem(
321 b'command-templates',
321 b'command-templates',
322 b'oneline-summary.*',
322 b'oneline-summary.*',
323 default=dynamicdefault,
323 default=dynamicdefault,
324 generic=True,
324 generic=True,
325 )
325 )
326 _registerdiffopts(section=b'commands', configprefix=b'commit.interactive.')
326 _registerdiffopts(section=b'commands', configprefix=b'commit.interactive.')
327 coreconfigitem(
327 coreconfigitem(
328 b'commands',
328 b'commands',
329 b'commit.post-status',
329 b'commit.post-status',
330 default=False,
330 default=False,
331 )
331 )
332 coreconfigitem(
332 coreconfigitem(
333 b'commands',
333 b'commands',
334 b'grep.all-files',
334 b'grep.all-files',
335 default=False,
335 default=False,
336 experimental=True,
336 experimental=True,
337 )
337 )
338 coreconfigitem(
338 coreconfigitem(
339 b'commands',
339 b'commands',
340 b'merge.require-rev',
340 b'merge.require-rev',
341 default=False,
341 default=False,
342 )
342 )
343 coreconfigitem(
343 coreconfigitem(
344 b'commands',
344 b'commands',
345 b'push.require-revs',
345 b'push.require-revs',
346 default=False,
346 default=False,
347 )
347 )
348 coreconfigitem(
348 coreconfigitem(
349 b'commands',
349 b'commands',
350 b'resolve.confirm',
350 b'resolve.confirm',
351 default=False,
351 default=False,
352 )
352 )
353 coreconfigitem(
353 coreconfigitem(
354 b'commands',
354 b'commands',
355 b'resolve.explicit-re-merge',
355 b'resolve.explicit-re-merge',
356 default=False,
356 default=False,
357 )
357 )
358 coreconfigitem(
358 coreconfigitem(
359 b'commands',
359 b'commands',
360 b'resolve.mark-check',
360 b'resolve.mark-check',
361 default=b'none',
361 default=b'none',
362 )
362 )
363 _registerdiffopts(section=b'commands', configprefix=b'revert.interactive.')
363 _registerdiffopts(section=b'commands', configprefix=b'revert.interactive.')
364 coreconfigitem(
364 coreconfigitem(
365 b'commands',
365 b'commands',
366 b'show.aliasprefix',
366 b'show.aliasprefix',
367 default=list,
367 default=list,
368 )
368 )
369 coreconfigitem(
369 coreconfigitem(
370 b'commands',
370 b'commands',
371 b'status.relative',
371 b'status.relative',
372 default=False,
372 default=False,
373 )
373 )
374 coreconfigitem(
374 coreconfigitem(
375 b'commands',
375 b'commands',
376 b'status.skipstates',
376 b'status.skipstates',
377 default=[],
377 default=[],
378 experimental=True,
378 experimental=True,
379 )
379 )
380 coreconfigitem(
380 coreconfigitem(
381 b'commands',
381 b'commands',
382 b'status.terse',
382 b'status.terse',
383 default=b'',
383 default=b'',
384 )
384 )
385 coreconfigitem(
385 coreconfigitem(
386 b'commands',
386 b'commands',
387 b'status.verbose',
387 b'status.verbose',
388 default=False,
388 default=False,
389 )
389 )
390 coreconfigitem(
390 coreconfigitem(
391 b'commands',
391 b'commands',
392 b'update.check',
392 b'update.check',
393 default=None,
393 default=None,
394 )
394 )
395 coreconfigitem(
395 coreconfigitem(
396 b'commands',
396 b'commands',
397 b'update.requiredest',
397 b'update.requiredest',
398 default=False,
398 default=False,
399 )
399 )
400 coreconfigitem(
400 coreconfigitem(
401 b'committemplate',
401 b'committemplate',
402 b'.*',
402 b'.*',
403 default=None,
403 default=None,
404 generic=True,
404 generic=True,
405 )
405 )
406 coreconfigitem(
406 coreconfigitem(
407 b'convert',
407 b'convert',
408 b'bzr.saverev',
408 b'bzr.saverev',
409 default=True,
409 default=True,
410 )
410 )
411 coreconfigitem(
411 coreconfigitem(
412 b'convert',
412 b'convert',
413 b'cvsps.cache',
413 b'cvsps.cache',
414 default=True,
414 default=True,
415 )
415 )
416 coreconfigitem(
416 coreconfigitem(
417 b'convert',
417 b'convert',
418 b'cvsps.fuzz',
418 b'cvsps.fuzz',
419 default=60,
419 default=60,
420 )
420 )
421 coreconfigitem(
421 coreconfigitem(
422 b'convert',
422 b'convert',
423 b'cvsps.logencoding',
423 b'cvsps.logencoding',
424 default=None,
424 default=None,
425 )
425 )
426 coreconfigitem(
426 coreconfigitem(
427 b'convert',
427 b'convert',
428 b'cvsps.mergefrom',
428 b'cvsps.mergefrom',
429 default=None,
429 default=None,
430 )
430 )
431 coreconfigitem(
431 coreconfigitem(
432 b'convert',
432 b'convert',
433 b'cvsps.mergeto',
433 b'cvsps.mergeto',
434 default=None,
434 default=None,
435 )
435 )
436 coreconfigitem(
436 coreconfigitem(
437 b'convert',
437 b'convert',
438 b'git.committeractions',
438 b'git.committeractions',
439 default=lambda: [b'messagedifferent'],
439 default=lambda: [b'messagedifferent'],
440 )
440 )
441 coreconfigitem(
441 coreconfigitem(
442 b'convert',
442 b'convert',
443 b'git.extrakeys',
443 b'git.extrakeys',
444 default=list,
444 default=list,
445 )
445 )
446 coreconfigitem(
446 coreconfigitem(
447 b'convert',
447 b'convert',
448 b'git.findcopiesharder',
448 b'git.findcopiesharder',
449 default=False,
449 default=False,
450 )
450 )
451 coreconfigitem(
451 coreconfigitem(
452 b'convert',
452 b'convert',
453 b'git.remoteprefix',
453 b'git.remoteprefix',
454 default=b'remote',
454 default=b'remote',
455 )
455 )
456 coreconfigitem(
456 coreconfigitem(
457 b'convert',
457 b'convert',
458 b'git.renamelimit',
458 b'git.renamelimit',
459 default=400,
459 default=400,
460 )
460 )
461 coreconfigitem(
461 coreconfigitem(
462 b'convert',
462 b'convert',
463 b'git.saverev',
463 b'git.saverev',
464 default=True,
464 default=True,
465 )
465 )
466 coreconfigitem(
466 coreconfigitem(
467 b'convert',
467 b'convert',
468 b'git.similarity',
468 b'git.similarity',
469 default=50,
469 default=50,
470 )
470 )
471 coreconfigitem(
471 coreconfigitem(
472 b'convert',
472 b'convert',
473 b'git.skipsubmodules',
473 b'git.skipsubmodules',
474 default=False,
474 default=False,
475 )
475 )
476 coreconfigitem(
476 coreconfigitem(
477 b'convert',
477 b'convert',
478 b'hg.clonebranches',
478 b'hg.clonebranches',
479 default=False,
479 default=False,
480 )
480 )
481 coreconfigitem(
481 coreconfigitem(
482 b'convert',
482 b'convert',
483 b'hg.ignoreerrors',
483 b'hg.ignoreerrors',
484 default=False,
484 default=False,
485 )
485 )
486 coreconfigitem(
486 coreconfigitem(
487 b'convert',
487 b'convert',
488 b'hg.preserve-hash',
488 b'hg.preserve-hash',
489 default=False,
489 default=False,
490 )
490 )
491 coreconfigitem(
491 coreconfigitem(
492 b'convert',
492 b'convert',
493 b'hg.revs',
493 b'hg.revs',
494 default=None,
494 default=None,
495 )
495 )
496 coreconfigitem(
496 coreconfigitem(
497 b'convert',
497 b'convert',
498 b'hg.saverev',
498 b'hg.saverev',
499 default=False,
499 default=False,
500 )
500 )
501 coreconfigitem(
501 coreconfigitem(
502 b'convert',
502 b'convert',
503 b'hg.sourcename',
503 b'hg.sourcename',
504 default=None,
504 default=None,
505 )
505 )
506 coreconfigitem(
506 coreconfigitem(
507 b'convert',
507 b'convert',
508 b'hg.startrev',
508 b'hg.startrev',
509 default=None,
509 default=None,
510 )
510 )
511 coreconfigitem(
511 coreconfigitem(
512 b'convert',
512 b'convert',
513 b'hg.tagsbranch',
513 b'hg.tagsbranch',
514 default=b'default',
514 default=b'default',
515 )
515 )
516 coreconfigitem(
516 coreconfigitem(
517 b'convert',
517 b'convert',
518 b'hg.usebranchnames',
518 b'hg.usebranchnames',
519 default=True,
519 default=True,
520 )
520 )
521 coreconfigitem(
521 coreconfigitem(
522 b'convert',
522 b'convert',
523 b'ignoreancestorcheck',
523 b'ignoreancestorcheck',
524 default=False,
524 default=False,
525 experimental=True,
525 experimental=True,
526 )
526 )
527 coreconfigitem(
527 coreconfigitem(
528 b'convert',
528 b'convert',
529 b'localtimezone',
529 b'localtimezone',
530 default=False,
530 default=False,
531 )
531 )
532 coreconfigitem(
532 coreconfigitem(
533 b'convert',
533 b'convert',
534 b'p4.encoding',
534 b'p4.encoding',
535 default=dynamicdefault,
535 default=dynamicdefault,
536 )
536 )
537 coreconfigitem(
537 coreconfigitem(
538 b'convert',
538 b'convert',
539 b'p4.startrev',
539 b'p4.startrev',
540 default=0,
540 default=0,
541 )
541 )
542 coreconfigitem(
542 coreconfigitem(
543 b'convert',
543 b'convert',
544 b'skiptags',
544 b'skiptags',
545 default=False,
545 default=False,
546 )
546 )
547 coreconfigitem(
547 coreconfigitem(
548 b'convert',
548 b'convert',
549 b'svn.debugsvnlog',
549 b'svn.debugsvnlog',
550 default=True,
550 default=True,
551 )
551 )
552 coreconfigitem(
552 coreconfigitem(
553 b'convert',
553 b'convert',
554 b'svn.trunk',
554 b'svn.trunk',
555 default=None,
555 default=None,
556 )
556 )
557 coreconfigitem(
557 coreconfigitem(
558 b'convert',
558 b'convert',
559 b'svn.tags',
559 b'svn.tags',
560 default=None,
560 default=None,
561 )
561 )
562 coreconfigitem(
562 coreconfigitem(
563 b'convert',
563 b'convert',
564 b'svn.branches',
564 b'svn.branches',
565 default=None,
565 default=None,
566 )
566 )
567 coreconfigitem(
567 coreconfigitem(
568 b'convert',
568 b'convert',
569 b'svn.startrev',
569 b'svn.startrev',
570 default=0,
570 default=0,
571 )
571 )
572 coreconfigitem(
572 coreconfigitem(
573 b'convert',
574 b'svn.dangerous-set-commit-dates',
575 default=False,
576 )
577 coreconfigitem(
573 b'debug',
578 b'debug',
574 b'dirstate.delaywrite',
579 b'dirstate.delaywrite',
575 default=0,
580 default=0,
576 )
581 )
577 coreconfigitem(
582 coreconfigitem(
578 b'defaults',
583 b'defaults',
579 b'.*',
584 b'.*',
580 default=None,
585 default=None,
581 generic=True,
586 generic=True,
582 )
587 )
583 coreconfigitem(
588 coreconfigitem(
584 b'devel',
589 b'devel',
585 b'all-warnings',
590 b'all-warnings',
586 default=False,
591 default=False,
587 )
592 )
588 coreconfigitem(
593 coreconfigitem(
589 b'devel',
594 b'devel',
590 b'bundle2.debug',
595 b'bundle2.debug',
591 default=False,
596 default=False,
592 )
597 )
593 coreconfigitem(
598 coreconfigitem(
594 b'devel',
599 b'devel',
595 b'bundle.delta',
600 b'bundle.delta',
596 default=b'',
601 default=b'',
597 )
602 )
598 coreconfigitem(
603 coreconfigitem(
599 b'devel',
604 b'devel',
600 b'cache-vfs',
605 b'cache-vfs',
601 default=None,
606 default=None,
602 )
607 )
603 coreconfigitem(
608 coreconfigitem(
604 b'devel',
609 b'devel',
605 b'check-locks',
610 b'check-locks',
606 default=False,
611 default=False,
607 )
612 )
608 coreconfigitem(
613 coreconfigitem(
609 b'devel',
614 b'devel',
610 b'check-relroot',
615 b'check-relroot',
611 default=False,
616 default=False,
612 )
617 )
613 coreconfigitem(
618 coreconfigitem(
614 b'devel',
619 b'devel',
615 b'default-date',
620 b'default-date',
616 default=None,
621 default=None,
617 )
622 )
618 coreconfigitem(
623 coreconfigitem(
619 b'devel',
624 b'devel',
620 b'deprec-warn',
625 b'deprec-warn',
621 default=False,
626 default=False,
622 )
627 )
623 coreconfigitem(
628 coreconfigitem(
624 b'devel',
629 b'devel',
625 b'disableloaddefaultcerts',
630 b'disableloaddefaultcerts',
626 default=False,
631 default=False,
627 )
632 )
628 coreconfigitem(
633 coreconfigitem(
629 b'devel',
634 b'devel',
630 b'warn-empty-changegroup',
635 b'warn-empty-changegroup',
631 default=False,
636 default=False,
632 )
637 )
633 coreconfigitem(
638 coreconfigitem(
634 b'devel',
639 b'devel',
635 b'legacy.exchange',
640 b'legacy.exchange',
636 default=list,
641 default=list,
637 )
642 )
638 # When True, revlogs use a special reference version of the nodemap, that is not
643 # When True, revlogs use a special reference version of the nodemap, that is not
639 # performant but is "known" to behave properly.
644 # performant but is "known" to behave properly.
640 coreconfigitem(
645 coreconfigitem(
641 b'devel',
646 b'devel',
642 b'persistent-nodemap',
647 b'persistent-nodemap',
643 default=False,
648 default=False,
644 )
649 )
645 coreconfigitem(
650 coreconfigitem(
646 b'devel',
651 b'devel',
647 b'servercafile',
652 b'servercafile',
648 default=b'',
653 default=b'',
649 )
654 )
650 coreconfigitem(
655 coreconfigitem(
651 b'devel',
656 b'devel',
652 b'serverexactprotocol',
657 b'serverexactprotocol',
653 default=b'',
658 default=b'',
654 )
659 )
655 coreconfigitem(
660 coreconfigitem(
656 b'devel',
661 b'devel',
657 b'serverrequirecert',
662 b'serverrequirecert',
658 default=False,
663 default=False,
659 )
664 )
660 coreconfigitem(
665 coreconfigitem(
661 b'devel',
666 b'devel',
662 b'strip-obsmarkers',
667 b'strip-obsmarkers',
663 default=True,
668 default=True,
664 )
669 )
665 coreconfigitem(
670 coreconfigitem(
666 b'devel',
671 b'devel',
667 b'warn-config',
672 b'warn-config',
668 default=None,
673 default=None,
669 )
674 )
670 coreconfigitem(
675 coreconfigitem(
671 b'devel',
676 b'devel',
672 b'warn-config-default',
677 b'warn-config-default',
673 default=None,
678 default=None,
674 )
679 )
675 coreconfigitem(
680 coreconfigitem(
676 b'devel',
681 b'devel',
677 b'user.obsmarker',
682 b'user.obsmarker',
678 default=None,
683 default=None,
679 )
684 )
680 coreconfigitem(
685 coreconfigitem(
681 b'devel',
686 b'devel',
682 b'warn-config-unknown',
687 b'warn-config-unknown',
683 default=None,
688 default=None,
684 )
689 )
685 coreconfigitem(
690 coreconfigitem(
686 b'devel',
691 b'devel',
687 b'debug.copies',
692 b'debug.copies',
688 default=False,
693 default=False,
689 )
694 )
690 coreconfigitem(
695 coreconfigitem(
691 b'devel',
696 b'devel',
692 b'debug.extensions',
697 b'debug.extensions',
693 default=False,
698 default=False,
694 )
699 )
695 coreconfigitem(
700 coreconfigitem(
696 b'devel',
701 b'devel',
697 b'debug.repo-filters',
702 b'debug.repo-filters',
698 default=False,
703 default=False,
699 )
704 )
700 coreconfigitem(
705 coreconfigitem(
701 b'devel',
706 b'devel',
702 b'debug.peer-request',
707 b'debug.peer-request',
703 default=False,
708 default=False,
704 )
709 )
705 # If discovery.exchange-heads is False, the discovery will not start with
710 # If discovery.exchange-heads is False, the discovery will not start with
706 # remote head fetching and local head querying.
711 # remote head fetching and local head querying.
707 coreconfigitem(
712 coreconfigitem(
708 b'devel',
713 b'devel',
709 b'discovery.exchange-heads',
714 b'discovery.exchange-heads',
710 default=True,
715 default=True,
711 )
716 )
712 # If discovery.grow-sample is False, the sample size used in set discovery will
717 # If discovery.grow-sample is False, the sample size used in set discovery will
713 # not be increased through the process
718 # not be increased through the process
714 coreconfigitem(
719 coreconfigitem(
715 b'devel',
720 b'devel',
716 b'discovery.grow-sample',
721 b'discovery.grow-sample',
717 default=True,
722 default=True,
718 )
723 )
719 # discovery.grow-sample.rate control the rate at which the sample grow
724 # discovery.grow-sample.rate control the rate at which the sample grow
720 coreconfigitem(
725 coreconfigitem(
721 b'devel',
726 b'devel',
722 b'discovery.grow-sample.rate',
727 b'discovery.grow-sample.rate',
723 default=1.05,
728 default=1.05,
724 )
729 )
725 # If discovery.randomize is False, random sampling during discovery are
730 # If discovery.randomize is False, random sampling during discovery are
726 # deterministic. It is meant for integration tests.
731 # deterministic. It is meant for integration tests.
727 coreconfigitem(
732 coreconfigitem(
728 b'devel',
733 b'devel',
729 b'discovery.randomize',
734 b'discovery.randomize',
730 default=True,
735 default=True,
731 )
736 )
732 # Control the initial size of the discovery sample
737 # Control the initial size of the discovery sample
733 coreconfigitem(
738 coreconfigitem(
734 b'devel',
739 b'devel',
735 b'discovery.sample-size',
740 b'discovery.sample-size',
736 default=200,
741 default=200,
737 )
742 )
738 # Control the initial size of the discovery for initial change
743 # Control the initial size of the discovery for initial change
739 coreconfigitem(
744 coreconfigitem(
740 b'devel',
745 b'devel',
741 b'discovery.sample-size.initial',
746 b'discovery.sample-size.initial',
742 default=100,
747 default=100,
743 )
748 )
744 _registerdiffopts(section=b'diff')
749 _registerdiffopts(section=b'diff')
745 coreconfigitem(
750 coreconfigitem(
746 b'email',
751 b'email',
747 b'bcc',
752 b'bcc',
748 default=None,
753 default=None,
749 )
754 )
750 coreconfigitem(
755 coreconfigitem(
751 b'email',
756 b'email',
752 b'cc',
757 b'cc',
753 default=None,
758 default=None,
754 )
759 )
755 coreconfigitem(
760 coreconfigitem(
756 b'email',
761 b'email',
757 b'charsets',
762 b'charsets',
758 default=list,
763 default=list,
759 )
764 )
760 coreconfigitem(
765 coreconfigitem(
761 b'email',
766 b'email',
762 b'from',
767 b'from',
763 default=None,
768 default=None,
764 )
769 )
765 coreconfigitem(
770 coreconfigitem(
766 b'email',
771 b'email',
767 b'method',
772 b'method',
768 default=b'smtp',
773 default=b'smtp',
769 )
774 )
770 coreconfigitem(
775 coreconfigitem(
771 b'email',
776 b'email',
772 b'reply-to',
777 b'reply-to',
773 default=None,
778 default=None,
774 )
779 )
775 coreconfigitem(
780 coreconfigitem(
776 b'email',
781 b'email',
777 b'to',
782 b'to',
778 default=None,
783 default=None,
779 )
784 )
780 coreconfigitem(
785 coreconfigitem(
781 b'experimental',
786 b'experimental',
782 b'archivemetatemplate',
787 b'archivemetatemplate',
783 default=dynamicdefault,
788 default=dynamicdefault,
784 )
789 )
785 coreconfigitem(
790 coreconfigitem(
786 b'experimental',
791 b'experimental',
787 b'auto-publish',
792 b'auto-publish',
788 default=b'publish',
793 default=b'publish',
789 )
794 )
790 coreconfigitem(
795 coreconfigitem(
791 b'experimental',
796 b'experimental',
792 b'bundle-phases',
797 b'bundle-phases',
793 default=False,
798 default=False,
794 )
799 )
795 coreconfigitem(
800 coreconfigitem(
796 b'experimental',
801 b'experimental',
797 b'bundle2-advertise',
802 b'bundle2-advertise',
798 default=True,
803 default=True,
799 )
804 )
800 coreconfigitem(
805 coreconfigitem(
801 b'experimental',
806 b'experimental',
802 b'bundle2-output-capture',
807 b'bundle2-output-capture',
803 default=False,
808 default=False,
804 )
809 )
805 coreconfigitem(
810 coreconfigitem(
806 b'experimental',
811 b'experimental',
807 b'bundle2.pushback',
812 b'bundle2.pushback',
808 default=False,
813 default=False,
809 )
814 )
810 coreconfigitem(
815 coreconfigitem(
811 b'experimental',
816 b'experimental',
812 b'bundle2lazylocking',
817 b'bundle2lazylocking',
813 default=False,
818 default=False,
814 )
819 )
815 coreconfigitem(
820 coreconfigitem(
816 b'experimental',
821 b'experimental',
817 b'bundlecomplevel',
822 b'bundlecomplevel',
818 default=None,
823 default=None,
819 )
824 )
820 coreconfigitem(
825 coreconfigitem(
821 b'experimental',
826 b'experimental',
822 b'bundlecomplevel.bzip2',
827 b'bundlecomplevel.bzip2',
823 default=None,
828 default=None,
824 )
829 )
825 coreconfigitem(
830 coreconfigitem(
826 b'experimental',
831 b'experimental',
827 b'bundlecomplevel.gzip',
832 b'bundlecomplevel.gzip',
828 default=None,
833 default=None,
829 )
834 )
830 coreconfigitem(
835 coreconfigitem(
831 b'experimental',
836 b'experimental',
832 b'bundlecomplevel.none',
837 b'bundlecomplevel.none',
833 default=None,
838 default=None,
834 )
839 )
835 coreconfigitem(
840 coreconfigitem(
836 b'experimental',
841 b'experimental',
837 b'bundlecomplevel.zstd',
842 b'bundlecomplevel.zstd',
838 default=None,
843 default=None,
839 )
844 )
840 coreconfigitem(
845 coreconfigitem(
841 b'experimental',
846 b'experimental',
842 b'changegroup3',
847 b'changegroup3',
843 default=False,
848 default=False,
844 )
849 )
845 coreconfigitem(
850 coreconfigitem(
846 b'experimental',
851 b'experimental',
847 b'cleanup-as-archived',
852 b'cleanup-as-archived',
848 default=False,
853 default=False,
849 )
854 )
850 coreconfigitem(
855 coreconfigitem(
851 b'experimental',
856 b'experimental',
852 b'clientcompressionengines',
857 b'clientcompressionengines',
853 default=list,
858 default=list,
854 )
859 )
855 coreconfigitem(
860 coreconfigitem(
856 b'experimental',
861 b'experimental',
857 b'copytrace',
862 b'copytrace',
858 default=b'on',
863 default=b'on',
859 )
864 )
860 coreconfigitem(
865 coreconfigitem(
861 b'experimental',
866 b'experimental',
862 b'copytrace.movecandidateslimit',
867 b'copytrace.movecandidateslimit',
863 default=100,
868 default=100,
864 )
869 )
865 coreconfigitem(
870 coreconfigitem(
866 b'experimental',
871 b'experimental',
867 b'copytrace.sourcecommitlimit',
872 b'copytrace.sourcecommitlimit',
868 default=100,
873 default=100,
869 )
874 )
870 coreconfigitem(
875 coreconfigitem(
871 b'experimental',
876 b'experimental',
872 b'copies.read-from',
877 b'copies.read-from',
873 default=b"filelog-only",
878 default=b"filelog-only",
874 )
879 )
875 coreconfigitem(
880 coreconfigitem(
876 b'experimental',
881 b'experimental',
877 b'copies.write-to',
882 b'copies.write-to',
878 default=b'filelog-only',
883 default=b'filelog-only',
879 )
884 )
880 coreconfigitem(
885 coreconfigitem(
881 b'experimental',
886 b'experimental',
882 b'crecordtest',
887 b'crecordtest',
883 default=None,
888 default=None,
884 )
889 )
885 coreconfigitem(
890 coreconfigitem(
886 b'experimental',
891 b'experimental',
887 b'directaccess',
892 b'directaccess',
888 default=False,
893 default=False,
889 )
894 )
890 coreconfigitem(
895 coreconfigitem(
891 b'experimental',
896 b'experimental',
892 b'directaccess.revnums',
897 b'directaccess.revnums',
893 default=False,
898 default=False,
894 )
899 )
895 coreconfigitem(
900 coreconfigitem(
896 b'experimental',
901 b'experimental',
897 b'editortmpinhg',
902 b'editortmpinhg',
898 default=False,
903 default=False,
899 )
904 )
900 coreconfigitem(
905 coreconfigitem(
901 b'experimental',
906 b'experimental',
902 b'evolution',
907 b'evolution',
903 default=list,
908 default=list,
904 )
909 )
905 coreconfigitem(
910 coreconfigitem(
906 b'experimental',
911 b'experimental',
907 b'evolution.allowdivergence',
912 b'evolution.allowdivergence',
908 default=False,
913 default=False,
909 alias=[(b'experimental', b'allowdivergence')],
914 alias=[(b'experimental', b'allowdivergence')],
910 )
915 )
911 coreconfigitem(
916 coreconfigitem(
912 b'experimental',
917 b'experimental',
913 b'evolution.allowunstable',
918 b'evolution.allowunstable',
914 default=None,
919 default=None,
915 )
920 )
916 coreconfigitem(
921 coreconfigitem(
917 b'experimental',
922 b'experimental',
918 b'evolution.createmarkers',
923 b'evolution.createmarkers',
919 default=None,
924 default=None,
920 )
925 )
921 coreconfigitem(
926 coreconfigitem(
922 b'experimental',
927 b'experimental',
923 b'evolution.effect-flags',
928 b'evolution.effect-flags',
924 default=True,
929 default=True,
925 alias=[(b'experimental', b'effect-flags')],
930 alias=[(b'experimental', b'effect-flags')],
926 )
931 )
927 coreconfigitem(
932 coreconfigitem(
928 b'experimental',
933 b'experimental',
929 b'evolution.exchange',
934 b'evolution.exchange',
930 default=None,
935 default=None,
931 )
936 )
932 coreconfigitem(
937 coreconfigitem(
933 b'experimental',
938 b'experimental',
934 b'evolution.bundle-obsmarker',
939 b'evolution.bundle-obsmarker',
935 default=False,
940 default=False,
936 )
941 )
937 coreconfigitem(
942 coreconfigitem(
938 b'experimental',
943 b'experimental',
939 b'evolution.bundle-obsmarker:mandatory',
944 b'evolution.bundle-obsmarker:mandatory',
940 default=True,
945 default=True,
941 )
946 )
942 coreconfigitem(
947 coreconfigitem(
943 b'experimental',
948 b'experimental',
944 b'log.topo',
949 b'log.topo',
945 default=False,
950 default=False,
946 )
951 )
947 coreconfigitem(
952 coreconfigitem(
948 b'experimental',
953 b'experimental',
949 b'evolution.report-instabilities',
954 b'evolution.report-instabilities',
950 default=True,
955 default=True,
951 )
956 )
952 coreconfigitem(
957 coreconfigitem(
953 b'experimental',
958 b'experimental',
954 b'evolution.track-operation',
959 b'evolution.track-operation',
955 default=True,
960 default=True,
956 )
961 )
957 # repo-level config to exclude a revset visibility
962 # repo-level config to exclude a revset visibility
958 #
963 #
959 # The target use case is to use `share` to expose different subset of the same
964 # The target use case is to use `share` to expose different subset of the same
960 # repository, especially server side. See also `server.view`.
965 # repository, especially server side. See also `server.view`.
961 coreconfigitem(
966 coreconfigitem(
962 b'experimental',
967 b'experimental',
963 b'extra-filter-revs',
968 b'extra-filter-revs',
964 default=None,
969 default=None,
965 )
970 )
966 coreconfigitem(
971 coreconfigitem(
967 b'experimental',
972 b'experimental',
968 b'maxdeltachainspan',
973 b'maxdeltachainspan',
969 default=-1,
974 default=-1,
970 )
975 )
971 # tracks files which were undeleted (merge might delete them but we explicitly
976 # tracks files which were undeleted (merge might delete them but we explicitly
972 # kept/undeleted them) and creates new filenodes for them
977 # kept/undeleted them) and creates new filenodes for them
973 coreconfigitem(
978 coreconfigitem(
974 b'experimental',
979 b'experimental',
975 b'merge-track-salvaged',
980 b'merge-track-salvaged',
976 default=False,
981 default=False,
977 )
982 )
978 coreconfigitem(
983 coreconfigitem(
979 b'experimental',
984 b'experimental',
980 b'mergetempdirprefix',
985 b'mergetempdirprefix',
981 default=None,
986 default=None,
982 )
987 )
983 coreconfigitem(
988 coreconfigitem(
984 b'experimental',
989 b'experimental',
985 b'mmapindexthreshold',
990 b'mmapindexthreshold',
986 default=None,
991 default=None,
987 )
992 )
988 coreconfigitem(
993 coreconfigitem(
989 b'experimental',
994 b'experimental',
990 b'narrow',
995 b'narrow',
991 default=False,
996 default=False,
992 )
997 )
993 coreconfigitem(
998 coreconfigitem(
994 b'experimental',
999 b'experimental',
995 b'nonnormalparanoidcheck',
1000 b'nonnormalparanoidcheck',
996 default=False,
1001 default=False,
997 )
1002 )
998 coreconfigitem(
1003 coreconfigitem(
999 b'experimental',
1004 b'experimental',
1000 b'exportableenviron',
1005 b'exportableenviron',
1001 default=list,
1006 default=list,
1002 )
1007 )
1003 coreconfigitem(
1008 coreconfigitem(
1004 b'experimental',
1009 b'experimental',
1005 b'extendedheader.index',
1010 b'extendedheader.index',
1006 default=None,
1011 default=None,
1007 )
1012 )
1008 coreconfigitem(
1013 coreconfigitem(
1009 b'experimental',
1014 b'experimental',
1010 b'extendedheader.similarity',
1015 b'extendedheader.similarity',
1011 default=False,
1016 default=False,
1012 )
1017 )
1013 coreconfigitem(
1018 coreconfigitem(
1014 b'experimental',
1019 b'experimental',
1015 b'graphshorten',
1020 b'graphshorten',
1016 default=False,
1021 default=False,
1017 )
1022 )
1018 coreconfigitem(
1023 coreconfigitem(
1019 b'experimental',
1024 b'experimental',
1020 b'graphstyle.parent',
1025 b'graphstyle.parent',
1021 default=dynamicdefault,
1026 default=dynamicdefault,
1022 )
1027 )
1023 coreconfigitem(
1028 coreconfigitem(
1024 b'experimental',
1029 b'experimental',
1025 b'graphstyle.missing',
1030 b'graphstyle.missing',
1026 default=dynamicdefault,
1031 default=dynamicdefault,
1027 )
1032 )
1028 coreconfigitem(
1033 coreconfigitem(
1029 b'experimental',
1034 b'experimental',
1030 b'graphstyle.grandparent',
1035 b'graphstyle.grandparent',
1031 default=dynamicdefault,
1036 default=dynamicdefault,
1032 )
1037 )
1033 coreconfigitem(
1038 coreconfigitem(
1034 b'experimental',
1039 b'experimental',
1035 b'hook-track-tags',
1040 b'hook-track-tags',
1036 default=False,
1041 default=False,
1037 )
1042 )
1038 coreconfigitem(
1043 coreconfigitem(
1039 b'experimental',
1044 b'experimental',
1040 b'httppeer.advertise-v2',
1045 b'httppeer.advertise-v2',
1041 default=False,
1046 default=False,
1042 )
1047 )
1043 coreconfigitem(
1048 coreconfigitem(
1044 b'experimental',
1049 b'experimental',
1045 b'httppeer.v2-encoder-order',
1050 b'httppeer.v2-encoder-order',
1046 default=None,
1051 default=None,
1047 )
1052 )
1048 coreconfigitem(
1053 coreconfigitem(
1049 b'experimental',
1054 b'experimental',
1050 b'httppostargs',
1055 b'httppostargs',
1051 default=False,
1056 default=False,
1052 )
1057 )
1053 coreconfigitem(b'experimental', b'nointerrupt', default=False)
1058 coreconfigitem(b'experimental', b'nointerrupt', default=False)
1054 coreconfigitem(b'experimental', b'nointerrupt-interactiveonly', default=True)
1059 coreconfigitem(b'experimental', b'nointerrupt-interactiveonly', default=True)
1055
1060
1056 coreconfigitem(
1061 coreconfigitem(
1057 b'experimental',
1062 b'experimental',
1058 b'obsmarkers-exchange-debug',
1063 b'obsmarkers-exchange-debug',
1059 default=False,
1064 default=False,
1060 )
1065 )
1061 coreconfigitem(
1066 coreconfigitem(
1062 b'experimental',
1067 b'experimental',
1063 b'remotenames',
1068 b'remotenames',
1064 default=False,
1069 default=False,
1065 )
1070 )
1066 coreconfigitem(
1071 coreconfigitem(
1067 b'experimental',
1072 b'experimental',
1068 b'removeemptydirs',
1073 b'removeemptydirs',
1069 default=True,
1074 default=True,
1070 )
1075 )
1071 coreconfigitem(
1076 coreconfigitem(
1072 b'experimental',
1077 b'experimental',
1073 b'revert.interactive.select-to-keep',
1078 b'revert.interactive.select-to-keep',
1074 default=False,
1079 default=False,
1075 )
1080 )
1076 coreconfigitem(
1081 coreconfigitem(
1077 b'experimental',
1082 b'experimental',
1078 b'revisions.prefixhexnode',
1083 b'revisions.prefixhexnode',
1079 default=False,
1084 default=False,
1080 )
1085 )
1081 coreconfigitem(
1086 coreconfigitem(
1082 b'experimental',
1087 b'experimental',
1083 b'revlogv2',
1088 b'revlogv2',
1084 default=None,
1089 default=None,
1085 )
1090 )
1086 coreconfigitem(
1091 coreconfigitem(
1087 b'experimental',
1092 b'experimental',
1088 b'revisions.disambiguatewithin',
1093 b'revisions.disambiguatewithin',
1089 default=None,
1094 default=None,
1090 )
1095 )
1091 coreconfigitem(
1096 coreconfigitem(
1092 b'experimental',
1097 b'experimental',
1093 b'rust.index',
1098 b'rust.index',
1094 default=False,
1099 default=False,
1095 )
1100 )
1096 coreconfigitem(
1101 coreconfigitem(
1097 b'experimental',
1102 b'experimental',
1098 b'server.filesdata.recommended-batch-size',
1103 b'server.filesdata.recommended-batch-size',
1099 default=50000,
1104 default=50000,
1100 )
1105 )
1101 coreconfigitem(
1106 coreconfigitem(
1102 b'experimental',
1107 b'experimental',
1103 b'server.manifestdata.recommended-batch-size',
1108 b'server.manifestdata.recommended-batch-size',
1104 default=100000,
1109 default=100000,
1105 )
1110 )
1106 coreconfigitem(
1111 coreconfigitem(
1107 b'experimental',
1112 b'experimental',
1108 b'server.stream-narrow-clones',
1113 b'server.stream-narrow-clones',
1109 default=False,
1114 default=False,
1110 )
1115 )
1111 coreconfigitem(
1116 coreconfigitem(
1112 b'experimental',
1117 b'experimental',
1113 b'single-head-per-branch',
1118 b'single-head-per-branch',
1114 default=False,
1119 default=False,
1115 )
1120 )
1116 coreconfigitem(
1121 coreconfigitem(
1117 b'experimental',
1122 b'experimental',
1118 b'single-head-per-branch:account-closed-heads',
1123 b'single-head-per-branch:account-closed-heads',
1119 default=False,
1124 default=False,
1120 )
1125 )
1121 coreconfigitem(
1126 coreconfigitem(
1122 b'experimental',
1127 b'experimental',
1123 b'single-head-per-branch:public-changes-only',
1128 b'single-head-per-branch:public-changes-only',
1124 default=False,
1129 default=False,
1125 )
1130 )
1126 coreconfigitem(
1131 coreconfigitem(
1127 b'experimental',
1132 b'experimental',
1128 b'sshserver.support-v2',
1133 b'sshserver.support-v2',
1129 default=False,
1134 default=False,
1130 )
1135 )
1131 coreconfigitem(
1136 coreconfigitem(
1132 b'experimental',
1137 b'experimental',
1133 b'sparse-read',
1138 b'sparse-read',
1134 default=False,
1139 default=False,
1135 )
1140 )
1136 coreconfigitem(
1141 coreconfigitem(
1137 b'experimental',
1142 b'experimental',
1138 b'sparse-read.density-threshold',
1143 b'sparse-read.density-threshold',
1139 default=0.50,
1144 default=0.50,
1140 )
1145 )
1141 coreconfigitem(
1146 coreconfigitem(
1142 b'experimental',
1147 b'experimental',
1143 b'sparse-read.min-gap-size',
1148 b'sparse-read.min-gap-size',
1144 default=b'65K',
1149 default=b'65K',
1145 )
1150 )
1146 coreconfigitem(
1151 coreconfigitem(
1147 b'experimental',
1152 b'experimental',
1148 b'treemanifest',
1153 b'treemanifest',
1149 default=False,
1154 default=False,
1150 )
1155 )
1151 coreconfigitem(
1156 coreconfigitem(
1152 b'experimental',
1157 b'experimental',
1153 b'update.atomic-file',
1158 b'update.atomic-file',
1154 default=False,
1159 default=False,
1155 )
1160 )
1156 coreconfigitem(
1161 coreconfigitem(
1157 b'experimental',
1162 b'experimental',
1158 b'sshpeer.advertise-v2',
1163 b'sshpeer.advertise-v2',
1159 default=False,
1164 default=False,
1160 )
1165 )
1161 coreconfigitem(
1166 coreconfigitem(
1162 b'experimental',
1167 b'experimental',
1163 b'web.apiserver',
1168 b'web.apiserver',
1164 default=False,
1169 default=False,
1165 )
1170 )
1166 coreconfigitem(
1171 coreconfigitem(
1167 b'experimental',
1172 b'experimental',
1168 b'web.api.http-v2',
1173 b'web.api.http-v2',
1169 default=False,
1174 default=False,
1170 )
1175 )
1171 coreconfigitem(
1176 coreconfigitem(
1172 b'experimental',
1177 b'experimental',
1173 b'web.api.debugreflect',
1178 b'web.api.debugreflect',
1174 default=False,
1179 default=False,
1175 )
1180 )
1176 coreconfigitem(
1181 coreconfigitem(
1177 b'experimental',
1182 b'experimental',
1178 b'worker.wdir-get-thread-safe',
1183 b'worker.wdir-get-thread-safe',
1179 default=False,
1184 default=False,
1180 )
1185 )
1181 coreconfigitem(
1186 coreconfigitem(
1182 b'experimental',
1187 b'experimental',
1183 b'worker.repository-upgrade',
1188 b'worker.repository-upgrade',
1184 default=False,
1189 default=False,
1185 )
1190 )
1186 coreconfigitem(
1191 coreconfigitem(
1187 b'experimental',
1192 b'experimental',
1188 b'xdiff',
1193 b'xdiff',
1189 default=False,
1194 default=False,
1190 )
1195 )
1191 coreconfigitem(
1196 coreconfigitem(
1192 b'extensions',
1197 b'extensions',
1193 b'.*',
1198 b'.*',
1194 default=None,
1199 default=None,
1195 generic=True,
1200 generic=True,
1196 )
1201 )
1197 coreconfigitem(
1202 coreconfigitem(
1198 b'extdata',
1203 b'extdata',
1199 b'.*',
1204 b'.*',
1200 default=None,
1205 default=None,
1201 generic=True,
1206 generic=True,
1202 )
1207 )
1203 coreconfigitem(
1208 coreconfigitem(
1204 b'format',
1209 b'format',
1205 b'bookmarks-in-store',
1210 b'bookmarks-in-store',
1206 default=False,
1211 default=False,
1207 )
1212 )
1208 coreconfigitem(
1213 coreconfigitem(
1209 b'format',
1214 b'format',
1210 b'chunkcachesize',
1215 b'chunkcachesize',
1211 default=None,
1216 default=None,
1212 experimental=True,
1217 experimental=True,
1213 )
1218 )
1214 coreconfigitem(
1219 coreconfigitem(
1215 b'format',
1220 b'format',
1216 b'dotencode',
1221 b'dotencode',
1217 default=True,
1222 default=True,
1218 )
1223 )
1219 coreconfigitem(
1224 coreconfigitem(
1220 b'format',
1225 b'format',
1221 b'generaldelta',
1226 b'generaldelta',
1222 default=False,
1227 default=False,
1223 experimental=True,
1228 experimental=True,
1224 )
1229 )
1225 coreconfigitem(
1230 coreconfigitem(
1226 b'format',
1231 b'format',
1227 b'manifestcachesize',
1232 b'manifestcachesize',
1228 default=None,
1233 default=None,
1229 experimental=True,
1234 experimental=True,
1230 )
1235 )
1231 coreconfigitem(
1236 coreconfigitem(
1232 b'format',
1237 b'format',
1233 b'maxchainlen',
1238 b'maxchainlen',
1234 default=dynamicdefault,
1239 default=dynamicdefault,
1235 experimental=True,
1240 experimental=True,
1236 )
1241 )
1237 coreconfigitem(
1242 coreconfigitem(
1238 b'format',
1243 b'format',
1239 b'obsstore-version',
1244 b'obsstore-version',
1240 default=None,
1245 default=None,
1241 )
1246 )
1242 coreconfigitem(
1247 coreconfigitem(
1243 b'format',
1248 b'format',
1244 b'sparse-revlog',
1249 b'sparse-revlog',
1245 default=True,
1250 default=True,
1246 )
1251 )
1247 coreconfigitem(
1252 coreconfigitem(
1248 b'format',
1253 b'format',
1249 b'revlog-compression',
1254 b'revlog-compression',
1250 default=lambda: [b'zlib'],
1255 default=lambda: [b'zlib'],
1251 alias=[(b'experimental', b'format.compression')],
1256 alias=[(b'experimental', b'format.compression')],
1252 )
1257 )
1253 coreconfigitem(
1258 coreconfigitem(
1254 b'format',
1259 b'format',
1255 b'usefncache',
1260 b'usefncache',
1256 default=True,
1261 default=True,
1257 )
1262 )
1258 coreconfigitem(
1263 coreconfigitem(
1259 b'format',
1264 b'format',
1260 b'usegeneraldelta',
1265 b'usegeneraldelta',
1261 default=True,
1266 default=True,
1262 )
1267 )
1263 coreconfigitem(
1268 coreconfigitem(
1264 b'format',
1269 b'format',
1265 b'usestore',
1270 b'usestore',
1266 default=True,
1271 default=True,
1267 )
1272 )
1268 coreconfigitem(
1273 coreconfigitem(
1269 b'format',
1274 b'format',
1270 b'use-persistent-nodemap',
1275 b'use-persistent-nodemap',
1271 default=False,
1276 default=False,
1272 )
1277 )
1273 coreconfigitem(
1278 coreconfigitem(
1274 b'format',
1279 b'format',
1275 b'exp-use-copies-side-data-changeset',
1280 b'exp-use-copies-side-data-changeset',
1276 default=False,
1281 default=False,
1277 experimental=True,
1282 experimental=True,
1278 )
1283 )
1279 coreconfigitem(
1284 coreconfigitem(
1280 b'format',
1285 b'format',
1281 b'exp-use-side-data',
1286 b'exp-use-side-data',
1282 default=False,
1287 default=False,
1283 experimental=True,
1288 experimental=True,
1284 )
1289 )
1285 coreconfigitem(
1290 coreconfigitem(
1286 b'format',
1291 b'format',
1287 b'use-share-safe',
1292 b'use-share-safe',
1288 default=False,
1293 default=False,
1289 )
1294 )
1290 coreconfigitem(
1295 coreconfigitem(
1291 b'format',
1296 b'format',
1292 b'internal-phase',
1297 b'internal-phase',
1293 default=False,
1298 default=False,
1294 experimental=True,
1299 experimental=True,
1295 )
1300 )
1296 coreconfigitem(
1301 coreconfigitem(
1297 b'fsmonitor',
1302 b'fsmonitor',
1298 b'warn_when_unused',
1303 b'warn_when_unused',
1299 default=True,
1304 default=True,
1300 )
1305 )
1301 coreconfigitem(
1306 coreconfigitem(
1302 b'fsmonitor',
1307 b'fsmonitor',
1303 b'warn_update_file_count',
1308 b'warn_update_file_count',
1304 default=50000,
1309 default=50000,
1305 )
1310 )
1306 coreconfigitem(
1311 coreconfigitem(
1307 b'fsmonitor',
1312 b'fsmonitor',
1308 b'warn_update_file_count_rust',
1313 b'warn_update_file_count_rust',
1309 default=400000,
1314 default=400000,
1310 )
1315 )
1311 coreconfigitem(
1316 coreconfigitem(
1312 b'help',
1317 b'help',
1313 br'hidden-command\..*',
1318 br'hidden-command\..*',
1314 default=False,
1319 default=False,
1315 generic=True,
1320 generic=True,
1316 )
1321 )
1317 coreconfigitem(
1322 coreconfigitem(
1318 b'help',
1323 b'help',
1319 br'hidden-topic\..*',
1324 br'hidden-topic\..*',
1320 default=False,
1325 default=False,
1321 generic=True,
1326 generic=True,
1322 )
1327 )
1323 coreconfigitem(
1328 coreconfigitem(
1324 b'hooks',
1329 b'hooks',
1325 b'.*',
1330 b'.*',
1326 default=dynamicdefault,
1331 default=dynamicdefault,
1327 generic=True,
1332 generic=True,
1328 )
1333 )
1329 coreconfigitem(
1334 coreconfigitem(
1330 b'hgweb-paths',
1335 b'hgweb-paths',
1331 b'.*',
1336 b'.*',
1332 default=list,
1337 default=list,
1333 generic=True,
1338 generic=True,
1334 )
1339 )
1335 coreconfigitem(
1340 coreconfigitem(
1336 b'hostfingerprints',
1341 b'hostfingerprints',
1337 b'.*',
1342 b'.*',
1338 default=list,
1343 default=list,
1339 generic=True,
1344 generic=True,
1340 )
1345 )
1341 coreconfigitem(
1346 coreconfigitem(
1342 b'hostsecurity',
1347 b'hostsecurity',
1343 b'ciphers',
1348 b'ciphers',
1344 default=None,
1349 default=None,
1345 )
1350 )
1346 coreconfigitem(
1351 coreconfigitem(
1347 b'hostsecurity',
1352 b'hostsecurity',
1348 b'minimumprotocol',
1353 b'minimumprotocol',
1349 default=dynamicdefault,
1354 default=dynamicdefault,
1350 )
1355 )
1351 coreconfigitem(
1356 coreconfigitem(
1352 b'hostsecurity',
1357 b'hostsecurity',
1353 b'.*:minimumprotocol$',
1358 b'.*:minimumprotocol$',
1354 default=dynamicdefault,
1359 default=dynamicdefault,
1355 generic=True,
1360 generic=True,
1356 )
1361 )
1357 coreconfigitem(
1362 coreconfigitem(
1358 b'hostsecurity',
1363 b'hostsecurity',
1359 b'.*:ciphers$',
1364 b'.*:ciphers$',
1360 default=dynamicdefault,
1365 default=dynamicdefault,
1361 generic=True,
1366 generic=True,
1362 )
1367 )
1363 coreconfigitem(
1368 coreconfigitem(
1364 b'hostsecurity',
1369 b'hostsecurity',
1365 b'.*:fingerprints$',
1370 b'.*:fingerprints$',
1366 default=list,
1371 default=list,
1367 generic=True,
1372 generic=True,
1368 )
1373 )
1369 coreconfigitem(
1374 coreconfigitem(
1370 b'hostsecurity',
1375 b'hostsecurity',
1371 b'.*:verifycertsfile$',
1376 b'.*:verifycertsfile$',
1372 default=None,
1377 default=None,
1373 generic=True,
1378 generic=True,
1374 )
1379 )
1375
1380
1376 coreconfigitem(
1381 coreconfigitem(
1377 b'http_proxy',
1382 b'http_proxy',
1378 b'always',
1383 b'always',
1379 default=False,
1384 default=False,
1380 )
1385 )
1381 coreconfigitem(
1386 coreconfigitem(
1382 b'http_proxy',
1387 b'http_proxy',
1383 b'host',
1388 b'host',
1384 default=None,
1389 default=None,
1385 )
1390 )
1386 coreconfigitem(
1391 coreconfigitem(
1387 b'http_proxy',
1392 b'http_proxy',
1388 b'no',
1393 b'no',
1389 default=list,
1394 default=list,
1390 )
1395 )
1391 coreconfigitem(
1396 coreconfigitem(
1392 b'http_proxy',
1397 b'http_proxy',
1393 b'passwd',
1398 b'passwd',
1394 default=None,
1399 default=None,
1395 )
1400 )
1396 coreconfigitem(
1401 coreconfigitem(
1397 b'http_proxy',
1402 b'http_proxy',
1398 b'user',
1403 b'user',
1399 default=None,
1404 default=None,
1400 )
1405 )
1401
1406
1402 coreconfigitem(
1407 coreconfigitem(
1403 b'http',
1408 b'http',
1404 b'timeout',
1409 b'timeout',
1405 default=None,
1410 default=None,
1406 )
1411 )
1407
1412
1408 coreconfigitem(
1413 coreconfigitem(
1409 b'logtoprocess',
1414 b'logtoprocess',
1410 b'commandexception',
1415 b'commandexception',
1411 default=None,
1416 default=None,
1412 )
1417 )
1413 coreconfigitem(
1418 coreconfigitem(
1414 b'logtoprocess',
1419 b'logtoprocess',
1415 b'commandfinish',
1420 b'commandfinish',
1416 default=None,
1421 default=None,
1417 )
1422 )
1418 coreconfigitem(
1423 coreconfigitem(
1419 b'logtoprocess',
1424 b'logtoprocess',
1420 b'command',
1425 b'command',
1421 default=None,
1426 default=None,
1422 )
1427 )
1423 coreconfigitem(
1428 coreconfigitem(
1424 b'logtoprocess',
1429 b'logtoprocess',
1425 b'develwarn',
1430 b'develwarn',
1426 default=None,
1431 default=None,
1427 )
1432 )
1428 coreconfigitem(
1433 coreconfigitem(
1429 b'logtoprocess',
1434 b'logtoprocess',
1430 b'uiblocked',
1435 b'uiblocked',
1431 default=None,
1436 default=None,
1432 )
1437 )
1433 coreconfigitem(
1438 coreconfigitem(
1434 b'merge',
1439 b'merge',
1435 b'checkunknown',
1440 b'checkunknown',
1436 default=b'abort',
1441 default=b'abort',
1437 )
1442 )
1438 coreconfigitem(
1443 coreconfigitem(
1439 b'merge',
1444 b'merge',
1440 b'checkignored',
1445 b'checkignored',
1441 default=b'abort',
1446 default=b'abort',
1442 )
1447 )
1443 coreconfigitem(
1448 coreconfigitem(
1444 b'experimental',
1449 b'experimental',
1445 b'merge.checkpathconflicts',
1450 b'merge.checkpathconflicts',
1446 default=False,
1451 default=False,
1447 )
1452 )
1448 coreconfigitem(
1453 coreconfigitem(
1449 b'merge',
1454 b'merge',
1450 b'followcopies',
1455 b'followcopies',
1451 default=True,
1456 default=True,
1452 )
1457 )
1453 coreconfigitem(
1458 coreconfigitem(
1454 b'merge',
1459 b'merge',
1455 b'on-failure',
1460 b'on-failure',
1456 default=b'continue',
1461 default=b'continue',
1457 )
1462 )
1458 coreconfigitem(
1463 coreconfigitem(
1459 b'merge',
1464 b'merge',
1460 b'preferancestor',
1465 b'preferancestor',
1461 default=lambda: [b'*'],
1466 default=lambda: [b'*'],
1462 experimental=True,
1467 experimental=True,
1463 )
1468 )
1464 coreconfigitem(
1469 coreconfigitem(
1465 b'merge',
1470 b'merge',
1466 b'strict-capability-check',
1471 b'strict-capability-check',
1467 default=False,
1472 default=False,
1468 )
1473 )
1469 coreconfigitem(
1474 coreconfigitem(
1470 b'merge-tools',
1475 b'merge-tools',
1471 b'.*',
1476 b'.*',
1472 default=None,
1477 default=None,
1473 generic=True,
1478 generic=True,
1474 )
1479 )
1475 coreconfigitem(
1480 coreconfigitem(
1476 b'merge-tools',
1481 b'merge-tools',
1477 br'.*\.args$',
1482 br'.*\.args$',
1478 default=b"$local $base $other",
1483 default=b"$local $base $other",
1479 generic=True,
1484 generic=True,
1480 priority=-1,
1485 priority=-1,
1481 )
1486 )
1482 coreconfigitem(
1487 coreconfigitem(
1483 b'merge-tools',
1488 b'merge-tools',
1484 br'.*\.binary$',
1489 br'.*\.binary$',
1485 default=False,
1490 default=False,
1486 generic=True,
1491 generic=True,
1487 priority=-1,
1492 priority=-1,
1488 )
1493 )
1489 coreconfigitem(
1494 coreconfigitem(
1490 b'merge-tools',
1495 b'merge-tools',
1491 br'.*\.check$',
1496 br'.*\.check$',
1492 default=list,
1497 default=list,
1493 generic=True,
1498 generic=True,
1494 priority=-1,
1499 priority=-1,
1495 )
1500 )
1496 coreconfigitem(
1501 coreconfigitem(
1497 b'merge-tools',
1502 b'merge-tools',
1498 br'.*\.checkchanged$',
1503 br'.*\.checkchanged$',
1499 default=False,
1504 default=False,
1500 generic=True,
1505 generic=True,
1501 priority=-1,
1506 priority=-1,
1502 )
1507 )
1503 coreconfigitem(
1508 coreconfigitem(
1504 b'merge-tools',
1509 b'merge-tools',
1505 br'.*\.executable$',
1510 br'.*\.executable$',
1506 default=dynamicdefault,
1511 default=dynamicdefault,
1507 generic=True,
1512 generic=True,
1508 priority=-1,
1513 priority=-1,
1509 )
1514 )
1510 coreconfigitem(
1515 coreconfigitem(
1511 b'merge-tools',
1516 b'merge-tools',
1512 br'.*\.fixeol$',
1517 br'.*\.fixeol$',
1513 default=False,
1518 default=False,
1514 generic=True,
1519 generic=True,
1515 priority=-1,
1520 priority=-1,
1516 )
1521 )
1517 coreconfigitem(
1522 coreconfigitem(
1518 b'merge-tools',
1523 b'merge-tools',
1519 br'.*\.gui$',
1524 br'.*\.gui$',
1520 default=False,
1525 default=False,
1521 generic=True,
1526 generic=True,
1522 priority=-1,
1527 priority=-1,
1523 )
1528 )
1524 coreconfigitem(
1529 coreconfigitem(
1525 b'merge-tools',
1530 b'merge-tools',
1526 br'.*\.mergemarkers$',
1531 br'.*\.mergemarkers$',
1527 default=b'basic',
1532 default=b'basic',
1528 generic=True,
1533 generic=True,
1529 priority=-1,
1534 priority=-1,
1530 )
1535 )
1531 coreconfigitem(
1536 coreconfigitem(
1532 b'merge-tools',
1537 b'merge-tools',
1533 br'.*\.mergemarkertemplate$',
1538 br'.*\.mergemarkertemplate$',
1534 default=dynamicdefault, # take from command-templates.mergemarker
1539 default=dynamicdefault, # take from command-templates.mergemarker
1535 generic=True,
1540 generic=True,
1536 priority=-1,
1541 priority=-1,
1537 )
1542 )
1538 coreconfigitem(
1543 coreconfigitem(
1539 b'merge-tools',
1544 b'merge-tools',
1540 br'.*\.priority$',
1545 br'.*\.priority$',
1541 default=0,
1546 default=0,
1542 generic=True,
1547 generic=True,
1543 priority=-1,
1548 priority=-1,
1544 )
1549 )
1545 coreconfigitem(
1550 coreconfigitem(
1546 b'merge-tools',
1551 b'merge-tools',
1547 br'.*\.premerge$',
1552 br'.*\.premerge$',
1548 default=dynamicdefault,
1553 default=dynamicdefault,
1549 generic=True,
1554 generic=True,
1550 priority=-1,
1555 priority=-1,
1551 )
1556 )
1552 coreconfigitem(
1557 coreconfigitem(
1553 b'merge-tools',
1558 b'merge-tools',
1554 br'.*\.symlink$',
1559 br'.*\.symlink$',
1555 default=False,
1560 default=False,
1556 generic=True,
1561 generic=True,
1557 priority=-1,
1562 priority=-1,
1558 )
1563 )
1559 coreconfigitem(
1564 coreconfigitem(
1560 b'pager',
1565 b'pager',
1561 b'attend-.*',
1566 b'attend-.*',
1562 default=dynamicdefault,
1567 default=dynamicdefault,
1563 generic=True,
1568 generic=True,
1564 )
1569 )
1565 coreconfigitem(
1570 coreconfigitem(
1566 b'pager',
1571 b'pager',
1567 b'ignore',
1572 b'ignore',
1568 default=list,
1573 default=list,
1569 )
1574 )
1570 coreconfigitem(
1575 coreconfigitem(
1571 b'pager',
1576 b'pager',
1572 b'pager',
1577 b'pager',
1573 default=dynamicdefault,
1578 default=dynamicdefault,
1574 )
1579 )
1575 coreconfigitem(
1580 coreconfigitem(
1576 b'patch',
1581 b'patch',
1577 b'eol',
1582 b'eol',
1578 default=b'strict',
1583 default=b'strict',
1579 )
1584 )
1580 coreconfigitem(
1585 coreconfigitem(
1581 b'patch',
1586 b'patch',
1582 b'fuzz',
1587 b'fuzz',
1583 default=2,
1588 default=2,
1584 )
1589 )
1585 coreconfigitem(
1590 coreconfigitem(
1586 b'paths',
1591 b'paths',
1587 b'default',
1592 b'default',
1588 default=None,
1593 default=None,
1589 )
1594 )
1590 coreconfigitem(
1595 coreconfigitem(
1591 b'paths',
1596 b'paths',
1592 b'default-push',
1597 b'default-push',
1593 default=None,
1598 default=None,
1594 )
1599 )
1595 coreconfigitem(
1600 coreconfigitem(
1596 b'paths',
1601 b'paths',
1597 b'.*',
1602 b'.*',
1598 default=None,
1603 default=None,
1599 generic=True,
1604 generic=True,
1600 )
1605 )
1601 coreconfigitem(
1606 coreconfigitem(
1602 b'phases',
1607 b'phases',
1603 b'checksubrepos',
1608 b'checksubrepos',
1604 default=b'follow',
1609 default=b'follow',
1605 )
1610 )
1606 coreconfigitem(
1611 coreconfigitem(
1607 b'phases',
1612 b'phases',
1608 b'new-commit',
1613 b'new-commit',
1609 default=b'draft',
1614 default=b'draft',
1610 )
1615 )
1611 coreconfigitem(
1616 coreconfigitem(
1612 b'phases',
1617 b'phases',
1613 b'publish',
1618 b'publish',
1614 default=True,
1619 default=True,
1615 )
1620 )
1616 coreconfigitem(
1621 coreconfigitem(
1617 b'profiling',
1622 b'profiling',
1618 b'enabled',
1623 b'enabled',
1619 default=False,
1624 default=False,
1620 )
1625 )
1621 coreconfigitem(
1626 coreconfigitem(
1622 b'profiling',
1627 b'profiling',
1623 b'format',
1628 b'format',
1624 default=b'text',
1629 default=b'text',
1625 )
1630 )
1626 coreconfigitem(
1631 coreconfigitem(
1627 b'profiling',
1632 b'profiling',
1628 b'freq',
1633 b'freq',
1629 default=1000,
1634 default=1000,
1630 )
1635 )
1631 coreconfigitem(
1636 coreconfigitem(
1632 b'profiling',
1637 b'profiling',
1633 b'limit',
1638 b'limit',
1634 default=30,
1639 default=30,
1635 )
1640 )
1636 coreconfigitem(
1641 coreconfigitem(
1637 b'profiling',
1642 b'profiling',
1638 b'nested',
1643 b'nested',
1639 default=0,
1644 default=0,
1640 )
1645 )
1641 coreconfigitem(
1646 coreconfigitem(
1642 b'profiling',
1647 b'profiling',
1643 b'output',
1648 b'output',
1644 default=None,
1649 default=None,
1645 )
1650 )
1646 coreconfigitem(
1651 coreconfigitem(
1647 b'profiling',
1652 b'profiling',
1648 b'showmax',
1653 b'showmax',
1649 default=0.999,
1654 default=0.999,
1650 )
1655 )
1651 coreconfigitem(
1656 coreconfigitem(
1652 b'profiling',
1657 b'profiling',
1653 b'showmin',
1658 b'showmin',
1654 default=dynamicdefault,
1659 default=dynamicdefault,
1655 )
1660 )
1656 coreconfigitem(
1661 coreconfigitem(
1657 b'profiling',
1662 b'profiling',
1658 b'showtime',
1663 b'showtime',
1659 default=True,
1664 default=True,
1660 )
1665 )
1661 coreconfigitem(
1666 coreconfigitem(
1662 b'profiling',
1667 b'profiling',
1663 b'sort',
1668 b'sort',
1664 default=b'inlinetime',
1669 default=b'inlinetime',
1665 )
1670 )
1666 coreconfigitem(
1671 coreconfigitem(
1667 b'profiling',
1672 b'profiling',
1668 b'statformat',
1673 b'statformat',
1669 default=b'hotpath',
1674 default=b'hotpath',
1670 )
1675 )
1671 coreconfigitem(
1676 coreconfigitem(
1672 b'profiling',
1677 b'profiling',
1673 b'time-track',
1678 b'time-track',
1674 default=dynamicdefault,
1679 default=dynamicdefault,
1675 )
1680 )
1676 coreconfigitem(
1681 coreconfigitem(
1677 b'profiling',
1682 b'profiling',
1678 b'type',
1683 b'type',
1679 default=b'stat',
1684 default=b'stat',
1680 )
1685 )
1681 coreconfigitem(
1686 coreconfigitem(
1682 b'progress',
1687 b'progress',
1683 b'assume-tty',
1688 b'assume-tty',
1684 default=False,
1689 default=False,
1685 )
1690 )
1686 coreconfigitem(
1691 coreconfigitem(
1687 b'progress',
1692 b'progress',
1688 b'changedelay',
1693 b'changedelay',
1689 default=1,
1694 default=1,
1690 )
1695 )
1691 coreconfigitem(
1696 coreconfigitem(
1692 b'progress',
1697 b'progress',
1693 b'clear-complete',
1698 b'clear-complete',
1694 default=True,
1699 default=True,
1695 )
1700 )
1696 coreconfigitem(
1701 coreconfigitem(
1697 b'progress',
1702 b'progress',
1698 b'debug',
1703 b'debug',
1699 default=False,
1704 default=False,
1700 )
1705 )
1701 coreconfigitem(
1706 coreconfigitem(
1702 b'progress',
1707 b'progress',
1703 b'delay',
1708 b'delay',
1704 default=3,
1709 default=3,
1705 )
1710 )
1706 coreconfigitem(
1711 coreconfigitem(
1707 b'progress',
1712 b'progress',
1708 b'disable',
1713 b'disable',
1709 default=False,
1714 default=False,
1710 )
1715 )
1711 coreconfigitem(
1716 coreconfigitem(
1712 b'progress',
1717 b'progress',
1713 b'estimateinterval',
1718 b'estimateinterval',
1714 default=60.0,
1719 default=60.0,
1715 )
1720 )
1716 coreconfigitem(
1721 coreconfigitem(
1717 b'progress',
1722 b'progress',
1718 b'format',
1723 b'format',
1719 default=lambda: [b'topic', b'bar', b'number', b'estimate'],
1724 default=lambda: [b'topic', b'bar', b'number', b'estimate'],
1720 )
1725 )
1721 coreconfigitem(
1726 coreconfigitem(
1722 b'progress',
1727 b'progress',
1723 b'refresh',
1728 b'refresh',
1724 default=0.1,
1729 default=0.1,
1725 )
1730 )
1726 coreconfigitem(
1731 coreconfigitem(
1727 b'progress',
1732 b'progress',
1728 b'width',
1733 b'width',
1729 default=dynamicdefault,
1734 default=dynamicdefault,
1730 )
1735 )
1731 coreconfigitem(
1736 coreconfigitem(
1732 b'pull',
1737 b'pull',
1733 b'confirm',
1738 b'confirm',
1734 default=False,
1739 default=False,
1735 )
1740 )
1736 coreconfigitem(
1741 coreconfigitem(
1737 b'push',
1742 b'push',
1738 b'pushvars.server',
1743 b'pushvars.server',
1739 default=False,
1744 default=False,
1740 )
1745 )
1741 coreconfigitem(
1746 coreconfigitem(
1742 b'rewrite',
1747 b'rewrite',
1743 b'backup-bundle',
1748 b'backup-bundle',
1744 default=True,
1749 default=True,
1745 alias=[(b'ui', b'history-editing-backup')],
1750 alias=[(b'ui', b'history-editing-backup')],
1746 )
1751 )
1747 coreconfigitem(
1752 coreconfigitem(
1748 b'rewrite',
1753 b'rewrite',
1749 b'update-timestamp',
1754 b'update-timestamp',
1750 default=False,
1755 default=False,
1751 )
1756 )
1752 coreconfigitem(
1757 coreconfigitem(
1753 b'rewrite',
1758 b'rewrite',
1754 b'empty-successor',
1759 b'empty-successor',
1755 default=b'skip',
1760 default=b'skip',
1756 experimental=True,
1761 experimental=True,
1757 )
1762 )
1758 coreconfigitem(
1763 coreconfigitem(
1759 b'storage',
1764 b'storage',
1760 b'new-repo-backend',
1765 b'new-repo-backend',
1761 default=b'revlogv1',
1766 default=b'revlogv1',
1762 experimental=True,
1767 experimental=True,
1763 )
1768 )
1764 coreconfigitem(
1769 coreconfigitem(
1765 b'storage',
1770 b'storage',
1766 b'revlog.optimize-delta-parent-choice',
1771 b'revlog.optimize-delta-parent-choice',
1767 default=True,
1772 default=True,
1768 alias=[(b'format', b'aggressivemergedeltas')],
1773 alias=[(b'format', b'aggressivemergedeltas')],
1769 )
1774 )
1770 # experimental as long as rust is experimental (or a C version is implemented)
1775 # experimental as long as rust is experimental (or a C version is implemented)
1771 coreconfigitem(
1776 coreconfigitem(
1772 b'storage',
1777 b'storage',
1773 b'revlog.persistent-nodemap.mmap',
1778 b'revlog.persistent-nodemap.mmap',
1774 default=True,
1779 default=True,
1775 )
1780 )
1776 # experimental as long as format.use-persistent-nodemap is.
1781 # experimental as long as format.use-persistent-nodemap is.
1777 coreconfigitem(
1782 coreconfigitem(
1778 b'storage',
1783 b'storage',
1779 b'revlog.persistent-nodemap.slow-path',
1784 b'revlog.persistent-nodemap.slow-path',
1780 default=b"abort",
1785 default=b"abort",
1781 )
1786 )
1782
1787
1783 coreconfigitem(
1788 coreconfigitem(
1784 b'storage',
1789 b'storage',
1785 b'revlog.reuse-external-delta',
1790 b'revlog.reuse-external-delta',
1786 default=True,
1791 default=True,
1787 )
1792 )
1788 coreconfigitem(
1793 coreconfigitem(
1789 b'storage',
1794 b'storage',
1790 b'revlog.reuse-external-delta-parent',
1795 b'revlog.reuse-external-delta-parent',
1791 default=None,
1796 default=None,
1792 )
1797 )
1793 coreconfigitem(
1798 coreconfigitem(
1794 b'storage',
1799 b'storage',
1795 b'revlog.zlib.level',
1800 b'revlog.zlib.level',
1796 default=None,
1801 default=None,
1797 )
1802 )
1798 coreconfigitem(
1803 coreconfigitem(
1799 b'storage',
1804 b'storage',
1800 b'revlog.zstd.level',
1805 b'revlog.zstd.level',
1801 default=None,
1806 default=None,
1802 )
1807 )
1803 coreconfigitem(
1808 coreconfigitem(
1804 b'server',
1809 b'server',
1805 b'bookmarks-pushkey-compat',
1810 b'bookmarks-pushkey-compat',
1806 default=True,
1811 default=True,
1807 )
1812 )
1808 coreconfigitem(
1813 coreconfigitem(
1809 b'server',
1814 b'server',
1810 b'bundle1',
1815 b'bundle1',
1811 default=True,
1816 default=True,
1812 )
1817 )
1813 coreconfigitem(
1818 coreconfigitem(
1814 b'server',
1819 b'server',
1815 b'bundle1gd',
1820 b'bundle1gd',
1816 default=None,
1821 default=None,
1817 )
1822 )
1818 coreconfigitem(
1823 coreconfigitem(
1819 b'server',
1824 b'server',
1820 b'bundle1.pull',
1825 b'bundle1.pull',
1821 default=None,
1826 default=None,
1822 )
1827 )
1823 coreconfigitem(
1828 coreconfigitem(
1824 b'server',
1829 b'server',
1825 b'bundle1gd.pull',
1830 b'bundle1gd.pull',
1826 default=None,
1831 default=None,
1827 )
1832 )
1828 coreconfigitem(
1833 coreconfigitem(
1829 b'server',
1834 b'server',
1830 b'bundle1.push',
1835 b'bundle1.push',
1831 default=None,
1836 default=None,
1832 )
1837 )
1833 coreconfigitem(
1838 coreconfigitem(
1834 b'server',
1839 b'server',
1835 b'bundle1gd.push',
1840 b'bundle1gd.push',
1836 default=None,
1841 default=None,
1837 )
1842 )
1838 coreconfigitem(
1843 coreconfigitem(
1839 b'server',
1844 b'server',
1840 b'bundle2.stream',
1845 b'bundle2.stream',
1841 default=True,
1846 default=True,
1842 alias=[(b'experimental', b'bundle2.stream')],
1847 alias=[(b'experimental', b'bundle2.stream')],
1843 )
1848 )
1844 coreconfigitem(
1849 coreconfigitem(
1845 b'server',
1850 b'server',
1846 b'compressionengines',
1851 b'compressionengines',
1847 default=list,
1852 default=list,
1848 )
1853 )
1849 coreconfigitem(
1854 coreconfigitem(
1850 b'server',
1855 b'server',
1851 b'concurrent-push-mode',
1856 b'concurrent-push-mode',
1852 default=b'check-related',
1857 default=b'check-related',
1853 )
1858 )
1854 coreconfigitem(
1859 coreconfigitem(
1855 b'server',
1860 b'server',
1856 b'disablefullbundle',
1861 b'disablefullbundle',
1857 default=False,
1862 default=False,
1858 )
1863 )
1859 coreconfigitem(
1864 coreconfigitem(
1860 b'server',
1865 b'server',
1861 b'maxhttpheaderlen',
1866 b'maxhttpheaderlen',
1862 default=1024,
1867 default=1024,
1863 )
1868 )
1864 coreconfigitem(
1869 coreconfigitem(
1865 b'server',
1870 b'server',
1866 b'pullbundle',
1871 b'pullbundle',
1867 default=False,
1872 default=False,
1868 )
1873 )
1869 coreconfigitem(
1874 coreconfigitem(
1870 b'server',
1875 b'server',
1871 b'preferuncompressed',
1876 b'preferuncompressed',
1872 default=False,
1877 default=False,
1873 )
1878 )
1874 coreconfigitem(
1879 coreconfigitem(
1875 b'server',
1880 b'server',
1876 b'streamunbundle',
1881 b'streamunbundle',
1877 default=False,
1882 default=False,
1878 )
1883 )
1879 coreconfigitem(
1884 coreconfigitem(
1880 b'server',
1885 b'server',
1881 b'uncompressed',
1886 b'uncompressed',
1882 default=True,
1887 default=True,
1883 )
1888 )
1884 coreconfigitem(
1889 coreconfigitem(
1885 b'server',
1890 b'server',
1886 b'uncompressedallowsecret',
1891 b'uncompressedallowsecret',
1887 default=False,
1892 default=False,
1888 )
1893 )
1889 coreconfigitem(
1894 coreconfigitem(
1890 b'server',
1895 b'server',
1891 b'view',
1896 b'view',
1892 default=b'served',
1897 default=b'served',
1893 )
1898 )
1894 coreconfigitem(
1899 coreconfigitem(
1895 b'server',
1900 b'server',
1896 b'validate',
1901 b'validate',
1897 default=False,
1902 default=False,
1898 )
1903 )
1899 coreconfigitem(
1904 coreconfigitem(
1900 b'server',
1905 b'server',
1901 b'zliblevel',
1906 b'zliblevel',
1902 default=-1,
1907 default=-1,
1903 )
1908 )
1904 coreconfigitem(
1909 coreconfigitem(
1905 b'server',
1910 b'server',
1906 b'zstdlevel',
1911 b'zstdlevel',
1907 default=3,
1912 default=3,
1908 )
1913 )
1909 coreconfigitem(
1914 coreconfigitem(
1910 b'share',
1915 b'share',
1911 b'pool',
1916 b'pool',
1912 default=None,
1917 default=None,
1913 )
1918 )
1914 coreconfigitem(
1919 coreconfigitem(
1915 b'share',
1920 b'share',
1916 b'poolnaming',
1921 b'poolnaming',
1917 default=b'identity',
1922 default=b'identity',
1918 )
1923 )
1919 coreconfigitem(
1924 coreconfigitem(
1920 b'share',
1925 b'share',
1921 b'safe-mismatch.source-not-safe',
1926 b'safe-mismatch.source-not-safe',
1922 default=b'abort',
1927 default=b'abort',
1923 )
1928 )
1924 coreconfigitem(
1929 coreconfigitem(
1925 b'share',
1930 b'share',
1926 b'safe-mismatch.source-safe',
1931 b'safe-mismatch.source-safe',
1927 default=b'abort',
1932 default=b'abort',
1928 )
1933 )
1929 coreconfigitem(
1934 coreconfigitem(
1930 b'share',
1935 b'share',
1931 b'safe-mismatch.source-not-safe.warn',
1936 b'safe-mismatch.source-not-safe.warn',
1932 default=True,
1937 default=True,
1933 )
1938 )
1934 coreconfigitem(
1939 coreconfigitem(
1935 b'share',
1940 b'share',
1936 b'safe-mismatch.source-safe.warn',
1941 b'safe-mismatch.source-safe.warn',
1937 default=True,
1942 default=True,
1938 )
1943 )
1939 coreconfigitem(
1944 coreconfigitem(
1940 b'shelve',
1945 b'shelve',
1941 b'maxbackups',
1946 b'maxbackups',
1942 default=10,
1947 default=10,
1943 )
1948 )
1944 coreconfigitem(
1949 coreconfigitem(
1945 b'smtp',
1950 b'smtp',
1946 b'host',
1951 b'host',
1947 default=None,
1952 default=None,
1948 )
1953 )
1949 coreconfigitem(
1954 coreconfigitem(
1950 b'smtp',
1955 b'smtp',
1951 b'local_hostname',
1956 b'local_hostname',
1952 default=None,
1957 default=None,
1953 )
1958 )
1954 coreconfigitem(
1959 coreconfigitem(
1955 b'smtp',
1960 b'smtp',
1956 b'password',
1961 b'password',
1957 default=None,
1962 default=None,
1958 )
1963 )
1959 coreconfigitem(
1964 coreconfigitem(
1960 b'smtp',
1965 b'smtp',
1961 b'port',
1966 b'port',
1962 default=dynamicdefault,
1967 default=dynamicdefault,
1963 )
1968 )
1964 coreconfigitem(
1969 coreconfigitem(
1965 b'smtp',
1970 b'smtp',
1966 b'tls',
1971 b'tls',
1967 default=b'none',
1972 default=b'none',
1968 )
1973 )
1969 coreconfigitem(
1974 coreconfigitem(
1970 b'smtp',
1975 b'smtp',
1971 b'username',
1976 b'username',
1972 default=None,
1977 default=None,
1973 )
1978 )
1974 coreconfigitem(
1979 coreconfigitem(
1975 b'sparse',
1980 b'sparse',
1976 b'missingwarning',
1981 b'missingwarning',
1977 default=True,
1982 default=True,
1978 experimental=True,
1983 experimental=True,
1979 )
1984 )
1980 coreconfigitem(
1985 coreconfigitem(
1981 b'subrepos',
1986 b'subrepos',
1982 b'allowed',
1987 b'allowed',
1983 default=dynamicdefault, # to make backporting simpler
1988 default=dynamicdefault, # to make backporting simpler
1984 )
1989 )
1985 coreconfigitem(
1990 coreconfigitem(
1986 b'subrepos',
1991 b'subrepos',
1987 b'hg:allowed',
1992 b'hg:allowed',
1988 default=dynamicdefault,
1993 default=dynamicdefault,
1989 )
1994 )
1990 coreconfigitem(
1995 coreconfigitem(
1991 b'subrepos',
1996 b'subrepos',
1992 b'git:allowed',
1997 b'git:allowed',
1993 default=dynamicdefault,
1998 default=dynamicdefault,
1994 )
1999 )
1995 coreconfigitem(
2000 coreconfigitem(
1996 b'subrepos',
2001 b'subrepos',
1997 b'svn:allowed',
2002 b'svn:allowed',
1998 default=dynamicdefault,
2003 default=dynamicdefault,
1999 )
2004 )
2000 coreconfigitem(
2005 coreconfigitem(
2001 b'templates',
2006 b'templates',
2002 b'.*',
2007 b'.*',
2003 default=None,
2008 default=None,
2004 generic=True,
2009 generic=True,
2005 )
2010 )
2006 coreconfigitem(
2011 coreconfigitem(
2007 b'templateconfig',
2012 b'templateconfig',
2008 b'.*',
2013 b'.*',
2009 default=dynamicdefault,
2014 default=dynamicdefault,
2010 generic=True,
2015 generic=True,
2011 )
2016 )
2012 coreconfigitem(
2017 coreconfigitem(
2013 b'trusted',
2018 b'trusted',
2014 b'groups',
2019 b'groups',
2015 default=list,
2020 default=list,
2016 )
2021 )
2017 coreconfigitem(
2022 coreconfigitem(
2018 b'trusted',
2023 b'trusted',
2019 b'users',
2024 b'users',
2020 default=list,
2025 default=list,
2021 )
2026 )
2022 coreconfigitem(
2027 coreconfigitem(
2023 b'ui',
2028 b'ui',
2024 b'_usedassubrepo',
2029 b'_usedassubrepo',
2025 default=False,
2030 default=False,
2026 )
2031 )
2027 coreconfigitem(
2032 coreconfigitem(
2028 b'ui',
2033 b'ui',
2029 b'allowemptycommit',
2034 b'allowemptycommit',
2030 default=False,
2035 default=False,
2031 )
2036 )
2032 coreconfigitem(
2037 coreconfigitem(
2033 b'ui',
2038 b'ui',
2034 b'archivemeta',
2039 b'archivemeta',
2035 default=True,
2040 default=True,
2036 )
2041 )
2037 coreconfigitem(
2042 coreconfigitem(
2038 b'ui',
2043 b'ui',
2039 b'askusername',
2044 b'askusername',
2040 default=False,
2045 default=False,
2041 )
2046 )
2042 coreconfigitem(
2047 coreconfigitem(
2043 b'ui',
2048 b'ui',
2044 b'available-memory',
2049 b'available-memory',
2045 default=None,
2050 default=None,
2046 )
2051 )
2047
2052
2048 coreconfigitem(
2053 coreconfigitem(
2049 b'ui',
2054 b'ui',
2050 b'clonebundlefallback',
2055 b'clonebundlefallback',
2051 default=False,
2056 default=False,
2052 )
2057 )
2053 coreconfigitem(
2058 coreconfigitem(
2054 b'ui',
2059 b'ui',
2055 b'clonebundleprefers',
2060 b'clonebundleprefers',
2056 default=list,
2061 default=list,
2057 )
2062 )
2058 coreconfigitem(
2063 coreconfigitem(
2059 b'ui',
2064 b'ui',
2060 b'clonebundles',
2065 b'clonebundles',
2061 default=True,
2066 default=True,
2062 )
2067 )
2063 coreconfigitem(
2068 coreconfigitem(
2064 b'ui',
2069 b'ui',
2065 b'color',
2070 b'color',
2066 default=b'auto',
2071 default=b'auto',
2067 )
2072 )
2068 coreconfigitem(
2073 coreconfigitem(
2069 b'ui',
2074 b'ui',
2070 b'commitsubrepos',
2075 b'commitsubrepos',
2071 default=False,
2076 default=False,
2072 )
2077 )
2073 coreconfigitem(
2078 coreconfigitem(
2074 b'ui',
2079 b'ui',
2075 b'debug',
2080 b'debug',
2076 default=False,
2081 default=False,
2077 )
2082 )
2078 coreconfigitem(
2083 coreconfigitem(
2079 b'ui',
2084 b'ui',
2080 b'debugger',
2085 b'debugger',
2081 default=None,
2086 default=None,
2082 )
2087 )
2083 coreconfigitem(
2088 coreconfigitem(
2084 b'ui',
2089 b'ui',
2085 b'editor',
2090 b'editor',
2086 default=dynamicdefault,
2091 default=dynamicdefault,
2087 )
2092 )
2088 coreconfigitem(
2093 coreconfigitem(
2089 b'ui',
2094 b'ui',
2090 b'detailed-exit-code',
2095 b'detailed-exit-code',
2091 default=False,
2096 default=False,
2092 experimental=True,
2097 experimental=True,
2093 )
2098 )
2094 coreconfigitem(
2099 coreconfigitem(
2095 b'ui',
2100 b'ui',
2096 b'fallbackencoding',
2101 b'fallbackencoding',
2097 default=None,
2102 default=None,
2098 )
2103 )
2099 coreconfigitem(
2104 coreconfigitem(
2100 b'ui',
2105 b'ui',
2101 b'forcecwd',
2106 b'forcecwd',
2102 default=None,
2107 default=None,
2103 )
2108 )
2104 coreconfigitem(
2109 coreconfigitem(
2105 b'ui',
2110 b'ui',
2106 b'forcemerge',
2111 b'forcemerge',
2107 default=None,
2112 default=None,
2108 )
2113 )
2109 coreconfigitem(
2114 coreconfigitem(
2110 b'ui',
2115 b'ui',
2111 b'formatdebug',
2116 b'formatdebug',
2112 default=False,
2117 default=False,
2113 )
2118 )
2114 coreconfigitem(
2119 coreconfigitem(
2115 b'ui',
2120 b'ui',
2116 b'formatjson',
2121 b'formatjson',
2117 default=False,
2122 default=False,
2118 )
2123 )
2119 coreconfigitem(
2124 coreconfigitem(
2120 b'ui',
2125 b'ui',
2121 b'formatted',
2126 b'formatted',
2122 default=None,
2127 default=None,
2123 )
2128 )
2124 coreconfigitem(
2129 coreconfigitem(
2125 b'ui',
2130 b'ui',
2126 b'interactive',
2131 b'interactive',
2127 default=None,
2132 default=None,
2128 )
2133 )
2129 coreconfigitem(
2134 coreconfigitem(
2130 b'ui',
2135 b'ui',
2131 b'interface',
2136 b'interface',
2132 default=None,
2137 default=None,
2133 )
2138 )
2134 coreconfigitem(
2139 coreconfigitem(
2135 b'ui',
2140 b'ui',
2136 b'interface.chunkselector',
2141 b'interface.chunkselector',
2137 default=None,
2142 default=None,
2138 )
2143 )
2139 coreconfigitem(
2144 coreconfigitem(
2140 b'ui',
2145 b'ui',
2141 b'large-file-limit',
2146 b'large-file-limit',
2142 default=10000000,
2147 default=10000000,
2143 )
2148 )
2144 coreconfigitem(
2149 coreconfigitem(
2145 b'ui',
2150 b'ui',
2146 b'logblockedtimes',
2151 b'logblockedtimes',
2147 default=False,
2152 default=False,
2148 )
2153 )
2149 coreconfigitem(
2154 coreconfigitem(
2150 b'ui',
2155 b'ui',
2151 b'merge',
2156 b'merge',
2152 default=None,
2157 default=None,
2153 )
2158 )
2154 coreconfigitem(
2159 coreconfigitem(
2155 b'ui',
2160 b'ui',
2156 b'mergemarkers',
2161 b'mergemarkers',
2157 default=b'basic',
2162 default=b'basic',
2158 )
2163 )
2159 coreconfigitem(
2164 coreconfigitem(
2160 b'ui',
2165 b'ui',
2161 b'message-output',
2166 b'message-output',
2162 default=b'stdio',
2167 default=b'stdio',
2163 )
2168 )
2164 coreconfigitem(
2169 coreconfigitem(
2165 b'ui',
2170 b'ui',
2166 b'nontty',
2171 b'nontty',
2167 default=False,
2172 default=False,
2168 )
2173 )
2169 coreconfigitem(
2174 coreconfigitem(
2170 b'ui',
2175 b'ui',
2171 b'origbackuppath',
2176 b'origbackuppath',
2172 default=None,
2177 default=None,
2173 )
2178 )
2174 coreconfigitem(
2179 coreconfigitem(
2175 b'ui',
2180 b'ui',
2176 b'paginate',
2181 b'paginate',
2177 default=True,
2182 default=True,
2178 )
2183 )
2179 coreconfigitem(
2184 coreconfigitem(
2180 b'ui',
2185 b'ui',
2181 b'patch',
2186 b'patch',
2182 default=None,
2187 default=None,
2183 )
2188 )
2184 coreconfigitem(
2189 coreconfigitem(
2185 b'ui',
2190 b'ui',
2186 b'portablefilenames',
2191 b'portablefilenames',
2187 default=b'warn',
2192 default=b'warn',
2188 )
2193 )
2189 coreconfigitem(
2194 coreconfigitem(
2190 b'ui',
2195 b'ui',
2191 b'promptecho',
2196 b'promptecho',
2192 default=False,
2197 default=False,
2193 )
2198 )
2194 coreconfigitem(
2199 coreconfigitem(
2195 b'ui',
2200 b'ui',
2196 b'quiet',
2201 b'quiet',
2197 default=False,
2202 default=False,
2198 )
2203 )
2199 coreconfigitem(
2204 coreconfigitem(
2200 b'ui',
2205 b'ui',
2201 b'quietbookmarkmove',
2206 b'quietbookmarkmove',
2202 default=False,
2207 default=False,
2203 )
2208 )
2204 coreconfigitem(
2209 coreconfigitem(
2205 b'ui',
2210 b'ui',
2206 b'relative-paths',
2211 b'relative-paths',
2207 default=b'legacy',
2212 default=b'legacy',
2208 )
2213 )
2209 coreconfigitem(
2214 coreconfigitem(
2210 b'ui',
2215 b'ui',
2211 b'remotecmd',
2216 b'remotecmd',
2212 default=b'hg',
2217 default=b'hg',
2213 )
2218 )
2214 coreconfigitem(
2219 coreconfigitem(
2215 b'ui',
2220 b'ui',
2216 b'report_untrusted',
2221 b'report_untrusted',
2217 default=True,
2222 default=True,
2218 )
2223 )
2219 coreconfigitem(
2224 coreconfigitem(
2220 b'ui',
2225 b'ui',
2221 b'rollback',
2226 b'rollback',
2222 default=True,
2227 default=True,
2223 )
2228 )
2224 coreconfigitem(
2229 coreconfigitem(
2225 b'ui',
2230 b'ui',
2226 b'signal-safe-lock',
2231 b'signal-safe-lock',
2227 default=True,
2232 default=True,
2228 )
2233 )
2229 coreconfigitem(
2234 coreconfigitem(
2230 b'ui',
2235 b'ui',
2231 b'slash',
2236 b'slash',
2232 default=False,
2237 default=False,
2233 )
2238 )
2234 coreconfigitem(
2239 coreconfigitem(
2235 b'ui',
2240 b'ui',
2236 b'ssh',
2241 b'ssh',
2237 default=b'ssh',
2242 default=b'ssh',
2238 )
2243 )
2239 coreconfigitem(
2244 coreconfigitem(
2240 b'ui',
2245 b'ui',
2241 b'ssherrorhint',
2246 b'ssherrorhint',
2242 default=None,
2247 default=None,
2243 )
2248 )
2244 coreconfigitem(
2249 coreconfigitem(
2245 b'ui',
2250 b'ui',
2246 b'statuscopies',
2251 b'statuscopies',
2247 default=False,
2252 default=False,
2248 )
2253 )
2249 coreconfigitem(
2254 coreconfigitem(
2250 b'ui',
2255 b'ui',
2251 b'strict',
2256 b'strict',
2252 default=False,
2257 default=False,
2253 )
2258 )
2254 coreconfigitem(
2259 coreconfigitem(
2255 b'ui',
2260 b'ui',
2256 b'style',
2261 b'style',
2257 default=b'',
2262 default=b'',
2258 )
2263 )
2259 coreconfigitem(
2264 coreconfigitem(
2260 b'ui',
2265 b'ui',
2261 b'supportcontact',
2266 b'supportcontact',
2262 default=None,
2267 default=None,
2263 )
2268 )
2264 coreconfigitem(
2269 coreconfigitem(
2265 b'ui',
2270 b'ui',
2266 b'textwidth',
2271 b'textwidth',
2267 default=78,
2272 default=78,
2268 )
2273 )
2269 coreconfigitem(
2274 coreconfigitem(
2270 b'ui',
2275 b'ui',
2271 b'timeout',
2276 b'timeout',
2272 default=b'600',
2277 default=b'600',
2273 )
2278 )
2274 coreconfigitem(
2279 coreconfigitem(
2275 b'ui',
2280 b'ui',
2276 b'timeout.warn',
2281 b'timeout.warn',
2277 default=0,
2282 default=0,
2278 )
2283 )
2279 coreconfigitem(
2284 coreconfigitem(
2280 b'ui',
2285 b'ui',
2281 b'timestamp-output',
2286 b'timestamp-output',
2282 default=False,
2287 default=False,
2283 )
2288 )
2284 coreconfigitem(
2289 coreconfigitem(
2285 b'ui',
2290 b'ui',
2286 b'traceback',
2291 b'traceback',
2287 default=False,
2292 default=False,
2288 )
2293 )
2289 coreconfigitem(
2294 coreconfigitem(
2290 b'ui',
2295 b'ui',
2291 b'tweakdefaults',
2296 b'tweakdefaults',
2292 default=False,
2297 default=False,
2293 )
2298 )
2294 coreconfigitem(b'ui', b'username', alias=[(b'ui', b'user')])
2299 coreconfigitem(b'ui', b'username', alias=[(b'ui', b'user')])
2295 coreconfigitem(
2300 coreconfigitem(
2296 b'ui',
2301 b'ui',
2297 b'verbose',
2302 b'verbose',
2298 default=False,
2303 default=False,
2299 )
2304 )
2300 coreconfigitem(
2305 coreconfigitem(
2301 b'verify',
2306 b'verify',
2302 b'skipflags',
2307 b'skipflags',
2303 default=None,
2308 default=None,
2304 )
2309 )
2305 coreconfigitem(
2310 coreconfigitem(
2306 b'web',
2311 b'web',
2307 b'allowbz2',
2312 b'allowbz2',
2308 default=False,
2313 default=False,
2309 )
2314 )
2310 coreconfigitem(
2315 coreconfigitem(
2311 b'web',
2316 b'web',
2312 b'allowgz',
2317 b'allowgz',
2313 default=False,
2318 default=False,
2314 )
2319 )
2315 coreconfigitem(
2320 coreconfigitem(
2316 b'web',
2321 b'web',
2317 b'allow-pull',
2322 b'allow-pull',
2318 alias=[(b'web', b'allowpull')],
2323 alias=[(b'web', b'allowpull')],
2319 default=True,
2324 default=True,
2320 )
2325 )
2321 coreconfigitem(
2326 coreconfigitem(
2322 b'web',
2327 b'web',
2323 b'allow-push',
2328 b'allow-push',
2324 alias=[(b'web', b'allow_push')],
2329 alias=[(b'web', b'allow_push')],
2325 default=list,
2330 default=list,
2326 )
2331 )
2327 coreconfigitem(
2332 coreconfigitem(
2328 b'web',
2333 b'web',
2329 b'allowzip',
2334 b'allowzip',
2330 default=False,
2335 default=False,
2331 )
2336 )
2332 coreconfigitem(
2337 coreconfigitem(
2333 b'web',
2338 b'web',
2334 b'archivesubrepos',
2339 b'archivesubrepos',
2335 default=False,
2340 default=False,
2336 )
2341 )
2337 coreconfigitem(
2342 coreconfigitem(
2338 b'web',
2343 b'web',
2339 b'cache',
2344 b'cache',
2340 default=True,
2345 default=True,
2341 )
2346 )
2342 coreconfigitem(
2347 coreconfigitem(
2343 b'web',
2348 b'web',
2344 b'comparisoncontext',
2349 b'comparisoncontext',
2345 default=5,
2350 default=5,
2346 )
2351 )
2347 coreconfigitem(
2352 coreconfigitem(
2348 b'web',
2353 b'web',
2349 b'contact',
2354 b'contact',
2350 default=None,
2355 default=None,
2351 )
2356 )
2352 coreconfigitem(
2357 coreconfigitem(
2353 b'web',
2358 b'web',
2354 b'deny_push',
2359 b'deny_push',
2355 default=list,
2360 default=list,
2356 )
2361 )
2357 coreconfigitem(
2362 coreconfigitem(
2358 b'web',
2363 b'web',
2359 b'guessmime',
2364 b'guessmime',
2360 default=False,
2365 default=False,
2361 )
2366 )
2362 coreconfigitem(
2367 coreconfigitem(
2363 b'web',
2368 b'web',
2364 b'hidden',
2369 b'hidden',
2365 default=False,
2370 default=False,
2366 )
2371 )
2367 coreconfigitem(
2372 coreconfigitem(
2368 b'web',
2373 b'web',
2369 b'labels',
2374 b'labels',
2370 default=list,
2375 default=list,
2371 )
2376 )
2372 coreconfigitem(
2377 coreconfigitem(
2373 b'web',
2378 b'web',
2374 b'logoimg',
2379 b'logoimg',
2375 default=b'hglogo.png',
2380 default=b'hglogo.png',
2376 )
2381 )
2377 coreconfigitem(
2382 coreconfigitem(
2378 b'web',
2383 b'web',
2379 b'logourl',
2384 b'logourl',
2380 default=b'https://mercurial-scm.org/',
2385 default=b'https://mercurial-scm.org/',
2381 )
2386 )
2382 coreconfigitem(
2387 coreconfigitem(
2383 b'web',
2388 b'web',
2384 b'accesslog',
2389 b'accesslog',
2385 default=b'-',
2390 default=b'-',
2386 )
2391 )
2387 coreconfigitem(
2392 coreconfigitem(
2388 b'web',
2393 b'web',
2389 b'address',
2394 b'address',
2390 default=b'',
2395 default=b'',
2391 )
2396 )
2392 coreconfigitem(
2397 coreconfigitem(
2393 b'web',
2398 b'web',
2394 b'allow-archive',
2399 b'allow-archive',
2395 alias=[(b'web', b'allow_archive')],
2400 alias=[(b'web', b'allow_archive')],
2396 default=list,
2401 default=list,
2397 )
2402 )
2398 coreconfigitem(
2403 coreconfigitem(
2399 b'web',
2404 b'web',
2400 b'allow_read',
2405 b'allow_read',
2401 default=list,
2406 default=list,
2402 )
2407 )
2403 coreconfigitem(
2408 coreconfigitem(
2404 b'web',
2409 b'web',
2405 b'baseurl',
2410 b'baseurl',
2406 default=None,
2411 default=None,
2407 )
2412 )
2408 coreconfigitem(
2413 coreconfigitem(
2409 b'web',
2414 b'web',
2410 b'cacerts',
2415 b'cacerts',
2411 default=None,
2416 default=None,
2412 )
2417 )
2413 coreconfigitem(
2418 coreconfigitem(
2414 b'web',
2419 b'web',
2415 b'certificate',
2420 b'certificate',
2416 default=None,
2421 default=None,
2417 )
2422 )
2418 coreconfigitem(
2423 coreconfigitem(
2419 b'web',
2424 b'web',
2420 b'collapse',
2425 b'collapse',
2421 default=False,
2426 default=False,
2422 )
2427 )
2423 coreconfigitem(
2428 coreconfigitem(
2424 b'web',
2429 b'web',
2425 b'csp',
2430 b'csp',
2426 default=None,
2431 default=None,
2427 )
2432 )
2428 coreconfigitem(
2433 coreconfigitem(
2429 b'web',
2434 b'web',
2430 b'deny_read',
2435 b'deny_read',
2431 default=list,
2436 default=list,
2432 )
2437 )
2433 coreconfigitem(
2438 coreconfigitem(
2434 b'web',
2439 b'web',
2435 b'descend',
2440 b'descend',
2436 default=True,
2441 default=True,
2437 )
2442 )
2438 coreconfigitem(
2443 coreconfigitem(
2439 b'web',
2444 b'web',
2440 b'description',
2445 b'description',
2441 default=b"",
2446 default=b"",
2442 )
2447 )
2443 coreconfigitem(
2448 coreconfigitem(
2444 b'web',
2449 b'web',
2445 b'encoding',
2450 b'encoding',
2446 default=lambda: encoding.encoding,
2451 default=lambda: encoding.encoding,
2447 )
2452 )
2448 coreconfigitem(
2453 coreconfigitem(
2449 b'web',
2454 b'web',
2450 b'errorlog',
2455 b'errorlog',
2451 default=b'-',
2456 default=b'-',
2452 )
2457 )
2453 coreconfigitem(
2458 coreconfigitem(
2454 b'web',
2459 b'web',
2455 b'ipv6',
2460 b'ipv6',
2456 default=False,
2461 default=False,
2457 )
2462 )
2458 coreconfigitem(
2463 coreconfigitem(
2459 b'web',
2464 b'web',
2460 b'maxchanges',
2465 b'maxchanges',
2461 default=10,
2466 default=10,
2462 )
2467 )
2463 coreconfigitem(
2468 coreconfigitem(
2464 b'web',
2469 b'web',
2465 b'maxfiles',
2470 b'maxfiles',
2466 default=10,
2471 default=10,
2467 )
2472 )
2468 coreconfigitem(
2473 coreconfigitem(
2469 b'web',
2474 b'web',
2470 b'maxshortchanges',
2475 b'maxshortchanges',
2471 default=60,
2476 default=60,
2472 )
2477 )
2473 coreconfigitem(
2478 coreconfigitem(
2474 b'web',
2479 b'web',
2475 b'motd',
2480 b'motd',
2476 default=b'',
2481 default=b'',
2477 )
2482 )
2478 coreconfigitem(
2483 coreconfigitem(
2479 b'web',
2484 b'web',
2480 b'name',
2485 b'name',
2481 default=dynamicdefault,
2486 default=dynamicdefault,
2482 )
2487 )
2483 coreconfigitem(
2488 coreconfigitem(
2484 b'web',
2489 b'web',
2485 b'port',
2490 b'port',
2486 default=8000,
2491 default=8000,
2487 )
2492 )
2488 coreconfigitem(
2493 coreconfigitem(
2489 b'web',
2494 b'web',
2490 b'prefix',
2495 b'prefix',
2491 default=b'',
2496 default=b'',
2492 )
2497 )
2493 coreconfigitem(
2498 coreconfigitem(
2494 b'web',
2499 b'web',
2495 b'push_ssl',
2500 b'push_ssl',
2496 default=True,
2501 default=True,
2497 )
2502 )
2498 coreconfigitem(
2503 coreconfigitem(
2499 b'web',
2504 b'web',
2500 b'refreshinterval',
2505 b'refreshinterval',
2501 default=20,
2506 default=20,
2502 )
2507 )
2503 coreconfigitem(
2508 coreconfigitem(
2504 b'web',
2509 b'web',
2505 b'server-header',
2510 b'server-header',
2506 default=None,
2511 default=None,
2507 )
2512 )
2508 coreconfigitem(
2513 coreconfigitem(
2509 b'web',
2514 b'web',
2510 b'static',
2515 b'static',
2511 default=None,
2516 default=None,
2512 )
2517 )
2513 coreconfigitem(
2518 coreconfigitem(
2514 b'web',
2519 b'web',
2515 b'staticurl',
2520 b'staticurl',
2516 default=None,
2521 default=None,
2517 )
2522 )
2518 coreconfigitem(
2523 coreconfigitem(
2519 b'web',
2524 b'web',
2520 b'stripes',
2525 b'stripes',
2521 default=1,
2526 default=1,
2522 )
2527 )
2523 coreconfigitem(
2528 coreconfigitem(
2524 b'web',
2529 b'web',
2525 b'style',
2530 b'style',
2526 default=b'paper',
2531 default=b'paper',
2527 )
2532 )
2528 coreconfigitem(
2533 coreconfigitem(
2529 b'web',
2534 b'web',
2530 b'templates',
2535 b'templates',
2531 default=None,
2536 default=None,
2532 )
2537 )
2533 coreconfigitem(
2538 coreconfigitem(
2534 b'web',
2539 b'web',
2535 b'view',
2540 b'view',
2536 default=b'served',
2541 default=b'served',
2537 experimental=True,
2542 experimental=True,
2538 )
2543 )
2539 coreconfigitem(
2544 coreconfigitem(
2540 b'worker',
2545 b'worker',
2541 b'backgroundclose',
2546 b'backgroundclose',
2542 default=dynamicdefault,
2547 default=dynamicdefault,
2543 )
2548 )
2544 # Windows defaults to a limit of 512 open files. A buffer of 128
2549 # Windows defaults to a limit of 512 open files. A buffer of 128
2545 # should give us enough headway.
2550 # should give us enough headway.
2546 coreconfigitem(
2551 coreconfigitem(
2547 b'worker',
2552 b'worker',
2548 b'backgroundclosemaxqueue',
2553 b'backgroundclosemaxqueue',
2549 default=384,
2554 default=384,
2550 )
2555 )
2551 coreconfigitem(
2556 coreconfigitem(
2552 b'worker',
2557 b'worker',
2553 b'backgroundcloseminfilecount',
2558 b'backgroundcloseminfilecount',
2554 default=2048,
2559 default=2048,
2555 )
2560 )
2556 coreconfigitem(
2561 coreconfigitem(
2557 b'worker',
2562 b'worker',
2558 b'backgroundclosethreadcount',
2563 b'backgroundclosethreadcount',
2559 default=4,
2564 default=4,
2560 )
2565 )
2561 coreconfigitem(
2566 coreconfigitem(
2562 b'worker',
2567 b'worker',
2563 b'enabled',
2568 b'enabled',
2564 default=True,
2569 default=True,
2565 )
2570 )
2566 coreconfigitem(
2571 coreconfigitem(
2567 b'worker',
2572 b'worker',
2568 b'numcpus',
2573 b'numcpus',
2569 default=None,
2574 default=None,
2570 )
2575 )
2571
2576
2572 # Rebase related configuration moved to core because other extension are doing
2577 # Rebase related configuration moved to core because other extension are doing
2573 # strange things. For example, shelve import the extensions to reuse some bit
2578 # strange things. For example, shelve import the extensions to reuse some bit
2574 # without formally loading it.
2579 # without formally loading it.
2575 coreconfigitem(
2580 coreconfigitem(
2576 b'commands',
2581 b'commands',
2577 b'rebase.requiredest',
2582 b'rebase.requiredest',
2578 default=False,
2583 default=False,
2579 )
2584 )
2580 coreconfigitem(
2585 coreconfigitem(
2581 b'experimental',
2586 b'experimental',
2582 b'rebaseskipobsolete',
2587 b'rebaseskipobsolete',
2583 default=True,
2588 default=True,
2584 )
2589 )
2585 coreconfigitem(
2590 coreconfigitem(
2586 b'rebase',
2591 b'rebase',
2587 b'singletransaction',
2592 b'singletransaction',
2588 default=False,
2593 default=False,
2589 )
2594 )
2590 coreconfigitem(
2595 coreconfigitem(
2591 b'rebase',
2596 b'rebase',
2592 b'experimental.inmemory',
2597 b'experimental.inmemory',
2593 default=False,
2598 default=False,
2594 )
2599 )
@@ -1,58 +1,59 b''
1 # Read the output of a "svn log --xml" command on stdin, parse it and
1 # Read the output of a "svn log --xml" command on stdin, parse it and
2 # print a subset of attributes common to all svn versions tested by
2 # print a subset of attributes common to all svn versions tested by
3 # hg.
3 # hg.
4 from __future__ import absolute_import
4 from __future__ import absolute_import
5 import sys
5 import sys
6 import xml.dom.minidom
6 import xml.dom.minidom
7
7
8
8
9 def xmltext(e):
9 def xmltext(e):
10 return ''.join(c.data for c in e.childNodes if c.nodeType == c.TEXT_NODE)
10 return ''.join(c.data for c in e.childNodes if c.nodeType == c.TEXT_NODE)
11
11
12
12
13 def parseentry(entry):
13 def parseentry(entry):
14 e = {}
14 e = {}
15 e['revision'] = entry.getAttribute('revision')
15 e['revision'] = entry.getAttribute('revision')
16 e['author'] = xmltext(entry.getElementsByTagName('author')[0])
16 e['author'] = xmltext(entry.getElementsByTagName('author')[0])
17 e['msg'] = xmltext(entry.getElementsByTagName('msg')[0])
17 e['msg'] = xmltext(entry.getElementsByTagName('msg')[0])
18 e['date'] = xmltext(entry.getElementsByTagName('date')[0])
18 e['paths'] = []
19 e['paths'] = []
19 paths = entry.getElementsByTagName('paths')
20 paths = entry.getElementsByTagName('paths')
20 if paths:
21 if paths:
21 paths = paths[0]
22 paths = paths[0]
22 for p in paths.getElementsByTagName('path'):
23 for p in paths.getElementsByTagName('path'):
23 action = p.getAttribute('action').encode('utf-8')
24 action = p.getAttribute('action').encode('utf-8')
24 path = xmltext(p).encode('utf-8')
25 path = xmltext(p).encode('utf-8')
25 frompath = p.getAttribute('copyfrom-path').encode('utf-8')
26 frompath = p.getAttribute('copyfrom-path').encode('utf-8')
26 fromrev = p.getAttribute('copyfrom-rev').encode('utf-8')
27 fromrev = p.getAttribute('copyfrom-rev').encode('utf-8')
27 e['paths'].append((path, action, frompath, fromrev))
28 e['paths'].append((path, action, frompath, fromrev))
28 return e
29 return e
29
30
30
31
31 def parselog(data):
32 def parselog(data):
32 entries = []
33 entries = []
33 doc = xml.dom.minidom.parseString(data)
34 doc = xml.dom.minidom.parseString(data)
34 for e in doc.getElementsByTagName('logentry'):
35 for e in doc.getElementsByTagName('logentry'):
35 entries.append(parseentry(e))
36 entries.append(parseentry(e))
36 return entries
37 return entries
37
38
38
39
39 def printentries(entries):
40 def printentries(entries):
40 try:
41 try:
41 fp = sys.stdout.buffer
42 fp = sys.stdout.buffer
42 except AttributeError:
43 except AttributeError:
43 fp = sys.stdout
44 fp = sys.stdout
44 for e in entries:
45 for e in entries:
45 for k in ('revision', 'author', 'msg'):
46 for k in ('revision', 'author', 'date', 'msg'):
46 fp.write(('%s: %s\n' % (k, e[k])).encode('utf-8'))
47 fp.write(('%s: %s\n' % (k, e[k])).encode('utf-8'))
47 for path, action, fpath, frev in sorted(e['paths']):
48 for path, action, fpath, frev in sorted(e['paths']):
48 frominfo = b''
49 frominfo = b''
49 if frev:
50 if frev:
50 frominfo = b' (from %s@%s)' % (fpath, frev)
51 frominfo = b' (from %s@%s)' % (fpath, frev)
51 p = b' %s %s%s\n' % (action, path, frominfo)
52 p = b' %s %s%s\n' % (action, path, frominfo)
52 fp.write(p)
53 fp.write(p)
53
54
54
55
55 if __name__ == '__main__':
56 if __name__ == '__main__':
56 data = sys.stdin.read()
57 data = sys.stdin.read()
57 entries = parselog(data)
58 entries = parselog(data)
58 printentries(entries)
59 printentries(entries)
@@ -1,550 +1,634 b''
1 #require svn13
1 #require svn13
2
2
3 $ svnupanddisplay()
3 $ svnupanddisplay()
4 > {
4 > {
5 > (
5 > (
6 > cd $1;
6 > cd $1;
7 > svn up -q;
7 > svn up -q;
8 > svn st -v | sed 's/ */ /g' | sort
8 > svn st -v | sed 's/ */ /g' | sort
9 > limit=''
9 > limit=''
10 > if [ $2 -gt 0 ]; then
10 > if [ $2 -gt 0 ]; then
11 > limit="--limit=$2"
11 > limit="--limit=$2"
12 > fi
12 > fi
13 > svn log --xml -v $limit | "$PYTHON" "$TESTDIR/svnxml.py"
13 > svn log --xml -v $limit | "$PYTHON" "$TESTDIR/svnxml.py"
14 > )
14 > )
15 > }
15 > }
16
16
17 $ cat >> $HGRCPATH <<EOF
17 $ cat >> $HGRCPATH <<EOF
18 > [extensions]
18 > [extensions]
19 > convert =
19 > convert =
20 > EOF
20 > EOF
21
21
22 $ hg init a
22 $ hg init a
23
23
24 Add
24 Add
25
25
26 $ echo a > a/a
26 $ echo a > a/a
27 $ mkdir -p a/d1/d2
27 $ mkdir -p a/d1/d2
28 $ echo b > a/d1/d2/b
28 $ echo b > a/d1/d2/b
29 $ hg --cwd a ci -d '0 0' -A -m 'add a file'
29 $ hg --cwd a ci -d '0 0' -A -m 'add a file'
30 adding a
30 adding a
31 adding d1/d2/b
31 adding d1/d2/b
32
32
33 Modify
33 Modify
34
34
35 $ svn-safe-append.py a a/a
35 $ svn-safe-append.py a a/a
36 $ hg --cwd a ci -d '1 0' -m 'modify a file'
36 $ hg --cwd a ci -d '1 0' -m 'modify a file'
37 $ hg --cwd a tip -q
37 $ hg --cwd a tip -q
38 1:e0e2b8a9156b
38 1:e0e2b8a9156b
39
39
40 $ hg convert -d svn a
40 $ hg convert -d svn a
41 assuming destination a-hg
41 assuming destination a-hg
42 initializing svn repository 'a-hg'
42 initializing svn repository 'a-hg'
43 initializing svn working copy 'a-hg-wc'
43 initializing svn working copy 'a-hg-wc'
44 scanning source...
44 scanning source...
45 sorting...
45 sorting...
46 converting...
46 converting...
47 1 add a file
47 1 add a file
48 0 modify a file
48 0 modify a file
49 $ svnupanddisplay a-hg-wc 2
49 $ svnupanddisplay a-hg-wc 2
50 2 1 test d1
50 2 1 test d1
51 2 1 test d1/d2
51 2 1 test d1/d2
52 2 1 test d1/d2/b
52 2 1 test d1/d2/b
53 2 2 test .
53 2 2 test .
54 2 2 test a
54 2 2 test a
55 revision: 2
55 revision: 2
56 author: test
56 author: test
57 date: * (glob)
57 msg: modify a file
58 msg: modify a file
58 M /a
59 M /a
59 revision: 1
60 revision: 1
60 author: test
61 author: test
62 date: * (glob)
61 msg: add a file
63 msg: add a file
62 A /a
64 A /a
63 A /d1
65 A /d1
64 A /d1/d2
66 A /d1/d2
65 A /d1/d2/b
67 A /d1/d2/b
66 $ ls a a-hg-wc
68 $ ls a a-hg-wc
67 a:
69 a:
68 a
70 a
69 d1
71 d1
70
72
71 a-hg-wc:
73 a-hg-wc:
72 a
74 a
73 d1
75 d1
74 $ cmp a/a a-hg-wc/a
76 $ cmp a/a a-hg-wc/a
75
77
76 Rename
78 Rename
77
79
78 $ hg --cwd a mv a b
80 $ hg --cwd a mv a b
79 $ hg --cwd a ci -d '2 0' -m 'rename a file'
81 $ hg --cwd a ci -d '2 0' -m 'rename a file'
80 $ hg --cwd a tip -q
82 $ hg --cwd a tip -q
81 2:eb5169441d43
83 2:eb5169441d43
82
84
83 $ hg convert -d svn a
85 $ hg convert -d svn a
84 assuming destination a-hg
86 assuming destination a-hg
85 initializing svn working copy 'a-hg-wc'
87 initializing svn working copy 'a-hg-wc'
86 scanning source...
88 scanning source...
87 sorting...
89 sorting...
88 converting...
90 converting...
89 0 rename a file
91 0 rename a file
90 $ svnupanddisplay a-hg-wc 1
92 $ svnupanddisplay a-hg-wc 1
91 3 1 test d1
93 3 1 test d1
92 3 1 test d1/d2
94 3 1 test d1/d2
93 3 1 test d1/d2/b
95 3 1 test d1/d2/b
94 3 3 test .
96 3 3 test .
95 3 3 test b
97 3 3 test b
96 revision: 3
98 revision: 3
97 author: test
99 author: test
100 date: * (glob)
98 msg: rename a file
101 msg: rename a file
99 D /a
102 D /a
100 A /b (from /a@2)
103 A /b (from /a@2)
101 $ ls a a-hg-wc
104 $ ls a a-hg-wc
102 a:
105 a:
103 b
106 b
104 d1
107 d1
105
108
106 a-hg-wc:
109 a-hg-wc:
107 b
110 b
108 d1
111 d1
109
112
110 Copy
113 Copy
111
114
112 $ hg --cwd a cp b c
115 $ hg --cwd a cp b c
113
116
114 $ hg --cwd a ci -d '3 0' -m 'copy a file'
117 $ hg --cwd a ci -d '3 0' -m 'copy a file'
115 $ hg --cwd a tip -q
118 $ hg --cwd a tip -q
116 3:60effef6ab48
119 3:60effef6ab48
117
120
118 $ hg convert -d svn a
121 $ hg convert -d svn a
119 assuming destination a-hg
122 assuming destination a-hg
120 initializing svn working copy 'a-hg-wc'
123 initializing svn working copy 'a-hg-wc'
121 scanning source...
124 scanning source...
122 sorting...
125 sorting...
123 converting...
126 converting...
124 0 copy a file
127 0 copy a file
125 $ svnupanddisplay a-hg-wc 1
128 $ svnupanddisplay a-hg-wc 1
126 4 1 test d1
129 4 1 test d1
127 4 1 test d1/d2
130 4 1 test d1/d2
128 4 1 test d1/d2/b
131 4 1 test d1/d2/b
129 4 3 test b
132 4 3 test b
130 4 4 test .
133 4 4 test .
131 4 4 test c
134 4 4 test c
132 revision: 4
135 revision: 4
133 author: test
136 author: test
137 date: * (glob)
134 msg: copy a file
138 msg: copy a file
135 A /c (from /b@3)
139 A /c (from /b@3)
136 $ ls a a-hg-wc
140 $ ls a a-hg-wc
137 a:
141 a:
138 b
142 b
139 c
143 c
140 d1
144 d1
141
145
142 a-hg-wc:
146 a-hg-wc:
143 b
147 b
144 c
148 c
145 d1
149 d1
146
150
147 $ hg --cwd a rm b
151 $ hg --cwd a rm b
148
152
149 Remove
153 Remove
150
154
151 $ hg --cwd a ci -d '4 0' -m 'remove a file'
155 $ hg --cwd a ci -d '4 0' -m 'remove a file'
152 $ hg --cwd a tip -q
156 $ hg --cwd a tip -q
153 4:87bbe3013fb6
157 4:87bbe3013fb6
154
158
155 $ hg convert -d svn a
159 $ hg convert -d svn a
156 assuming destination a-hg
160 assuming destination a-hg
157 initializing svn working copy 'a-hg-wc'
161 initializing svn working copy 'a-hg-wc'
158 scanning source...
162 scanning source...
159 sorting...
163 sorting...
160 converting...
164 converting...
161 0 remove a file
165 0 remove a file
162 $ svnupanddisplay a-hg-wc 1
166 $ svnupanddisplay a-hg-wc 1
163 5 1 test d1
167 5 1 test d1
164 5 1 test d1/d2
168 5 1 test d1/d2
165 5 1 test d1/d2/b
169 5 1 test d1/d2/b
166 5 4 test c
170 5 4 test c
167 5 5 test .
171 5 5 test .
168 revision: 5
172 revision: 5
169 author: test
173 author: test
174 date: * (glob)
170 msg: remove a file
175 msg: remove a file
171 D /b
176 D /b
172 $ ls a a-hg-wc
177 $ ls a a-hg-wc
173 a:
178 a:
174 c
179 c
175 d1
180 d1
176
181
177 a-hg-wc:
182 a-hg-wc:
178 c
183 c
179 d1
184 d1
180
185
181 Executable
186 Executable
182
187
183 #if execbit
188 #if execbit
184 $ chmod +x a/c
189 $ chmod +x a/c
185 #else
190 #else
186 $ echo fake >> a/c
191 $ echo fake >> a/c
187 #endif
192 #endif
188 $ hg --cwd a ci -d '5 0' -m 'make a file executable'
193 $ hg --cwd a ci -d '5 0' -m 'make a file executable'
189 #if execbit
194 #if execbit
190 $ hg --cwd a tip -q
195 $ hg --cwd a tip -q
191 5:ff42e473c340
196 5:ff42e473c340
192 #else
197 #else
193 $ hg --cwd a tip -q
198 $ hg --cwd a tip -q
194 5:817a700c8cf1
199 5:817a700c8cf1
195 #endif
200 #endif
196
201
197 $ hg convert -d svn a
202 $ hg convert -d svn a
198 assuming destination a-hg
203 assuming destination a-hg
199 initializing svn working copy 'a-hg-wc'
204 initializing svn working copy 'a-hg-wc'
200 scanning source...
205 scanning source...
201 sorting...
206 sorting...
202 converting...
207 converting...
203 0 make a file executable
208 0 make a file executable
204 $ svnupanddisplay a-hg-wc 1
209 $ svnupanddisplay a-hg-wc 1
205 6 1 test d1
210 6 1 test d1
206 6 1 test d1/d2
211 6 1 test d1/d2
207 6 1 test d1/d2/b
212 6 1 test d1/d2/b
208 6 6 test .
213 6 6 test .
209 6 6 test c
214 6 6 test c
210 revision: 6
215 revision: 6
211 author: test
216 author: test
217 date: * (glob)
212 msg: make a file executable
218 msg: make a file executable
213 M /c
219 M /c
214 #if execbit
220 #if execbit
215 $ test -x a-hg-wc/c
221 $ test -x a-hg-wc/c
216 #endif
222 #endif
217
223
218 #if symlink
224 #if symlink
219
225
220 Symlinks
226 Symlinks
221
227
222 $ ln -s a/missing a/link
228 $ ln -s a/missing a/link
223 $ hg --cwd a commit -Am 'add symlink'
229 $ hg --cwd a commit -Am 'add symlink'
224 adding link
230 adding link
225 $ hg --cwd a mv link newlink
231 $ hg --cwd a mv link newlink
226 $ hg --cwd a commit -m 'move symlink'
232 $ hg --cwd a commit -m 'move symlink'
227 $ hg convert -d svn a a-svnlink
233 $ hg convert -d svn a a-svnlink
228 initializing svn repository 'a-svnlink'
234 initializing svn repository 'a-svnlink'
229 initializing svn working copy 'a-svnlink-wc'
235 initializing svn working copy 'a-svnlink-wc'
230 scanning source...
236 scanning source...
231 sorting...
237 sorting...
232 converting...
238 converting...
233 7 add a file
239 7 add a file
234 6 modify a file
240 6 modify a file
235 5 rename a file
241 5 rename a file
236 4 copy a file
242 4 copy a file
237 3 remove a file
243 3 remove a file
238 2 make a file executable
244 2 make a file executable
239 1 add symlink
245 1 add symlink
240 0 move symlink
246 0 move symlink
241 $ svnupanddisplay a-svnlink-wc 1
247 $ svnupanddisplay a-svnlink-wc 1
242 8 1 test d1
248 8 1 test d1
243 8 1 test d1/d2
249 8 1 test d1/d2
244 8 1 test d1/d2/b
250 8 1 test d1/d2/b
245 8 6 test c
251 8 6 test c
246 8 8 test .
252 8 8 test .
247 8 8 test newlink
253 8 8 test newlink
248 revision: 8
254 revision: 8
249 author: test
255 author: test
256 date: * (glob)
250 msg: move symlink
257 msg: move symlink
251 D /link
258 D /link
252 A /newlink (from /link@7)
259 A /newlink (from /link@7)
253
260
254 Make sure our changes don't affect the rest of the test cases
261 Make sure our changes don't affect the rest of the test cases
255
262
256 $ hg --cwd a up 5
263 $ hg --cwd a up 5
257 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
264 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
258 $ hg --cwd a --config extensions.strip= strip -r 6
265 $ hg --cwd a --config extensions.strip= strip -r 6
259 saved backup bundle to $TESTTMP/a/.hg/strip-backup/bd4f7b7a7067-ed505e42-backup.hg
266 saved backup bundle to $TESTTMP/a/.hg/strip-backup/bd4f7b7a7067-ed505e42-backup.hg
260
267
261 #endif
268 #endif
262
269
263 Convert with --full adds and removes files that didn't change
270 Convert with --full adds and removes files that didn't change
264
271
265 $ touch a/f
272 $ touch a/f
266 $ hg -R a ci -Aqmf
273 $ hg -R a ci -Aqmf
267 $ echo "rename c d" > filemap
274 $ echo "rename c d" > filemap
268 $ hg convert -d svn a --filemap filemap --full
275 $ hg convert -d svn a --filemap filemap --full
269 assuming destination a-hg
276 assuming destination a-hg
270 initializing svn working copy 'a-hg-wc'
277 initializing svn working copy 'a-hg-wc'
271 scanning source...
278 scanning source...
272 sorting...
279 sorting...
273 converting...
280 converting...
274 0 f
281 0 f
275 $ svnupanddisplay a-hg-wc 1
282 $ svnupanddisplay a-hg-wc 1
276 7 7 test .
283 7 7 test .
277 7 7 test d
284 7 7 test d
278 7 7 test f
285 7 7 test f
279 revision: 7
286 revision: 7
280 author: test
287 author: test
288 date: * (glob)
281 msg: f
289 msg: f
282 D /c
290 D /c
283 A /d
291 A /d
284 D /d1
292 D /d1
285 A /f
293 A /f
286
294
287 $ rm -rf a a-hg a-hg-wc
295 $ rm -rf a a-hg a-hg-wc
288
296
289
297
290 Executable in new directory
298 Executable in new directory
291
299
292 $ hg init a
300 $ hg init a
293
301
294 $ mkdir a/d1
302 $ mkdir a/d1
295 $ echo a > a/d1/a
303 $ echo a > a/d1/a
296 #if execbit
304 #if execbit
297 $ chmod +x a/d1/a
305 $ chmod +x a/d1/a
298 #else
306 #else
299 $ echo fake >> a/d1/a
307 $ echo fake >> a/d1/a
300 #endif
308 #endif
301 $ hg --cwd a ci -d '0 0' -A -m 'add executable file in new directory'
309 $ hg --cwd a ci -d '0 0' -A -m 'add executable file in new directory'
302 adding d1/a
310 adding d1/a
303
311
304 $ hg convert -d svn a
312 $ hg convert -d svn a
305 assuming destination a-hg
313 assuming destination a-hg
306 initializing svn repository 'a-hg'
314 initializing svn repository 'a-hg'
307 initializing svn working copy 'a-hg-wc'
315 initializing svn working copy 'a-hg-wc'
308 scanning source...
316 scanning source...
309 sorting...
317 sorting...
310 converting...
318 converting...
311 0 add executable file in new directory
319 0 add executable file in new directory
312 $ svnupanddisplay a-hg-wc 1
320 $ svnupanddisplay a-hg-wc 1
313 1 1 test .
321 1 1 test .
314 1 1 test d1
322 1 1 test d1
315 1 1 test d1/a
323 1 1 test d1/a
316 revision: 1
324 revision: 1
317 author: test
325 author: test
326 date: * (glob)
318 msg: add executable file in new directory
327 msg: add executable file in new directory
319 A /d1
328 A /d1
320 A /d1/a
329 A /d1/a
321 #if execbit
330 #if execbit
322 $ test -x a-hg-wc/d1/a
331 $ test -x a-hg-wc/d1/a
323 #endif
332 #endif
324
333
325 Copy to new directory
334 Copy to new directory
326
335
327 $ mkdir a/d2
336 $ mkdir a/d2
328 $ hg --cwd a cp d1/a d2/a
337 $ hg --cwd a cp d1/a d2/a
329 $ hg --cwd a ci -d '1 0' -A -m 'copy file to new directory'
338 $ hg --cwd a ci -d '1 0' -A -m 'copy file to new directory'
330
339
331 $ hg convert -d svn a
340 $ hg convert -d svn a
332 assuming destination a-hg
341 assuming destination a-hg
333 initializing svn working copy 'a-hg-wc'
342 initializing svn working copy 'a-hg-wc'
334 scanning source...
343 scanning source...
335 sorting...
344 sorting...
336 converting...
345 converting...
337 0 copy file to new directory
346 0 copy file to new directory
338 $ svnupanddisplay a-hg-wc 1
347 $ svnupanddisplay a-hg-wc 1
339 2 1 test d1
348 2 1 test d1
340 2 1 test d1/a
349 2 1 test d1/a
341 2 2 test .
350 2 2 test .
342 2 2 test d2
351 2 2 test d2
343 2 2 test d2/a
352 2 2 test d2/a
344 revision: 2
353 revision: 2
345 author: test
354 author: test
355 date: * (glob)
346 msg: copy file to new directory
356 msg: copy file to new directory
347 A /d2
357 A /d2
348 A /d2/a (from /d1/a@1)
358 A /d2/a (from /d1/a@1)
349
359
350 Branchy history
360 Branchy history
351
361
352 $ hg init b
362 $ hg init b
353 $ echo base > b/b
363 $ echo base > b/b
354 $ hg --cwd b ci -d '0 0' -Ambase
364 $ hg --cwd b ci -d '0 0' -Ambase
355 adding b
365 adding b
356
366
357 $ svn-safe-append.py left-1 b/b
367 $ svn-safe-append.py left-1 b/b
358 $ echo left-1 > b/left-1
368 $ echo left-1 > b/left-1
359 $ hg --cwd b ci -d '1 0' -Amleft-1
369 $ hg --cwd b ci -d '1 0' -Amleft-1
360 adding left-1
370 adding left-1
361
371
362 $ svn-safe-append.py left-2 b/b
372 $ svn-safe-append.py left-2 b/b
363 $ echo left-2 > b/left-2
373 $ echo left-2 > b/left-2
364 $ hg --cwd b ci -d '2 0' -Amleft-2
374 $ hg --cwd b ci -d '2 0' -Amleft-2
365 adding left-2
375 adding left-2
366
376
367 $ hg --cwd b up 0
377 $ hg --cwd b up 0
368 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
378 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
369
379
370 $ svn-safe-append.py right-1 b/b
380 $ svn-safe-append.py right-1 b/b
371 $ echo right-1 > b/right-1
381 $ echo right-1 > b/right-1
372 $ hg --cwd b ci -d '3 0' -Amright-1
382 $ hg --cwd b ci -d '3 0' -Amright-1
373 adding right-1
383 adding right-1
374 created new head
384 created new head
375
385
376 $ svn-safe-append.py right-2 b/b
386 $ svn-safe-append.py right-2 b/b
377 $ echo right-2 > b/right-2
387 $ echo right-2 > b/right-2
378 $ hg --cwd b ci -d '4 0' -Amright-2
388 $ hg --cwd b ci -d '4 0' -Amright-2
379 adding right-2
389 adding right-2
380
390
381 $ hg --cwd b up -C 2
391 $ hg --cwd b up -C 2
382 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
392 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
383 $ hg --cwd b merge
393 $ hg --cwd b merge
384 merging b
394 merging b
385 warning: conflicts while merging b! (edit, then use 'hg resolve --mark')
395 warning: conflicts while merging b! (edit, then use 'hg resolve --mark')
386 2 files updated, 0 files merged, 0 files removed, 1 files unresolved
396 2 files updated, 0 files merged, 0 files removed, 1 files unresolved
387 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
397 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
388 [1]
398 [1]
389 $ hg --cwd b revert -r 2 b
399 $ hg --cwd b revert -r 2 b
390 $ hg --cwd b resolve -m b
400 $ hg --cwd b resolve -m b
391 (no more unresolved files)
401 (no more unresolved files)
392 $ hg --cwd b ci -d '5 0' -m 'merge'
402 $ hg --cwd b ci -d '5 0' -m 'merge'
393
403
394 Expect 4 changes
404 Expect 4 changes
395
405
396 $ hg convert -d svn b
406 $ hg convert -d svn b
397 assuming destination b-hg
407 assuming destination b-hg
398 initializing svn repository 'b-hg'
408 initializing svn repository 'b-hg'
399 initializing svn working copy 'b-hg-wc'
409 initializing svn working copy 'b-hg-wc'
400 scanning source...
410 scanning source...
401 sorting...
411 sorting...
402 converting...
412 converting...
403 5 base
413 5 base
404 4 left-1
414 4 left-1
405 3 left-2
415 3 left-2
406 2 right-1
416 2 right-1
407 1 right-2
417 1 right-2
408 0 merge
418 0 merge
409
419
410 $ svnupanddisplay b-hg-wc 0
420 $ svnupanddisplay b-hg-wc 0
411 4 2 test left-1
421 4 2 test left-1
412 4 3 test b
422 4 3 test b
413 4 3 test left-2
423 4 3 test left-2
414 4 4 test .
424 4 4 test .
415 4 4 test right-1
425 4 4 test right-1
416 4 4 test right-2
426 4 4 test right-2
417 revision: 4
427 revision: 4
418 author: test
428 author: test
429 date: * (glob)
419 msg: merge
430 msg: merge
420 A /right-1
431 A /right-1
421 A /right-2
432 A /right-2
422 revision: 3
433 revision: 3
423 author: test
434 author: test
435 date: * (glob)
424 msg: left-2
436 msg: left-2
425 M /b
437 M /b
426 A /left-2
438 A /left-2
427 revision: 2
439 revision: 2
428 author: test
440 author: test
441 date: * (glob)
429 msg: left-1
442 msg: left-1
430 M /b
443 M /b
431 A /left-1
444 A /left-1
432 revision: 1
445 revision: 1
433 author: test
446 author: test
447 date: * (glob)
434 msg: base
448 msg: base
435 A /b
449 A /b
436
450
437 Tags are not supported, but must not break conversion
451 Tags are not supported, but must not break conversion
438
452
439 $ rm -rf a a-hg a-hg-wc
453 $ rm -rf a a-hg a-hg-wc
440 $ hg init a
454 $ hg init a
441 $ echo a > a/a
455 $ echo a > a/a
442 $ hg --cwd a ci -d '0 0' -A -m 'Add file a'
456 $ hg --cwd a ci -d '0 0' -A -m 'Add file a'
443 adding a
457 adding a
444 $ hg --cwd a tag -d '1 0' -m 'Tagged as v1.0' v1.0
458 $ hg --cwd a tag -d '1 0' -m 'Tagged as v1.0' v1.0
445
459
446 $ hg convert -d svn a
460 $ hg convert -d svn a
447 assuming destination a-hg
461 assuming destination a-hg
448 initializing svn repository 'a-hg'
462 initializing svn repository 'a-hg'
449 initializing svn working copy 'a-hg-wc'
463 initializing svn working copy 'a-hg-wc'
450 scanning source...
464 scanning source...
451 sorting...
465 sorting...
452 converting...
466 converting...
453 1 Add file a
467 1 Add file a
454 0 Tagged as v1.0
468 0 Tagged as v1.0
455 writing Subversion tags is not yet implemented
469 writing Subversion tags is not yet implemented
456 $ svnupanddisplay a-hg-wc 2
470 $ svnupanddisplay a-hg-wc 2
457 2 1 test a
471 2 1 test a
458 2 2 test .
472 2 2 test .
459 2 2 test .hgtags
473 2 2 test .hgtags
460 revision: 2
474 revision: 2
461 author: test
475 author: test
476 date: * (glob)
462 msg: Tagged as v1.0
477 msg: Tagged as v1.0
463 A /.hgtags
478 A /.hgtags
464 revision: 1
479 revision: 1
465 author: test
480 author: test
481 date: * (glob)
466 msg: Add file a
482 msg: Add file a
467 A /a
483 A /a
468 $ rm -rf a a-hg a-hg-wc
484 $ rm -rf a a-hg a-hg-wc
469
485
470 #if execbit
486 #if execbit
471
487
472 Executable bit removal
488 Executable bit removal
473
489
474 $ hg init a
490 $ hg init a
475
491
476 $ echo a > a/exec
492 $ echo a > a/exec
477 $ chmod +x a/exec
493 $ chmod +x a/exec
478 $ hg --cwd a ci -d '1 0' -A -m 'create executable'
494 $ hg --cwd a ci -d '1 0' -A -m 'create executable'
479 adding exec
495 adding exec
480 $ chmod -x a/exec
496 $ chmod -x a/exec
481 $ hg --cwd a ci -d '2 0' -A -m 'remove executable bit'
497 $ hg --cwd a ci -d '2 0' -A -m 'remove executable bit'
482
498
483 $ hg convert -d svn a
499 $ hg convert -d svn a
484 assuming destination a-hg
500 assuming destination a-hg
485 initializing svn repository 'a-hg'
501 initializing svn repository 'a-hg'
486 initializing svn working copy 'a-hg-wc'
502 initializing svn working copy 'a-hg-wc'
487 scanning source...
503 scanning source...
488 sorting...
504 sorting...
489 converting...
505 converting...
490 1 create executable
506 1 create executable
491 0 remove executable bit
507 0 remove executable bit
492 $ svnupanddisplay a-hg-wc 0
508 $ svnupanddisplay a-hg-wc 0
493 2 2 test .
509 2 2 test .
494 2 2 test exec
510 2 2 test exec
495 revision: 2
511 revision: 2
496 author: test
512 author: test
513 date: * (glob)
497 msg: remove executable bit
514 msg: remove executable bit
498 M /exec
515 M /exec
499 revision: 1
516 revision: 1
500 author: test
517 author: test
518 date: * (glob)
501 msg: create executable
519 msg: create executable
502 A /exec
520 A /exec
503 $ test ! -x a-hg-wc/exec
521 $ test ! -x a-hg-wc/exec
504
522
505 $ rm -rf a a-hg a-hg-wc
523 $ rm -rf a a-hg a-hg-wc
506
524
507 #endif
525 #endif
508
526
509 Skipping empty commits
527 Skipping empty commits
510
528
511 $ hg init a
529 $ hg init a
512
530
513 $ hg --cwd a --config ui.allowemptycommit=True ci -d '1 0' -m 'Initial empty commit'
531 $ hg --cwd a --config ui.allowemptycommit=True ci -d '1 0' -m 'Initial empty commit'
514
532
515 $ echo a > a/a
533 $ echo a > a/a
516 $ hg --cwd a ci -d '0 0' -A -m 'Some change'
534 $ hg --cwd a ci -d '0 0' -A -m 'Some change'
517 adding a
535 adding a
518 $ hg --cwd a --config ui.allowemptycommit=True ci -d '2 0' -m 'Empty commit 1'
536 $ hg --cwd a --config ui.allowemptycommit=True ci -d '2 0' -m 'Empty commit 1'
519 $ hg --cwd a --config ui.allowemptycommit=True ci -d '3 0' -m 'Empty commit 2'
537 $ hg --cwd a --config ui.allowemptycommit=True ci -d '3 0' -m 'Empty commit 2'
520 $ echo b > a/b
538 $ echo b > a/b
521 $ hg --cwd a ci -d '0 0' -A -m 'Another change'
539 $ hg --cwd a ci -d '0 0' -A -m 'Another change'
522 adding b
540 adding b
523
541
524 $ hg convert -d svn a
542 $ hg convert -d svn a
525 assuming destination a-hg
543 assuming destination a-hg
526 initializing svn repository 'a-hg'
544 initializing svn repository 'a-hg'
527 initializing svn working copy 'a-hg-wc'
545 initializing svn working copy 'a-hg-wc'
528 scanning source...
546 scanning source...
529 sorting...
547 sorting...
530 converting...
548 converting...
531 4 Initial empty commit
549 4 Initial empty commit
532 3 Some change
550 3 Some change
533 2 Empty commit 1
551 2 Empty commit 1
534 1 Empty commit 2
552 1 Empty commit 2
535 0 Another change
553 0 Another change
536
554
537 $ svnupanddisplay a-hg-wc 0
555 $ svnupanddisplay a-hg-wc 0
538 2 1 test a
556 2 1 test a
539 2 2 test .
557 2 2 test .
540 2 2 test b
558 2 2 test b
541 revision: 2
559 revision: 2
542 author: test
560 author: test
561 date: * (glob)
543 msg: Another change
562 msg: Another change
544 A /b
563 A /b
545 revision: 1
564 revision: 1
546 author: test
565 author: test
566 date: * (glob)
547 msg: Some change
567 msg: Some change
548 A /a
568 A /a
549
569
550 $ rm -rf a a-hg a-hg-wc
570 $ rm -rf a a-hg a-hg-wc
571
572 Commit dates convertion
573
574 $ hg init a
575
576 $ echo a >> a/a
577 $ hg add a
578 adding a/a
579 $ hg --cwd a ci -d '1 0' -A -m 'Change 1'
580
581 $ echo a >> a/a
582 $ hg --cwd a ci -d '2 0' -m 'Change 2'
583
584 $ echo a >> a/a
585 $ hg --cwd a ci -d '2 0' -m 'Change at the same time'
586
587 $ echo a >> a/a
588 $ hg --cwd a ci -d '1 0' -m 'Change in the past'
589
590 $ echo a >> a/a
591 $ hg --cwd a ci -d '3 0' -m 'Change in the future'
592
593 $ hg convert --config convert.svn.dangerous-set-commit-dates=true -d svn a
594 assuming destination a-hg
595 initializing svn repository 'a-hg'
596 initializing svn working copy 'a-hg-wc'
597 scanning source...
598 sorting...
599 converting...
600 4 Change 1
601 3 Change 2
602 2 Change at the same time
603 1 Change in the past
604 0 Change in the future
605 $ svnupanddisplay a-hg-wc 0
606 5 5 test .
607 5 5 test a
608 revision: 5
609 author: test
610 date: 1970-01-01T00:00:03.000000Z
611 msg: Change in the future
612 M /a
613 revision: 4
614 author: test
615 date: 1970-01-01T00:00:01.000000Z
616 msg: Change in the past
617 M /a
618 revision: 3
619 author: test
620 date: 1970-01-01T00:00:02.000000Z
621 msg: Change at the same time
622 M /a
623 revision: 2
624 author: test
625 date: 1970-01-01T00:00:02.000000Z
626 msg: Change 2
627 M /a
628 revision: 1
629 author: test
630 date: 1970-01-01T00:00:01.000000Z
631 msg: Change 1
632 A /a
633
634 $ rm -rf a a-hg a-hg-wc
@@ -1,635 +1,652 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 new branch name.
128 destination repository. No whitespace is allowed in the new branch name.
129 This can be used to (for instance) move code in one repository from
129 This can be used to (for instance) move code in one repository from
130 "default" to a named branch.
130 "default" 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 Bazaar Source
151 Bazaar Source
152 #############
152 #############
153
153
154 The following options can be used with "--config":
154 The following options can be used with "--config":
155
155
156 convert.bzr.saverev
156 convert.bzr.saverev
157 whether to store the original Bazaar commit ID in the
157 whether to store the original Bazaar commit ID in the
158 metadata of the destination commit. The default is True.
158 metadata of the destination commit. The default is True.
159
159
160 CVS Source
160 CVS Source
161 ##########
161 ##########
162
162
163 CVS source will use a sandbox (i.e. a checked-out copy) from CVS to
163 CVS source will use a sandbox (i.e. a checked-out copy) from CVS to
164 indicate the starting point of what will be converted. Direct access to
164 indicate the starting point of what will be converted. Direct access to
165 the repository files is not needed, unless of course the repository is
165 the repository files is not needed, unless of course the repository is
166 ":local:". The conversion uses the top level directory in the sandbox to
166 ":local:". The conversion uses the top level directory in the sandbox to
167 find the CVS repository, and then uses CVS rlog commands to find files to
167 find the CVS repository, and then uses CVS rlog commands to find files to
168 convert. This means that unless a filemap is given, all files under the
168 convert. This means that unless a filemap is given, all files under the
169 starting directory will be converted, and that any directory
169 starting directory will be converted, and that any directory
170 reorganization in the CVS sandbox is ignored.
170 reorganization in the CVS sandbox is ignored.
171
171
172 The following options can be used with "--config":
172 The following options can be used with "--config":
173
173
174 convert.cvsps.cache
174 convert.cvsps.cache
175 Set to False to disable remote log caching, for testing and
175 Set to False to disable remote log caching, for testing and
176 debugging purposes. Default is True.
176 debugging purposes. Default is True.
177 convert.cvsps.fuzz
177 convert.cvsps.fuzz
178 Specify the maximum time (in seconds) that is allowed
178 Specify the maximum time (in seconds) that is allowed
179 between commits with identical user and log message in a
179 between commits with identical user and log message in a
180 single changeset. When very large files were checked in as
180 single changeset. When very large files were checked in as
181 part of a changeset then the default may not be long enough.
181 part of a changeset then the default may not be long enough.
182 The default is 60.
182 The default is 60.
183 convert.cvsps.logencoding
183 convert.cvsps.logencoding
184 Specify encoding name to be used for transcoding CVS log
184 Specify encoding name to be used for transcoding CVS log
185 messages. Multiple encoding names can be specified as a list
185 messages. Multiple encoding names can be specified as a list
186 (see 'hg help config.Syntax'), but only the first acceptable
186 (see 'hg help config.Syntax'), but only the first acceptable
187 encoding in the list is used per CVS log entries. This
187 encoding in the list is used per CVS log entries. This
188 transcoding is executed before cvslog hook below.
188 transcoding is executed before cvslog hook below.
189 convert.cvsps.mergeto
189 convert.cvsps.mergeto
190 Specify a regular expression to which commit log messages
190 Specify a regular expression to which commit log messages
191 are matched. If a match occurs, then the conversion process
191 are matched. If a match occurs, then the conversion process
192 will insert a dummy revision merging the branch on which
192 will insert a dummy revision merging the branch on which
193 this log message occurs to the branch indicated in the
193 this log message occurs to the branch indicated in the
194 regex. Default is "{{mergetobranch ([-\w]+)}}"
194 regex. Default is "{{mergetobranch ([-\w]+)}}"
195 convert.cvsps.mergefrom
195 convert.cvsps.mergefrom
196 Specify a regular expression to which commit log messages
196 Specify a regular expression to which commit log messages
197 are matched. If a match occurs, then the conversion process
197 are matched. If a match occurs, then the conversion process
198 will add the most recent revision on the branch indicated in
198 will add the most recent revision on the branch indicated in
199 the regex as the second parent of the changeset. Default is
199 the regex as the second parent of the changeset. Default is
200 "{{mergefrombranch ([-\w]+)}}"
200 "{{mergefrombranch ([-\w]+)}}"
201 convert.localtimezone
201 convert.localtimezone
202 use local time (as determined by the TZ environment
202 use local time (as determined by the TZ environment
203 variable) for changeset date/times. The default is False
203 variable) for changeset date/times. The default is False
204 (use UTC).
204 (use UTC).
205 hooks.cvslog Specify a Python function to be called at the end of
205 hooks.cvslog Specify a Python function to be called at the end of
206 gathering the CVS log. The function is passed a list with
206 gathering the CVS log. The function is passed a list with
207 the log entries, and can modify the entries in-place, or add
207 the log entries, and can modify the entries in-place, or add
208 or delete them.
208 or delete them.
209 hooks.cvschangesets
209 hooks.cvschangesets
210 Specify a Python function to be called after the changesets
210 Specify a Python function to be called after the changesets
211 are calculated from the CVS log. The function is passed a
211 are calculated from the CVS log. The function is passed a
212 list with the changeset entries, and can modify the
212 list with the changeset entries, and can modify the
213 changesets in-place, or add or delete them.
213 changesets in-place, or add or delete them.
214
214
215 An additional "debugcvsps" Mercurial command allows the builtin changeset
215 An additional "debugcvsps" Mercurial command allows the builtin changeset
216 merging code to be run without doing a conversion. Its parameters and
216 merging code to be run without doing a conversion. Its parameters and
217 output are similar to that of cvsps 2.1. Please see the command help for
217 output are similar to that of cvsps 2.1. Please see the command help for
218 more details.
218 more details.
219
219
220 Subversion Source
220 Subversion Source
221 #################
221 #################
222
222
223 Subversion source detects classical trunk/branches/tags layouts. By
223 Subversion source detects classical trunk/branches/tags layouts. By
224 default, the supplied "svn://repo/path/" source URL is converted as a
224 default, the supplied "svn://repo/path/" source URL is converted as a
225 single branch. If "svn://repo/path/trunk" exists it replaces the default
225 single branch. If "svn://repo/path/trunk" exists it replaces the default
226 branch. If "svn://repo/path/branches" exists, its subdirectories are
226 branch. If "svn://repo/path/branches" exists, its subdirectories are
227 listed as possible branches. If "svn://repo/path/tags" exists, it is
227 listed as possible branches. If "svn://repo/path/tags" exists, it is
228 looked for tags referencing converted branches. Default "trunk",
228 looked for tags referencing converted branches. Default "trunk",
229 "branches" and "tags" values can be overridden with following options. Set
229 "branches" and "tags" values can be overridden with following options. Set
230 them to paths relative to the source URL, or leave them blank to disable
230 them to paths relative to the source URL, or leave them blank to disable
231 auto detection.
231 auto detection.
232
232
233 The following options can be set with "--config":
233 The following options can be set with "--config":
234
234
235 convert.svn.branches
235 convert.svn.branches
236 specify the directory containing branches. The default is
236 specify the directory containing branches. The default is
237 "branches".
237 "branches".
238 convert.svn.tags
238 convert.svn.tags
239 specify the directory containing tags. The default is
239 specify the directory containing tags. The default is
240 "tags".
240 "tags".
241 convert.svn.trunk
241 convert.svn.trunk
242 specify the name of the trunk branch. The default is
242 specify the name of the trunk branch. The default is
243 "trunk".
243 "trunk".
244 convert.localtimezone
244 convert.localtimezone
245 use local time (as determined by the TZ environment
245 use local time (as determined by the TZ environment
246 variable) for changeset date/times. The default is False
246 variable) for changeset date/times. The default is False
247 (use UTC).
247 (use UTC).
248
248
249 Source history can be retrieved starting at a specific revision, instead
249 Source history can be retrieved starting at a specific revision, instead
250 of being integrally converted. Only single branch conversions are
250 of being integrally converted. Only single branch conversions are
251 supported.
251 supported.
252
252
253 convert.svn.startrev
253 convert.svn.startrev
254 specify start Subversion revision number. The default is 0.
254 specify start Subversion revision number. The default is 0.
255
255
256 Git Source
256 Git Source
257 ##########
257 ##########
258
258
259 The Git importer converts commits from all reachable branches (refs in
259 The Git importer converts commits from all reachable branches (refs in
260 refs/heads) and remotes (refs in refs/remotes) to Mercurial. Branches are
260 refs/heads) and remotes (refs in refs/remotes) to Mercurial. Branches are
261 converted to bookmarks with the same name, with the leading 'refs/heads'
261 converted to bookmarks with the same name, with the leading 'refs/heads'
262 stripped. Git submodules are converted to Git subrepos in Mercurial.
262 stripped. Git submodules are converted to Git subrepos in Mercurial.
263
263
264 The following options can be set with "--config":
264 The following options can be set with "--config":
265
265
266 convert.git.similarity
266 convert.git.similarity
267 specify how similar files modified in a commit must be to be
267 specify how similar files modified in a commit must be to be
268 imported as renames or copies, as a percentage between "0"
268 imported as renames or copies, as a percentage between "0"
269 (disabled) and "100" (files must be identical). For example,
269 (disabled) and "100" (files must be identical). For example,
270 "90" means that a delete/add pair will be imported as a
270 "90" means that a delete/add pair will be imported as a
271 rename if more than 90% of the file hasn't changed. The
271 rename if more than 90% of the file hasn't changed. The
272 default is "50".
272 default is "50".
273 convert.git.findcopiesharder
273 convert.git.findcopiesharder
274 while detecting copies, look at all files in the working
274 while detecting copies, look at all files in the working
275 copy instead of just changed ones. This is very expensive
275 copy instead of just changed ones. This is very expensive
276 for large projects, and is only effective when
276 for large projects, and is only effective when
277 "convert.git.similarity" is greater than 0. The default is
277 "convert.git.similarity" is greater than 0. The default is
278 False.
278 False.
279 convert.git.renamelimit
279 convert.git.renamelimit
280 perform rename and copy detection up to this many changed
280 perform rename and copy detection up to this many changed
281 files in a commit. Increasing this will make rename and copy
281 files in a commit. Increasing this will make rename and copy
282 detection more accurate but will significantly slow down
282 detection more accurate but will significantly slow down
283 computation on large projects. The option is only relevant
283 computation on large projects. The option is only relevant
284 if "convert.git.similarity" is greater than 0. The default
284 if "convert.git.similarity" is greater than 0. The default
285 is "400".
285 is "400".
286 convert.git.committeractions
286 convert.git.committeractions
287 list of actions to take when processing author and committer
287 list of actions to take when processing author and committer
288 values.
288 values.
289
289
290 Git commits have separate author (who wrote the commit) and committer
290 Git commits have separate author (who wrote the commit) and committer
291 (who applied the commit) fields. Not all destinations support separate
291 (who applied the commit) fields. Not all destinations support separate
292 author and committer fields (including Mercurial). This config option
292 author and committer fields (including Mercurial). This config option
293 controls what to do with these author and committer fields during
293 controls what to do with these author and committer fields during
294 conversion.
294 conversion.
295
295
296 A value of "messagedifferent" will append a "committer: ..." line to
296 A value of "messagedifferent" will append a "committer: ..." line to
297 the commit message if the Git committer is different from the author.
297 the commit message if the Git committer is different from the author.
298 The prefix of that line can be specified using the syntax
298 The prefix of that line can be specified using the syntax
299 "messagedifferent=<prefix>". e.g. "messagedifferent=git-committer:".
299 "messagedifferent=<prefix>". e.g. "messagedifferent=git-committer:".
300 When a prefix is specified, a space will always be inserted between
300 When a prefix is specified, a space will always be inserted between
301 the prefix and the value.
301 the prefix and the value.
302
302
303 "messagealways" behaves like "messagedifferent" except it will always
303 "messagealways" behaves like "messagedifferent" except it will always
304 result in a "committer: ..." line being appended to the commit
304 result in a "committer: ..." line being appended to the commit
305 message. This value is mutually exclusive with "messagedifferent".
305 message. This value is mutually exclusive with "messagedifferent".
306
306
307 "dropcommitter" will remove references to the committer. Only
307 "dropcommitter" will remove references to the committer. Only
308 references to the author will remain. Actions that add references to
308 references to the author will remain. Actions that add references to
309 the committer will have no effect when this is set.
309 the committer will have no effect when this is set.
310
310
311 "replaceauthor" will replace the value of the author field with the
311 "replaceauthor" will replace the value of the author field with the
312 committer. Other actions that add references to the committer will
312 committer. Other actions that add references to the committer will
313 still take effect when this is set.
313 still take effect when this is set.
314
314
315 The default is "messagedifferent".
315 The default is "messagedifferent".
316
316
317 convert.git.extrakeys
317 convert.git.extrakeys
318 list of extra keys from commit metadata to copy to the
318 list of extra keys from commit metadata to copy to the
319 destination. Some Git repositories store extra metadata in
319 destination. Some Git repositories store extra metadata in
320 commits. By default, this non-default metadata will be lost
320 commits. By default, this non-default metadata will be lost
321 during conversion. Setting this config option can retain
321 during conversion. Setting this config option can retain
322 that metadata. Some built-in keys such as "parent" and
322 that metadata. Some built-in keys such as "parent" and
323 "branch" are not allowed to be copied.
323 "branch" are not allowed to be copied.
324 convert.git.remoteprefix
324 convert.git.remoteprefix
325 remote refs are converted as bookmarks with
325 remote refs are converted as bookmarks with
326 "convert.git.remoteprefix" as a prefix followed by a /. The
326 "convert.git.remoteprefix" as a prefix followed by a /. The
327 default is 'remote'.
327 default is 'remote'.
328 convert.git.saverev
328 convert.git.saverev
329 whether to store the original Git commit ID in the metadata
329 whether to store the original Git commit ID in the metadata
330 of the destination commit. The default is True.
330 of the destination commit. The default is True.
331 convert.git.skipsubmodules
331 convert.git.skipsubmodules
332 does not convert root level .gitmodules files or files with
332 does not convert root level .gitmodules files or files with
333 160000 mode indicating a submodule. Default is False.
333 160000 mode indicating a submodule. Default is False.
334
334
335 Perforce Source
335 Perforce Source
336 ###############
336 ###############
337
337
338 The Perforce (P4) importer can be given a p4 depot path or a client
338 The Perforce (P4) importer can be given a p4 depot path or a client
339 specification as source. It will convert all files in the source to a flat
339 specification as source. It will convert all files in the source to a flat
340 Mercurial repository, ignoring labels, branches and integrations. Note
340 Mercurial repository, ignoring labels, branches and integrations. Note
341 that when a depot path is given you then usually should specify a target
341 that when a depot path is given you then usually should specify a target
342 directory, because otherwise the target may be named "...-hg".
342 directory, because otherwise the target may be named "...-hg".
343
343
344 The following options can be set with "--config":
344 The following options can be set with "--config":
345
345
346 convert.p4.encoding
346 convert.p4.encoding
347 specify the encoding to use when decoding standard output of
347 specify the encoding to use when decoding standard output of
348 the Perforce command line tool. The default is default
348 the Perforce command line tool. The default is default
349 system encoding.
349 system encoding.
350 convert.p4.startrev
350 convert.p4.startrev
351 specify initial Perforce revision (a Perforce changelist
351 specify initial Perforce revision (a Perforce changelist
352 number).
352 number).
353
353
354 Mercurial Destination
354 Mercurial Destination
355 #####################
355 #####################
356
356
357 The Mercurial destination will recognize Mercurial subrepositories in the
357 The Mercurial destination will recognize Mercurial subrepositories in the
358 destination directory, and update the .hgsubstate file automatically if
358 destination directory, and update the .hgsubstate file automatically if
359 the destination subrepositories contain the <dest>/<sub>/.hg/shamap file.
359 the destination subrepositories contain the <dest>/<sub>/.hg/shamap file.
360 Converting a repository with subrepositories requires converting a single
360 Converting a repository with subrepositories requires converting a single
361 repository at a time, from the bottom up.
361 repository at a time, from the bottom up.
362
362
363 The following options are supported:
363 The following options are supported:
364
364
365 convert.hg.clonebranches
365 convert.hg.clonebranches
366 dispatch source branches in separate clones. The default is
366 dispatch source branches in separate clones. The default is
367 False.
367 False.
368 convert.hg.tagsbranch
368 convert.hg.tagsbranch
369 branch name for tag revisions, defaults to "default".
369 branch name for tag revisions, defaults to "default".
370 convert.hg.usebranchnames
370 convert.hg.usebranchnames
371 preserve branch names. The default is True.
371 preserve branch names. The default is True.
372 convert.hg.sourcename
372 convert.hg.sourcename
373 records the given string as a 'convert_source' extra value
373 records the given string as a 'convert_source' extra value
374 on each commit made in the target repository. The default is
374 on each commit made in the target repository. The default is
375 None.
375 None.
376 convert.hg.preserve-hash
376 convert.hg.preserve-hash
377 only works with mercurial sources. Make convert prevent
377 only works with mercurial sources. Make convert prevent
378 performance improvement to the list of modified files in
378 performance improvement to the list of modified files in
379 commits when such an improvement would cause the hash of a
379 commits when such an improvement would cause the hash of a
380 commit to change. The default is False.
380 commit to change. The default is False.
381
381
382 All Destinations
382 All Destinations
383 ################
383 ################
384
384
385 All destination types accept the following options:
385 All destination types accept the following options:
386
386
387 convert.skiptags
387 convert.skiptags
388 does not convert tags from the source repo to the target
388 does not convert tags from the source repo to the target
389 repo. The default is False.
389 repo. The default is False.
390
390
391 Subversion Destination
392 ######################
393
394 Original commit dates are not preserved by default.
395
396 convert.svn.dangerous-set-commit-dates
397 preserve original commit dates, forcefully setting
398 "svn:date" revision properties. This option is DANGEROUS and
399 may break some subversion functionality for the resulting
400 repository (e.g. filtering revisions with date ranges in
401 "svn log"), as original commit dates are not guaranteed to
402 be monotonically increasing.
403
404 For commit dates setting to work destination repository must have "pre-
405 revprop-change" hook configured to allow setting of "svn:date" revision
406 properties. See Subversion documentation for more details.
407
391 options ([+] can be repeated):
408 options ([+] can be repeated):
392
409
393 -s --source-type TYPE source repository type
410 -s --source-type TYPE source repository type
394 -d --dest-type TYPE destination repository type
411 -d --dest-type TYPE destination repository type
395 -r --rev REV [+] import up to source revision REV
412 -r --rev REV [+] import up to source revision REV
396 -A --authormap FILE remap usernames using this file
413 -A --authormap FILE remap usernames using this file
397 --filemap FILE remap file names using contents of file
414 --filemap FILE remap file names using contents of file
398 --full apply filemap changes by converting all files again
415 --full apply filemap changes by converting all files again
399 --splicemap FILE splice synthesized history into place
416 --splicemap FILE splice synthesized history into place
400 --branchmap FILE change branch names while converting
417 --branchmap FILE change branch names while converting
401 --branchsort try to sort changesets by branches
418 --branchsort try to sort changesets by branches
402 --datesort try to sort changesets by date
419 --datesort try to sort changesets by date
403 --sourcesort preserve source changesets order
420 --sourcesort preserve source changesets order
404 --closesort try to reorder closed revisions
421 --closesort try to reorder closed revisions
405
422
406 (some details hidden, use --verbose to show complete help)
423 (some details hidden, use --verbose to show complete help)
407 $ hg init a
424 $ hg init a
408 $ cd a
425 $ cd a
409 $ echo a > a
426 $ echo a > a
410 $ hg ci -d'0 0' -Ama
427 $ hg ci -d'0 0' -Ama
411 adding a
428 adding a
412 $ hg cp a b
429 $ hg cp a b
413 $ hg ci -d'1 0' -mb
430 $ hg ci -d'1 0' -mb
414 $ hg rm a
431 $ hg rm a
415 $ hg ci -d'2 0' -mc
432 $ hg ci -d'2 0' -mc
416 $ hg mv b a
433 $ hg mv b a
417 $ hg ci -d'3 0' -md
434 $ hg ci -d'3 0' -md
418 $ echo a >> a
435 $ echo a >> a
419 $ hg ci -d'4 0' -me
436 $ hg ci -d'4 0' -me
420 $ cd ..
437 $ cd ..
421 $ hg convert a 2>&1 | grep -v 'subversion python bindings could not be loaded'
438 $ hg convert a 2>&1 | grep -v 'subversion python bindings could not be loaded'
422 assuming destination a-hg
439 assuming destination a-hg
423 initializing destination a-hg repository
440 initializing destination a-hg repository
424 scanning source...
441 scanning source...
425 sorting...
442 sorting...
426 converting...
443 converting...
427 4 a
444 4 a
428 3 b
445 3 b
429 2 c
446 2 c
430 1 d
447 1 d
431 0 e
448 0 e
432 $ hg --cwd a-hg pull ../a
449 $ hg --cwd a-hg pull ../a
433 pulling from ../a
450 pulling from ../a
434 searching for changes
451 searching for changes
435 no changes found
452 no changes found
436 5 local changesets published
453 5 local changesets published
437
454
438 conversion to existing file should fail
455 conversion to existing file should fail
439
456
440 $ touch bogusfile
457 $ touch bogusfile
441 $ hg convert a bogusfile
458 $ hg convert a bogusfile
442 initializing destination bogusfile repository
459 initializing destination bogusfile repository
443 abort: cannot create new bundle repository
460 abort: cannot create new bundle repository
444 [255]
461 [255]
445
462
446 #if unix-permissions no-root
463 #if unix-permissions no-root
447
464
448 conversion to dir without permissions should fail
465 conversion to dir without permissions should fail
449
466
450 $ mkdir bogusdir
467 $ mkdir bogusdir
451 $ chmod 000 bogusdir
468 $ chmod 000 bogusdir
452
469
453 $ hg convert a bogusdir
470 $ hg convert a bogusdir
454 abort: Permission denied: *bogusdir* (glob)
471 abort: Permission denied: *bogusdir* (glob)
455 [255]
472 [255]
456
473
457 user permissions should succeed
474 user permissions should succeed
458
475
459 $ chmod 700 bogusdir
476 $ chmod 700 bogusdir
460 $ hg convert a bogusdir
477 $ hg convert a bogusdir
461 initializing destination bogusdir repository
478 initializing destination bogusdir repository
462 scanning source...
479 scanning source...
463 sorting...
480 sorting...
464 converting...
481 converting...
465 4 a
482 4 a
466 3 b
483 3 b
467 2 c
484 2 c
468 1 d
485 1 d
469 0 e
486 0 e
470
487
471 #endif
488 #endif
472
489
473 test pre and post conversion actions
490 test pre and post conversion actions
474
491
475 $ echo 'include b' > filemap
492 $ echo 'include b' > filemap
476 $ hg convert --debug --filemap filemap a partialb | \
493 $ hg convert --debug --filemap filemap a partialb | \
477 > grep 'run hg'
494 > grep 'run hg'
478 run hg source pre-conversion action
495 run hg source pre-conversion action
479 run hg sink pre-conversion action
496 run hg sink pre-conversion action
480 run hg sink post-conversion action
497 run hg sink post-conversion action
481 run hg source post-conversion action
498 run hg source post-conversion action
482
499
483 converting empty dir should fail "nicely
500 converting empty dir should fail "nicely
484
501
485 $ mkdir emptydir
502 $ mkdir emptydir
486
503
487 override $PATH to ensure p4 not visible; use $PYTHON in case we're
504 override $PATH to ensure p4 not visible; use $PYTHON in case we're
488 running from a devel copy, not a temp installation
505 running from a devel copy, not a temp installation
489
506
490 $ PATH="$BINDIR" "$PYTHON" "$BINDIR"/hg convert emptydir
507 $ PATH="$BINDIR" "$PYTHON" "$BINDIR"/hg convert emptydir
491 assuming destination emptydir-hg
508 assuming destination emptydir-hg
492 initializing destination emptydir-hg repository
509 initializing destination emptydir-hg repository
493 emptydir does not look like a CVS checkout
510 emptydir does not look like a CVS checkout
494 $TESTTMP/emptydir does not look like a Git repository
511 $TESTTMP/emptydir does not look like a Git repository
495 emptydir does not look like a Subversion repository
512 emptydir does not look like a Subversion repository
496 emptydir is not a local Mercurial repository
513 emptydir is not a local Mercurial repository
497 emptydir does not look like a darcs repository
514 emptydir does not look like a darcs repository
498 emptydir does not look like a monotone repository
515 emptydir does not look like a monotone repository
499 emptydir does not look like a GNU Arch repository
516 emptydir does not look like a GNU Arch repository
500 emptydir does not look like a Bazaar repository
517 emptydir does not look like a Bazaar repository
501 cannot find required "p4" tool
518 cannot find required "p4" tool
502 abort: emptydir: missing or unsupported repository
519 abort: emptydir: missing or unsupported repository
503 [255]
520 [255]
504
521
505 convert with imaginary source type
522 convert with imaginary source type
506
523
507 $ hg convert --source-type foo a a-foo
524 $ hg convert --source-type foo a a-foo
508 initializing destination a-foo repository
525 initializing destination a-foo repository
509 abort: foo: invalid source repository type
526 abort: foo: invalid source repository type
510 [255]
527 [255]
511
528
512 convert with imaginary sink type
529 convert with imaginary sink type
513
530
514 $ hg convert --dest-type foo a a-foo
531 $ hg convert --dest-type foo a a-foo
515 abort: foo: invalid destination repository type
532 abort: foo: invalid destination repository type
516 [255]
533 [255]
517
534
518 testing: convert must not produce duplicate entries in fncache
535 testing: convert must not produce duplicate entries in fncache
519
536
520 $ hg convert a b
537 $ hg convert a b
521 initializing destination b repository
538 initializing destination b repository
522 scanning source...
539 scanning source...
523 sorting...
540 sorting...
524 converting...
541 converting...
525 4 a
542 4 a
526 3 b
543 3 b
527 2 c
544 2 c
528 1 d
545 1 d
529 0 e
546 0 e
530
547
531 contents of fncache file:
548 contents of fncache file:
532
549
533 #if repofncache
550 #if repofncache
534 $ cat b/.hg/store/fncache | sort
551 $ cat b/.hg/store/fncache | sort
535 data/a.i (reporevlogstore !)
552 data/a.i (reporevlogstore !)
536 data/b.i (reporevlogstore !)
553 data/b.i (reporevlogstore !)
537 #endif
554 #endif
538
555
539 test bogus URL
556 test bogus URL
540
557
541 #if no-msys
558 #if no-msys
542 $ hg convert -q bzr+ssh://foobar@selenic.com/baz baz
559 $ hg convert -q bzr+ssh://foobar@selenic.com/baz baz
543 abort: bzr+ssh://foobar@selenic.com/baz: missing or unsupported repository
560 abort: bzr+ssh://foobar@selenic.com/baz: missing or unsupported repository
544 [255]
561 [255]
545 #endif
562 #endif
546
563
547 test revset converted() lookup
564 test revset converted() lookup
548
565
549 $ hg --config convert.hg.saverev=True convert a c
566 $ hg --config convert.hg.saverev=True convert a c
550 initializing destination c repository
567 initializing destination c repository
551 scanning source...
568 scanning source...
552 sorting...
569 sorting...
553 converting...
570 converting...
554 4 a
571 4 a
555 3 b
572 3 b
556 2 c
573 2 c
557 1 d
574 1 d
558 0 e
575 0 e
559 $ echo f > c/f
576 $ echo f > c/f
560 $ hg -R c ci -d'0 0' -Amf
577 $ hg -R c ci -d'0 0' -Amf
561 adding f
578 adding f
562 created new head
579 created new head
563 $ hg -R c log -r "converted(09d945a62ce6)"
580 $ hg -R c log -r "converted(09d945a62ce6)"
564 changeset: 1:98c3dd46a874
581 changeset: 1:98c3dd46a874
565 user: test
582 user: test
566 date: Thu Jan 01 00:00:01 1970 +0000
583 date: Thu Jan 01 00:00:01 1970 +0000
567 summary: b
584 summary: b
568
585
569 $ hg -R c log -r "converted()"
586 $ hg -R c log -r "converted()"
570 changeset: 0:31ed57b2037c
587 changeset: 0:31ed57b2037c
571 user: test
588 user: test
572 date: Thu Jan 01 00:00:00 1970 +0000
589 date: Thu Jan 01 00:00:00 1970 +0000
573 summary: a
590 summary: a
574
591
575 changeset: 1:98c3dd46a874
592 changeset: 1:98c3dd46a874
576 user: test
593 user: test
577 date: Thu Jan 01 00:00:01 1970 +0000
594 date: Thu Jan 01 00:00:01 1970 +0000
578 summary: b
595 summary: b
579
596
580 changeset: 2:3b9ca06ef716
597 changeset: 2:3b9ca06ef716
581 user: test
598 user: test
582 date: Thu Jan 01 00:00:02 1970 +0000
599 date: Thu Jan 01 00:00:02 1970 +0000
583 summary: c
600 summary: c
584
601
585 changeset: 3:4e0debd37cf2
602 changeset: 3:4e0debd37cf2
586 user: test
603 user: test
587 date: Thu Jan 01 00:00:03 1970 +0000
604 date: Thu Jan 01 00:00:03 1970 +0000
588 summary: d
605 summary: d
589
606
590 changeset: 4:9de3bc9349c5
607 changeset: 4:9de3bc9349c5
591 user: test
608 user: test
592 date: Thu Jan 01 00:00:04 1970 +0000
609 date: Thu Jan 01 00:00:04 1970 +0000
593 summary: e
610 summary: e
594
611
595
612
596 test specifying a sourcename
613 test specifying a sourcename
597 $ echo g > a/g
614 $ echo g > a/g
598 $ hg -R a ci -d'0 0' -Amg
615 $ hg -R a ci -d'0 0' -Amg
599 adding g
616 adding g
600 $ hg --config convert.hg.sourcename=mysource --config convert.hg.saverev=True convert a c
617 $ hg --config convert.hg.sourcename=mysource --config convert.hg.saverev=True convert a c
601 scanning source...
618 scanning source...
602 sorting...
619 sorting...
603 converting...
620 converting...
604 0 g
621 0 g
605 $ hg -R c log -r tip --template '{extras % "{extra}\n"}'
622 $ hg -R c log -r tip --template '{extras % "{extra}\n"}'
606 branch=default
623 branch=default
607 convert_revision=a3bc6100aa8ec03e00aaf271f1f50046fb432072
624 convert_revision=a3bc6100aa8ec03e00aaf271f1f50046fb432072
608 convert_source=mysource
625 convert_source=mysource
609
626
610 $ cat > branchmap.txt << EOF
627 $ cat > branchmap.txt << EOF
611 > old branch new_branch
628 > old branch new_branch
612 > EOF
629 > EOF
613
630
614 $ hg -R a branch -q 'old branch'
631 $ hg -R a branch -q 'old branch'
615 $ echo gg > a/g
632 $ echo gg > a/g
616 $ hg -R a ci -m 'branch name with spaces'
633 $ hg -R a ci -m 'branch name with spaces'
617 $ hg convert --branchmap branchmap.txt a d
634 $ hg convert --branchmap branchmap.txt a d
618 initializing destination d repository
635 initializing destination d repository
619 scanning source...
636 scanning source...
620 sorting...
637 sorting...
621 converting...
638 converting...
622 6 a
639 6 a
623 5 b
640 5 b
624 4 c
641 4 c
625 3 d
642 3 d
626 2 e
643 2 e
627 1 g
644 1 g
628 0 branch name with spaces
645 0 branch name with spaces
629
646
630 $ hg -R a branches
647 $ hg -R a branches
631 old branch 6:a24a66ade009
648 old branch 6:a24a66ade009
632 default 5:a3bc6100aa8e (inactive)
649 default 5:a3bc6100aa8e (inactive)
633 $ hg -R d branches
650 $ hg -R d branches
634 new_branch 6:64ed208b732b
651 new_branch 6:64ed208b732b
635 default 5:a3bc6100aa8e (inactive)
652 default 5:a3bc6100aa8e (inactive)
General Comments 0
You need to be logged in to leave comments. Login now