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(
246 action
='store_false', dest
='prune',
247 help='don\'t prune empty directories',
249 'When all files are deleted from a directory in the Subversion '
250 'repository, don\'t delete the empty directory (the default is '
251 'to delete any empty directories).'
254 group
.add_option(ContextOption(
255 '--no-cross-branch-commits',
256 action
='store_false', dest
='cross_branch_commits',
257 help='prevent the creation of cross-branch commits',
259 'Prevent the creation of commits that affect files on multiple '
266 def _get_extraction_options_group(self
):
267 group
= super(SVNRunOptions
, self
)._get
_extraction
_options
_group
()
268 self
._add
_use
_internal
_co
_option
(group
)
269 self
._add
_use
_cvs
_option
(group
)
270 self
._add
_use
_rcs
_option
(group
)
273 def _get_environment_options_group(self
):
274 group
= super(SVNRunOptions
, self
)._get
_environment
_options
_group
()
276 group
.add_option(ContextOption(
277 '--svnadmin', type='string',
278 action
='store', dest
='svnadmin_executable',
279 help='path to the "svnadmin" program',
281 'Path to the \\fIsvnadmin\\fR program. (\\fIsvnadmin\\fR is '
282 'needed when the \\fB-s\\fR/\\fB--svnrepos\\fR output option is '
290 def callback_dump_only(self
, option
, opt_str
, value
, parser
):
291 parser
.values
.dump_only
= True
294 ': The --dump-only option is deprecated (it is implied '
298 def callback_create(self
, option
, opt_str
, value
, parser
):
301 ': The behaviour produced by the --create option is now the '
303 'passing the option is deprecated.\n'
306 def process_extraction_options(self
):
307 """Process options related to extracting data from the CVS repository."""
308 self
.process_all_extraction_options()
310 def process_output_options(self
):
311 """Process the options related to SVN output."""
314 options
= self
.options
316 if options
.dump_only
and not options
.dumpfile
:
317 raise FatalError("'--dump-only' requires '--dumpfile' to be specified.")
319 if not options
.svnrepos
and not options
.dumpfile
and not ctx
.dry_run
:
320 raise FatalError("must pass one of '-s' or '--dumpfile'.")
322 not_both(options
.svnrepos
, '-s',
323 options
.dumpfile
, '--dumpfile')
325 not_both(options
.dumpfile
, '--dumpfile',
326 options
.existing_svnrepos
, '--existing-svnrepos')
328 not_both(options
.bdb_txn_nosync
, '--bdb-txn-nosync',
329 options
.existing_svnrepos
, '--existing-svnrepos')
331 not_both(options
.dumpfile
, '--dumpfile',
332 options
.bdb_txn_nosync
, '--bdb-txn-nosync')
334 not_both(options
.fs_type
, '--fs-type',
335 options
.existing_svnrepos
, '--existing-svnrepos')
339 and options
.fs_type
!= 'bdb'
340 and options
.bdb_txn_nosync
342 raise FatalError("cannot pass --bdb-txn-nosync with --fs-type=%s."
346 if options
.existing_svnrepos
:
347 ctx
.output_option
= ExistingRepositoryOutputOption(options
.svnrepos
)
349 ctx
.output_option
= NewRepositoryOutputOption(
351 fs_type
=options
.fs_type
, bdb_txn_nosync
=options
.bdb_txn_nosync
,
352 create_options
=options
.create_options
)
354 ctx
.output_option
= DumpfileOutputOption(options
.dumpfile
)
358 project_cvs_repos_path
,
359 trunk_path
=None, branches_path
=None, tags_path
=None,
360 initial_directories
=[],
361 symbol_transforms
=None,
362 symbol_strategy_rules
=[],
364 """Add a project to be converted.
366 Most arguments are passed straight through to the Project
367 constructor. SYMBOL_STRATEGY_RULES is an iterable of
368 SymbolStrategyRules that will be applied to symbols in this
371 if trunk_path
is not None:
372 trunk_path
= normalize_svn_path(trunk_path
, allow_empty
=True)
373 if branches_path
is not None:
374 branches_path
= normalize_svn_path(branches_path
, allow_empty
=False)
375 if tags_path
is not None:
376 tags_path
= normalize_svn_path(tags_path
, allow_empty
=False)
378 initial_directories
= [
380 for path
in [trunk_path
, branches_path
, tags_path
]
383 normalize_svn_path(path
)
384 for path
in initial_directories
387 symbol_strategy_rules
= list(symbol_strategy_rules
)
389 # Add rules to set the SVN paths for LODs depending on whether
390 # they are the trunk, tags, or branches:
391 if trunk_path
is not None:
392 symbol_strategy_rules
.append(TrunkPathRule(trunk_path
))
393 if branches_path
is not None:
394 symbol_strategy_rules
.append(BranchesPathRule(branches_path
))
395 if tags_path
is not None:
396 symbol_strategy_rules
.append(TagsPathRule(tags_path
))
398 id = len(self
.projects
)
401 project_cvs_repos_path
,
402 initial_directories
=initial_directories
,
403 symbol_transforms
=symbol_transforms
,
406 self
.projects
.append(project
)
407 self
.project_symbol_strategy_rules
.append(symbol_strategy_rules
)
409 def clear_projects(self
):
410 """Clear the list of projects to be converted.
412 This method is for the convenience of options files, which may
413 want to import one another."""
416 del self
.project_symbol_strategy_rules
[:]
418 def process_options(self
):
419 # Consistency check for options and arguments.
420 if len(self
.args
) == 0:
424 if len(self
.args
) > 1:
425 Log().error(error_prefix
+ ": must pass only one CVS repository.\n")
429 cvsroot
= self
.args
[0]
431 self
.process_extraction_options()
432 self
.process_output_options()
433 self
.process_symbol_strategy_options()
434 self
.process_property_setter_options()
436 # Create the default project (using ctx.trunk, ctx.branches, and
440 trunk_path
=self
.options
.trunk_base
,
441 branches_path
=self
.options
.branches_base
,
442 tags_path
=self
.options
.tags_base
,
443 symbol_transforms
=self
.options
.symbol_transforms
,
444 symbol_strategy_rules
=self
.options
.symbol_strategy_rules
,