1 # (Be in -*- python -*- mode.)
3 # ====================================================================
4 # Copyright (c) 2000-2009 CollabNet. All rights reserved.
6 # This software is licensed as described in the file COPYING, which
7 # you should have received as part of this distribution. The terms
8 # are also available at http://subversion.tigris.org/license-1.html.
9 # If newer versions of this license are posted there, you may use a
10 # newer version instead, at your option.
12 # This software consists of voluntary contributions made by many
13 # individuals. For exact contribution history, see the revision
14 # history and logs, available at http://cvs2svn.tigris.org/.
15 # ====================================================================
17 """This module manages cvs2svn run options."""
23 from cvs2svn_lib
.version
import VERSION
24 from cvs2svn_lib
import config
25 from cvs2svn_lib
.common
import warning_prefix
26 from cvs2svn_lib
.common
import error_prefix
27 from cvs2svn_lib
.common
import FatalError
28 from cvs2svn_lib
.common
import normalize_svn_path
29 from cvs2svn_lib
.log
import Log
30 from cvs2svn_lib
.context
import Ctx
31 from cvs2svn_lib
.run_options
import not_both
32 from cvs2svn_lib
.run_options
import RunOptions
33 from cvs2svn_lib
.run_options
import ContextOption
34 from cvs2svn_lib
.run_options
import IncompatibleOption
35 from cvs2svn_lib
.project
import Project
36 from cvs2svn_lib
.svn_output_option
import DumpfileOutputOption
37 from cvs2svn_lib
.svn_output_option
import ExistingRepositoryOutputOption
38 from cvs2svn_lib
.svn_output_option
import NewRepositoryOutputOption
39 from cvs2svn_lib
.symbol_strategy
import TrunkPathRule
40 from cvs2svn_lib
.symbol_strategy
import BranchesPathRule
41 from cvs2svn_lib
.symbol_strategy
import TagsPathRule
44 class SVNRunOptions(RunOptions
):
45 short_desc
= 'convert a CVS repository into a Subversion repository'
49 [\\fIOPTION\\fR]... \\fIOUTPUT-OPTION CVS-REPOS-PATH\\fR
52 [\\fIOPTION\\fR]... \\fI--options=PATH\\fR
56 Create a new Subversion repository based on the version history stored in a
57 CVS repository. Each CVS commit will be mirrored in the Subversion
58 repository, including such information as date of commit and id of the
61 \\fICVS-REPOS-PATH\\fR is the filesystem path of the part of the CVS
62 repository that you want to convert. It is not possible to convert a
63 CVS repository to which you only have remote access; see the FAQ for
64 more information. This path doesn't have to be the top level
65 directory of a CVS repository; it can point at a project within a
66 repository, in which case only that project will be converted. This
67 path or one of its parent directories has to contain a subdirectory
68 called CVSROOT (though the CVSROOT directory can be empty).
70 Multiple CVS repositories can be converted into a single Subversion
71 repository in a single run of cvs2svn, but only by using an
72 \\fB--options\\fR file.
76 A directory called \\fIcvs2svn-tmp\\fR (or the directory specified by
77 \\fB--tmpdir\\fR) is used as scratch space for temporary data files.
86 def _get_output_options_group(self
):
87 group
= super(SVNRunOptions
, self
)._get
_output
_options
_group
()
89 group
.add_option(IncompatibleOption(
90 '--svnrepos', '-s', type='string',
92 help='path where SVN repos should be created',
94 'Write the output of the conversion into a Subversion repository '
95 'located at \\fIpath\\fR. This option causes a new Subversion '
96 'repository to be created at \\fIpath\\fR unless the '
97 '\\fB--existing-svnrepos\\fR option is also used.'
101 self
.parser
.set_default('existing_svnrepos', False)
102 group
.add_option(IncompatibleOption(
103 '--existing-svnrepos',
105 help='load into existing SVN repository (for use with --svnrepos)',
107 'Load the converted CVS repository into an existing Subversion '
108 'repository, instead of creating a new repository. (This option '
109 'should be used in combination with '
110 '\\fB-s\\fR/\\fB--svnrepos\\fR.) The repository must either be '
111 'empty or contain no paths that overlap with those that will '
112 'result from the conversion. Please note that you need write '
113 'permission for the repository files.'
116 group
.add_option(IncompatibleOption(
117 '--fs-type', type='string',
120 'pass --fs-type=TYPE to "svnadmin create" (for use with '
124 'Pass \\fI--fs-type\\fR=\\fItype\\fR to "svnadmin create" when '
125 'creating a new repository.'
129 self
.parser
.set_default('bdb_txn_nosync', False)
130 group
.add_option(IncompatibleOption(
134 'pass --bdb-txn-nosync to "svnadmin create" (for use with '
138 'Pass \\fI--bdb-txn-nosync\\fR to "svnadmin create" when '
139 'creating a new BDB-style Subversion repository.'
142 self
.parser
.set_default('create_options', [])
143 group
.add_option(IncompatibleOption(
144 '--create-option', type='string',
145 action
='append', dest
='create_options',
146 help='pass OPT to "svnadmin create" (for use with --svnrepos)',
148 'Pass \\fIopt\\fR to "svnadmin create" when creating a new '
149 'Subversion repository (can be specified multiple times to '
150 'pass multiple options).'
154 group
.add_option(IncompatibleOption(
155 '--dumpfile', type='string',
157 help='just produce a dumpfile; don\'t commit to a repos',
159 'Just produce a dumpfile; don\'t commit to an SVN repository. '
160 'Write the dumpfile to \\fIpath\\fR.'
165 group
.add_option(ContextOption(
169 'do not create a repository or a dumpfile; just print what '
173 'Do not create a repository or a dumpfile; just print the '
174 'details of what cvs2svn would do if it were really converting '
179 # Deprecated options:
180 self
.parser
.set_default('dump_only', False)
181 group
.add_option(IncompatibleOption(
183 action
='callback', callback
=self
.callback_dump_only
,
184 help=optparse
.SUPPRESS_HELP
,
185 man_help
=optparse
.SUPPRESS_HELP
,
187 group
.add_option(IncompatibleOption(
189 action
='callback', callback
=self
.callback_create
,
190 help=optparse
.SUPPRESS_HELP
,
191 man_help
=optparse
.SUPPRESS_HELP
,
196 def _get_conversion_options_group(self
):
197 group
= super(SVNRunOptions
, self
)._get
_conversion
_options
_group
()
199 self
.parser
.set_default('trunk_base', config
.DEFAULT_TRUNK_BASE
)
200 group
.add_option(IncompatibleOption(
201 '--trunk', type='string',
202 action
='store', dest
='trunk_base',
204 'path for trunk (default: %s)'
205 % (config
.DEFAULT_TRUNK_BASE
,)
208 'Set the top-level path to use for trunk in the Subversion '
209 'repository. The default is \\fI%s\\fR.'
210 % (config
.DEFAULT_TRUNK_BASE
,)
214 self
.parser
.set_default('branches_base', config
.DEFAULT_BRANCHES_BASE
)
215 group
.add_option(IncompatibleOption(
216 '--branches', type='string',
217 action
='store', dest
='branches_base',
219 'path for branches (default: %s)'
220 % (config
.DEFAULT_BRANCHES_BASE
,)
223 'Set the top-level path to use for branches in the Subversion '
224 'repository. The default is \\fI%s\\fR.'
225 % (config
.DEFAULT_BRANCHES_BASE
,)
229 self
.parser
.set_default('tags_base', config
.DEFAULT_TAGS_BASE
)
230 group
.add_option(IncompatibleOption(
231 '--tags', type='string',
232 action
='store', dest
='tags_base',
234 'path for tags (default: %s)'
235 % (config
.DEFAULT_TAGS_BASE
,)
238 'Set the top-level path to use for tags in the Subversion '
239 'repository. The default is \\fI%s\\fR.'
240 % (config
.DEFAULT_TAGS_BASE
,)
244 group
.add_option(ContextOption(
245 '--include-empty-directories',
246 action
='store_true', dest
='include_empty_directories',
248 'include empty directories within the CVS repository '
252 'Treat empty subdirectories within the CVS repository as actual '
253 'directories, creating them when the parent directory is created '
254 'and removing them if and when the parent directory is pruned.'
257 group
.add_option(ContextOption(
259 action
='store_false', dest
='prune',
260 help='don\'t prune empty directories',
262 'When all files are deleted from a directory in the Subversion '
263 'repository, don\'t delete the empty directory (the default is '
264 'to delete any empty directories).'
267 group
.add_option(ContextOption(
268 '--no-cross-branch-commits',
269 action
='store_false', dest
='cross_branch_commits',
270 help='prevent the creation of cross-branch commits',
272 'Prevent the creation of commits that affect files on multiple '
279 def _get_extraction_options_group(self
):
280 group
= super(SVNRunOptions
, self
)._get
_extraction
_options
_group
()
281 self
._add
_use
_internal
_co
_option
(group
)
282 self
._add
_use
_cvs
_option
(group
)
283 self
._add
_use
_rcs
_option
(group
)
286 def _get_environment_options_group(self
):
287 group
= super(SVNRunOptions
, self
)._get
_environment
_options
_group
()
289 group
.add_option(ContextOption(
290 '--svnadmin', type='string',
291 action
='store', dest
='svnadmin_executable',
292 help='path to the "svnadmin" program',
294 'Path to the \\fIsvnadmin\\fR program. (\\fIsvnadmin\\fR is '
295 'needed when the \\fB-s\\fR/\\fB--svnrepos\\fR output option is '
303 def callback_dump_only(self
, option
, opt_str
, value
, parser
):
304 parser
.values
.dump_only
= True
307 ': The --dump-only option is deprecated (it is implied '
311 def callback_create(self
, option
, opt_str
, value
, parser
):
314 ': The behaviour produced by the --create option is now the '
316 'passing the option is deprecated.\n'
319 def process_extraction_options(self
):
320 """Process options related to extracting data from the CVS repository."""
321 self
.process_all_extraction_options()
323 def process_output_options(self
):
324 """Process the options related to SVN output."""
327 options
= self
.options
329 if options
.dump_only
and not options
.dumpfile
:
330 raise FatalError("'--dump-only' requires '--dumpfile' to be specified.")
332 if not options
.svnrepos
and not options
.dumpfile
and not ctx
.dry_run
:
333 raise FatalError("must pass one of '-s' or '--dumpfile'.")
335 not_both(options
.svnrepos
, '-s',
336 options
.dumpfile
, '--dumpfile')
338 not_both(options
.dumpfile
, '--dumpfile',
339 options
.existing_svnrepos
, '--existing-svnrepos')
341 not_both(options
.bdb_txn_nosync
, '--bdb-txn-nosync',
342 options
.existing_svnrepos
, '--existing-svnrepos')
344 not_both(options
.dumpfile
, '--dumpfile',
345 options
.bdb_txn_nosync
, '--bdb-txn-nosync')
347 not_both(options
.fs_type
, '--fs-type',
348 options
.existing_svnrepos
, '--existing-svnrepos')
352 and options
.fs_type
!= 'bdb'
353 and options
.bdb_txn_nosync
355 raise FatalError("cannot pass --bdb-txn-nosync with --fs-type=%s."
359 if options
.existing_svnrepos
:
360 ctx
.output_option
= ExistingRepositoryOutputOption(options
.svnrepos
)
362 ctx
.output_option
= NewRepositoryOutputOption(
364 fs_type
=options
.fs_type
, bdb_txn_nosync
=options
.bdb_txn_nosync
,
365 create_options
=options
.create_options
)
367 ctx
.output_option
= DumpfileOutputOption(options
.dumpfile
)
371 project_cvs_repos_path
,
372 trunk_path
=None, branches_path
=None, tags_path
=None,
373 initial_directories
=[],
374 symbol_transforms
=None,
375 symbol_strategy_rules
=[],
377 """Add a project to be converted.
379 Most arguments are passed straight through to the Project
380 constructor. SYMBOL_STRATEGY_RULES is an iterable of
381 SymbolStrategyRules that will be applied to symbols in this
384 if trunk_path
is not None:
385 trunk_path
= normalize_svn_path(trunk_path
, allow_empty
=True)
386 if branches_path
is not None:
387 branches_path
= normalize_svn_path(branches_path
, allow_empty
=False)
388 if tags_path
is not None:
389 tags_path
= normalize_svn_path(tags_path
, allow_empty
=False)
391 initial_directories
= [
393 for path
in [trunk_path
, branches_path
, tags_path
]
396 normalize_svn_path(path
)
397 for path
in initial_directories
400 symbol_strategy_rules
= list(symbol_strategy_rules
)
402 # Add rules to set the SVN paths for LODs depending on whether
403 # they are the trunk, tags, or branches:
404 if trunk_path
is not None:
405 symbol_strategy_rules
.append(TrunkPathRule(trunk_path
))
406 if branches_path
is not None:
407 symbol_strategy_rules
.append(BranchesPathRule(branches_path
))
408 if tags_path
is not None:
409 symbol_strategy_rules
.append(TagsPathRule(tags_path
))
411 id = len(self
.projects
)
414 project_cvs_repos_path
,
415 initial_directories
=initial_directories
,
416 symbol_transforms
=symbol_transforms
,
419 self
.projects
.append(project
)
420 self
.project_symbol_strategy_rules
.append(symbol_strategy_rules
)
422 def clear_projects(self
):
423 """Clear the list of projects to be converted.
425 This method is for the convenience of options files, which may
426 want to import one another."""
429 del self
.project_symbol_strategy_rules
[:]
431 def process_options(self
):
432 # Consistency check for options and arguments.
433 if len(self
.args
) == 0:
437 if len(self
.args
) > 1:
438 Log().error(error_prefix
+ ": must pass only one CVS repository.\n")
442 cvsroot
= self
.args
[0]
444 self
.process_extraction_options()
445 self
.process_output_options()
446 self
.process_symbol_strategy_options()
447 self
.process_property_setter_options()
449 # Create the default project (using ctx.trunk, ctx.branches, and
453 trunk_path
=self
.options
.trunk_base
,
454 branches_path
=self
.options
.branches_base
,
455 tags_path
=self
.options
.tags_base
,
456 symbol_transforms
=self
.options
.symbol_transforms
,
457 symbol_strategy_rules
=self
.options
.symbol_strategy_rules
,