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 contains classes to set common cvs2xxx run options."""
22 from optparse
import OptionGroup
25 from cvs2svn_lib
.version
import VERSION
26 from cvs2svn_lib
import config
27 from cvs2svn_lib
.common
import warning_prefix
28 from cvs2svn_lib
.common
import error_prefix
29 from cvs2svn_lib
.common
import FatalError
30 from cvs2svn_lib
.common
import CVSTextDecoder
31 from cvs2svn_lib
.log
import Log
32 from cvs2svn_lib
.context
import Ctx
33 from cvs2svn_lib
.man_writer
import ManOption
34 from cvs2svn_lib
.pass_manager
import InvalidPassError
35 from cvs2svn_lib
.symbol_strategy
import AllBranchRule
36 from cvs2svn_lib
.symbol_strategy
import AllTagRule
37 from cvs2svn_lib
.symbol_strategy
import BranchIfCommitsRule
38 from cvs2svn_lib
.symbol_strategy
import ExcludeRegexpStrategyRule
39 from cvs2svn_lib
.symbol_strategy
import ForceBranchRegexpStrategyRule
40 from cvs2svn_lib
.symbol_strategy
import ForceTagRegexpStrategyRule
41 from cvs2svn_lib
.symbol_strategy
import ExcludeTrivialImportBranchRule
42 from cvs2svn_lib
.symbol_strategy
import HeuristicStrategyRule
43 from cvs2svn_lib
.symbol_strategy
import UnambiguousUsageRule
44 from cvs2svn_lib
.symbol_strategy
import HeuristicPreferredParentRule
45 from cvs2svn_lib
.symbol_strategy
import SymbolHintsFileRule
46 from cvs2svn_lib
.symbol_transform
import ReplaceSubstringsSymbolTransform
47 from cvs2svn_lib
.symbol_transform
import RegexpSymbolTransform
48 from cvs2svn_lib
.symbol_transform
import NormalizePathsSymbolTransform
49 from cvs2svn_lib
.property_setters
import AutoPropsPropertySetter
50 from cvs2svn_lib
.property_setters
import CVSBinaryFileDefaultMimeTypeSetter
51 from cvs2svn_lib
.property_setters
import CVSBinaryFileEOLStyleSetter
52 from cvs2svn_lib
.property_setters
import CVSRevisionNumberSetter
53 from cvs2svn_lib
.property_setters
import DefaultEOLStyleSetter
54 from cvs2svn_lib
.property_setters
import EOLStyleFromMimeTypeSetter
55 from cvs2svn_lib
.property_setters
import ExecutablePropertySetter
56 from cvs2svn_lib
.property_setters
import KeywordsPropertySetter
57 from cvs2svn_lib
.property_setters
import MimeMapper
58 from cvs2svn_lib
.property_setters
import SVNBinaryFileKeywordsPropertySetter
62 Usage: %prog --options OPTIONFILE
63 %prog [OPTION...] OUTPUT-OPTION CVS-REPOS-PATH"""
66 Convert a CVS repository into a Subversion repository, including history.
72 C. Michael Pilato <cmpilato@collab.net>
74 Greg Stein <gstein@lyra.org>
76 Branko \u010cibej <brane@xbc.nu>
78 Blair Zajac <blair@orcaware.com>
80 Max Bowsher <maxb@ukf.net>
82 Brian Fitzpatrick <fitz@red-bean.com>
84 Tobias Ringstr\u00f6m <tobias@ringstrom.mine.nu>
86 Karl Fogel <kfogel@collab.net>
88 Erik H\u00fclsmann <e.huelsmann@gmx.net>
90 David Summers <david@summersoft.fay.ar.us>
92 Michael Haggerty <mhagger@alum.mit.edu>
94 Manpage was written for the Debian GNU/Linux system by
95 Laszlo 'GCS' Boszormenyi <gcs@lsc.hu> (but may be used by others).
99 class IncompatibleOption(ManOption
):
100 """A ManOption that is incompatible with the --options option.
102 Record that the option was used so that error checking can later be
105 def __init__(self
, *args
, **kw
):
106 ManOption
.__init
__(self
, *args
, **kw
)
108 def take_action(self
, action
, dest
, opt
, value
, values
, parser
):
109 oio
= parser
.values
.options_incompatible_options
112 return ManOption
.take_action(
113 self
, action
, dest
, opt
, value
, values
, parser
117 class ContextOption(ManOption
):
118 """A ManOption that stores its value to Ctx."""
120 def __init__(self
, *args
, **kw
):
121 if kw
.get('action') not in self
.STORE_ACTIONS
:
122 raise ValueError('Invalid action: %s' % (kw
['action'],))
124 self
.__compatible
_with
_option
= kw
.pop('compatible_with_option', False)
125 self
.__action
= kw
.pop('action')
127 self
.__dest
= kw
.pop('dest')
130 if not opt
.startswith('--'):
132 self
.__dest
= opt
[2:].replace('-', '_')
134 self
.__const
= kw
.pop('const')
136 kw
['action'] = 'callback'
137 kw
['callback'] = self
.__callback
139 ManOption
.__init
__(self
, *args
, **kw
)
141 def __callback(self
, option
, opt_str
, value
, parser
):
142 if not self
.__compatible
_with
_option
:
143 oio
= parser
.values
.options_incompatible_options
144 if opt_str
not in oio
:
147 action
= self
.__action
150 if action
== "store":
151 setattr(Ctx(), dest
, value
)
152 elif action
== "store_const":
153 setattr(Ctx(), dest
, self
.__const
)
154 elif action
== "store_true":
155 setattr(Ctx(), dest
, True)
156 elif action
== "store_false":
157 setattr(Ctx(), dest
, False)
158 elif action
== "append":
159 getattr(Ctx(), dest
).append(value
)
160 elif action
== "count":
161 setattr(Ctx(), dest
, getattr(Ctx(), dest
, 0) + 1)
163 raise RuntimeError("unknown action %r" % self
.__action
)
168 class IncompatibleOptionsException(FatalError
):
172 # Options that are not allowed to be used with --trunk-only:
174 '--symbol-transform',
179 '--keep-trivial-imports',
181 '--no-cross-branch-commits',
184 class SymbolOptionsWithTrunkOnlyException(IncompatibleOptionsException
):
186 IncompatibleOptionsException
.__init
__(
188 'The following symbol-related options cannot be used together\n'
189 'with --trunk-only:\n'
191 % ('\n '.join(SYMBOL_OPTIONS
),)
195 def not_both(opt1val
, opt1name
, opt2val
, opt2name
):
196 """Raise an exception if both opt1val and opt2val are set."""
197 if opt1val
and opt2val
:
198 raise IncompatibleOptionsException(
199 "cannot pass both '%s' and '%s'." % (opt1name
, opt2name
,)
203 class RunOptions(object):
204 """A place to store meta-options that are used to start the conversion."""
206 def __init__(self
, progname
, cmd_args
, pass_manager
):
207 """Process the command-line options, storing run options to SELF.
209 PROGNAME is the name of the program, used in the usage string.
210 CMD_ARGS is the list of command-line arguments passed to the
211 program. PASS_MANAGER is an instance of PassManager, needed to
212 help process the -p and --help-passes options."""
214 self
.progname
= progname
215 self
.cmd_args
= cmd_args
216 self
.pass_manager
= pass_manager
218 self
.end_pass
= self
.pass_manager
.num_passes
219 self
.profiling
= False
223 # A list of one list of SymbolStrategyRules for each project:
224 self
.project_symbol_strategy_rules
= []
226 parser
= self
.parser
= optparse
.OptionParser(
228 description
=self
.get_description(),
229 add_help_option
=False,
231 # A place to record any options used that are incompatible with
233 parser
.set_default('options_incompatible_options', [])
235 # Populate the options parser with the options, one group at a
237 parser
.add_option_group(self
._get
_options
_file
_options
_group
())
238 parser
.add_option_group(self
._get
_output
_options
_group
())
239 parser
.add_option_group(self
._get
_conversion
_options
_group
())
240 parser
.add_option_group(self
._get
_symbol
_handling
_options
_group
())
241 parser
.add_option_group(self
._get
_subversion
_properties
_options
_group
())
242 parser
.add_option_group(self
._get
_extraction
_options
_group
())
243 parser
.add_option_group(self
._get
_environment
_options
_group
())
244 parser
.add_option_group(self
._get
_partial
_conversion
_options
_group
())
245 parser
.add_option_group(self
._get
_information
_options
_group
())
247 (self
.options
, self
.args
) = parser
.parse_args(args
=self
.cmd_args
)
249 # Now the log level has been set; log the time when the run started:
252 'Conversion start time: %Y-%m-%d %I:%M:%S %Z',
253 time
.localtime(Log().start_time
)
257 if self
.options
.options_file_found
:
258 # Check that no options that are incompatible with --options
260 self
.verify_option_compatibility()
262 # --options was not specified. So do the main initialization
263 # based on other command-line options:
264 self
.process_options()
266 # Check for problems with the options:
269 def get_description(self
):
272 def _get_options_file_options_group(self
):
274 self
.parser
, 'Configuration via options file'
276 self
.parser
.set_default('options_file_found', False)
277 group
.add_option(ManOption(
278 '--options', type='string',
279 action
='callback', callback
=self
.callback_options
,
281 'read the conversion options from PATH. This '
282 'method allows more flexibility than using '
283 'command-line options. See documentation for info'
286 'Read the conversion options from \\fIpath\\fR instead of from '
287 'the command line. This option allows far more conversion '
288 'flexibility than can be achieved using the command-line alone. '
289 'See the documentation for more information. Only the following '
290 'command-line options are allowed in combination with '
291 '\\fB--options\\fR: \\fB-h\\fR/\\fB--help\\fR, '
292 '\\fB--help-passes\\fR, \\fB--version\\fR, '
293 '\\fB-v\\fR/\\fB--verbose\\fR, \\fB-q\\fR/\\fB--quiet\\fR, '
294 '\\fB-p\\fR/\\fB--pass\\fR/\\fB--passes\\fR, \\fB--dry-run\\fR, '
295 '\\fB--profile\\fR, \\fB--sort\\fR, \\fB--trunk-only\\fR, '
296 '\\fB--encoding\\fR, and \\fB--fallback-encoding\\fR. '
297 'Options are processed in the order specified on the command '
304 def _get_output_options_group(self
):
305 group
= OptionGroup(self
.parser
, 'Output options')
308 def _get_conversion_options_group(self
):
309 group
= OptionGroup(self
.parser
, 'Conversion options')
310 group
.add_option(ContextOption(
313 compatible_with_option
=True,
314 help='convert only trunk commits, not tags nor branches',
316 'Convert only trunk commits, not tags nor branches.'
319 group
.add_option(ManOption(
320 '--encoding', type='string',
321 action
='callback', callback
=self
.callback_encoding
,
323 'encoding for paths and log messages in CVS repos. '
324 'If option is specified multiple times, encoders '
325 'are tried in order until one succeeds. See '
326 'http://docs.python.org/lib/standard-encodings.html '
327 'for a list of standard Python encodings.'
330 'Use \\fIencoding\\fR as the encoding for filenames, log '
331 'messages, and author names in the CVS repos. This option '
332 'may be specified multiple times, in which case the encodings '
333 'are tried in order until one succeeds. Default: ascii. See '
334 'http://docs.python.org/lib/standard-encodings.html for a list '
335 'of other standard encodings.'
339 group
.add_option(ManOption(
340 '--fallback-encoding', type='string',
341 action
='callback', callback
=self
.callback_fallback_encoding
,
342 help='If all --encodings fail, use lossy encoding with ENC',
344 'If none of the encodings specified with \\fB--encoding\\fR '
345 'succeed in decoding an author name or log message, then fall '
346 'back to using \\fIencoding\\fR in lossy \'replace\' mode. '
347 'Use of this option may cause information to be lost, but at '
348 'least it allows the conversion to run to completion. This '
349 'option only affects the encoding of log messages and author '
350 'names; there is no fallback encoding for filenames. (By '
351 'using an \\fB--options\\fR file, it is possible to specify '
352 'a fallback encoding for filenames.) Default: disabled.'
356 group
.add_option(ContextOption(
357 '--retain-conflicting-attic-files',
360 'if a file appears both in and out of '
361 'the CVS Attic, then leave the attic version in a '
362 'SVN directory called "Attic"'
365 'If a file appears both inside an outside of the CVS attic, '
366 'retain the attic version in an SVN subdirectory called '
367 '\'Attic\'. (Normally this situation is treated as a fatal '
374 def _get_symbol_handling_options_group(self
):
375 group
= OptionGroup(self
.parser
, 'Symbol handling')
376 self
.parser
.set_default('symbol_transforms', [])
377 group
.add_option(IncompatibleOption(
378 '--symbol-transform', type='string',
379 action
='callback', callback
=self
.callback_symbol_transform
,
381 'transform symbol names from P to S, where P and S '
382 'use Python regexp and reference syntax '
383 'respectively. P must match the whole symbol name'
386 'Transform RCS/CVS symbol names before entering them into '
387 'Subversion. \\fIpattern\\fR is a Python regexp pattern that '
388 'is matches against the entire symbol name; \\fIreplacement\\fR '
389 'is a replacement using Python\'s regexp reference syntax. '
390 'You may specify any number of these options; they will be '
391 'applied in the order given on the command line.'
395 self
.parser
.set_default('symbol_strategy_rules', [])
396 group
.add_option(IncompatibleOption(
397 '--symbol-hints', type='string',
398 action
='callback', callback
=self
.callback_symbol_hints
,
399 help='read symbol conversion hints from PATH',
401 'Read symbol conversion hints from \\fIpath\\fR. The format of '
402 '\\fIpath\\fR is the same as the format output by '
403 '\\fB--write-symbol-info\\fR, namely a text file with four '
404 'whitespace-separated columns: \\fIproject-id\\fR, '
405 '\\fIsymbol\\fR, \\fIconversion\\fR, and '
406 '\\fIparent-lod-name\\fR. \\fIproject-id\\fR is the numerical '
407 'ID of the project to which the symbol belongs, counting from '
408 '0. \\fIproject-id\\fR can be set to \'.\' if '
409 'project-specificity is not needed. \\fIsymbol-name\\fR is the '
410 'name of the symbol being specified. \\fIconversion\\fR '
411 'specifies how the symbol should be converted, and can be one '
412 'of the values \'branch\', \'tag\', or \'exclude\'. If '
413 '\\fIconversion\\fR is \'.\', then this rule does not affect '
414 'how the symbol is converted. \\fIparent-lod-name\\fR is the '
415 'name of the symbol from which this symbol should sprout, or '
416 '\'.trunk.\' if the symbol should sprout from trunk. If '
417 '\\fIparent-lod-name\\fR is omitted or \'.\', then this rule '
418 'does not affect the preferred parent of this symbol. The file '
419 'may contain blank lines or comment lines (lines whose first '
420 'non-whitespace character is \'#\').'
424 self
.parser
.set_default('symbol_default', 'heuristic')
425 group
.add_option(IncompatibleOption(
426 '--symbol-default', type='choice',
427 choices
=['heuristic', 'strict', 'branch', 'tag'],
430 'specify how ambiguous symbols are converted. '
431 'OPT is "heuristic" (default), "strict", "branch", '
435 'Specify how to convert ambiguous symbols (those that appear in '
436 'the CVS archive as both branches and tags). \\fIopt\\fR must '
437 'be \'heuristic\' (decide how to treat each ambiguous symbol '
438 'based on whether it was used more often as a branch/tag in '
439 'CVS), \'strict\' (no default; every ambiguous symbol has to be '
440 'resolved manually using \\fB--force-branch\\fR, '
441 '\\fB--force-tag\\fR, or \\fB--exclude\\fR), \'branch\' (treat '
442 'every ambiguous symbol as a branch), or \'tag\' (treat every '
443 'ambiguous symbol as a tag). The default is \'heuristic\'.'
447 group
.add_option(IncompatibleOption(
448 '--force-branch', type='string',
449 action
='callback', callback
=self
.callback_force_branch
,
450 help='force symbols matching REGEXP to be branches',
452 'Force symbols whose names match \\fIregexp\\fR to be branches. '
453 '\\fIregexp\\fR must match the whole symbol name.'
457 group
.add_option(IncompatibleOption(
458 '--force-tag', type='string',
459 action
='callback', callback
=self
.callback_force_tag
,
460 help='force symbols matching REGEXP to be tags',
462 'Force symbols whose names match \\fIregexp\\fR to be tags. '
463 '\\fIregexp\\fR must match the whole symbol name.'
467 group
.add_option(IncompatibleOption(
468 '--exclude', type='string',
469 action
='callback', callback
=self
.callback_exclude
,
470 help='exclude branches and tags matching REGEXP',
472 'Exclude branches and tags whose names match \\fIregexp\\fR '
473 'from the conversion. \\fIregexp\\fR must match the whole '
478 self
.parser
.set_default('keep_trivial_imports', False)
479 group
.add_option(IncompatibleOption(
480 '--keep-trivial-imports',
483 'do not exclude branches that were only used for '
484 'a single import (usually these are unneeded)'
487 'Do not exclude branches that were only used for a single '
488 'import. (By default such branches are excluded because they '
489 'are usually created by the inappropriate use of \\fBcvs '
496 def _get_subversion_properties_options_group(self
):
497 group
= OptionGroup(self
.parser
, 'Subversion properties')
498 group
.add_option(ContextOption(
499 '--username', type='string',
501 help='username for cvs2svn-synthesized commits',
503 'Set the default username to \\fIname\\fR when cvs2svn needs '
504 'to generate a commit for which CVS does not record the '
505 'original username. This happens when a branch or tag is '
506 'created. The default is to use no author at all for such '
511 self
.parser
.set_default('auto_props_files', [])
512 group
.add_option(IncompatibleOption(
513 '--auto-props', type='string',
514 action
='append', dest
='auto_props_files',
516 'set file properties from the auto-props section '
517 'of a file in svn config format'
520 'Specify a file in the format of Subversion\'s config file, '
521 'whose [auto-props] section can be used to set arbitrary '
522 'properties on files in the Subversion repository based on '
523 'their filenames. (The [auto-props] section header must be '
524 'present; other sections of the config file, including the '
525 'enable-auto-props setting, are ignored.) Filenames are matched '
526 'to the filename patterns case-insensitively.'
531 self
.parser
.set_default('mime_types_files', [])
532 group
.add_option(IncompatibleOption(
533 '--mime-types', type='string',
534 action
='append', dest
='mime_types_files',
536 'specify an apache-style mime.types file for setting '
540 'Specify an apache-style mime.types \\fIfile\\fR for setting '
545 self
.parser
.set_default('eol_from_mime_type', False)
546 group
.add_option(IncompatibleOption(
547 '--eol-from-mime-type',
549 help='set svn:eol-style from mime type if known',
551 'For files that don\'t have the kb expansion mode but have a '
552 'known mime type, set the eol-style based on the mime type. '
553 'For such files, set svn:eol-style to "native" if the mime type '
554 'begins with "text/", and leave it unset (i.e., no EOL '
555 'translation) otherwise. Files with unknown mime types are '
556 'not affected by this option. This option has no effect '
557 'unless the \\fB--mime-types\\fR option is also specified.'
560 group
.add_option(IncompatibleOption(
561 '--default-eol', type='choice',
562 choices
=['binary', 'native', 'CRLF', 'LF', 'CR'],
565 'default svn:eol-style for non-binary files with '
566 'undetermined mime types. STYLE is "binary" '
567 '(default), "native", "CRLF", "LF", or "CR"'
570 'Set svn:eol-style to \\fIstyle\\fR for files that don\'t have '
571 'the CVS \'kb\' expansion mode and whose end-of-line '
572 'translation mode hasn\'t been determined by one of the other '
573 'options. \\fIstyle\\fR must be \'binary\' (default), '
574 '\'native\', \'CRLF\', \'LF\', or \'CR\'.'
578 self
.parser
.set_default('keywords_off', False)
579 group
.add_option(IncompatibleOption(
583 'don\'t set svn:keywords on any files (by default, '
584 'cvs2svn sets svn:keywords on non-binary files to "%s")'
585 % (config
.SVN_KEYWORDS_VALUE
,)
588 'By default, cvs2svn sets svn:keywords on CVS files to "author '
589 'id date" if the mode of the RCS file in question is either kv, '
590 'kvl or unset. If you use the --keywords-off switch, cvs2svn '
591 'will not set svn:keywords for any file. While this will not '
592 'touch the keywords in the contents of your files, Subversion '
593 'will not expand them.'
596 group
.add_option(ContextOption(
600 'keep .cvsignore files (in addition to creating '
601 'the analogous svn:ignore properties)'
604 'Include \\fI.cvsignore\\fR files in the output. (Normally '
605 'they are unneeded because cvs2svn sets the corresponding '
606 '\\fIsvn:ignore\\fR properties.)'
609 group
.add_option(IncompatibleOption(
611 action
='callback', callback
=self
.callback_cvs_revnums
,
612 help='record CVS revision numbers as file properties',
614 'Record CVS revision numbers as file properties in the '
615 'Subversion repository. (Note that unless it is removed '
616 'explicitly, the last CVS revision number will remain '
617 'associated with the file even after the file is changed '
618 'within Subversion.)'
622 # Deprecated options:
623 group
.add_option(IncompatibleOption(
625 action
='store_const', dest
='default_eol', const
=None,
626 help=optparse
.SUPPRESS_HELP
,
627 man_help
=optparse
.SUPPRESS_HELP
,
629 self
.parser
.set_default('auto_props_ignore_case', True)
630 # True is the default now, so this option has no effect:
631 group
.add_option(IncompatibleOption(
632 '--auto-props-ignore-case',
634 help=optparse
.SUPPRESS_HELP
,
635 man_help
=optparse
.SUPPRESS_HELP
,
640 def _get_extraction_options_group(self
):
641 group
= OptionGroup(self
.parser
, 'Extraction options')
645 def _get_environment_options_group(self
):
646 group
= OptionGroup(self
.parser
, 'Environment options')
647 group
.add_option(ContextOption(
648 '--tmpdir', type='string',
651 'directory to use for temporary data files '
652 '(default "cvs2svn-tmp")'
655 'Set the \\fIpath\\fR to use for temporary data. Default '
656 'is a directory called \\fIcvs2svn-tmp\\fR under the current '
661 self
.parser
.set_default('co_executable', config
.CO_EXECUTABLE
)
662 group
.add_option(IncompatibleOption(
663 '--co', type='string',
664 action
='store', dest
='co_executable',
665 help='path to the "co" program (required if --use-rcs)',
667 'Path to the \\fIco\\fR program. (\\fIco\\fR is needed if the '
668 '\\fB--use-rcs\\fR option is used.)'
672 self
.parser
.set_default('cvs_executable', config
.CVS_EXECUTABLE
)
673 group
.add_option(IncompatibleOption(
674 '--cvs', type='string',
675 action
='store', dest
='cvs_executable',
676 help='path to the "cvs" program (required if --use-cvs)',
678 'Path to the \\fIcvs\\fR program. (\\fIcvs\\fR is needed if the '
679 '\\fB--use-cvs\\fR option is used.)'
683 group
.add_option(ContextOption(
684 '--sort', type='string',
685 action
='store', dest
='sort_executable',
686 compatible_with_option
=True,
687 help='path to the GNU "sort" program',
689 'Path to the GNU \\fIsort\\fR program. (cvs2svn requires GNU '
697 def _get_partial_conversion_options_group(self
):
698 group
= OptionGroup(self
.parser
, 'Partial conversions')
699 group
.add_option(ManOption(
700 '--pass', type='string',
701 action
='callback', callback
=self
.callback_passes
,
702 help='execute only specified PASS of conversion',
704 'Execute only pass \\fIpass\\fR of the conversion. '
705 '\\fIpass\\fR can be specified by name or by number (see '
706 '\\fB--help-passes\\fR).'
710 group
.add_option(ManOption(
711 '--passes', '-p', type='string',
712 action
='callback', callback
=self
.callback_passes
,
714 'execute passes START through END, inclusive (PASS, '
715 'START, and END can be pass names or numbers)'
718 'Execute passes \\fIstart\\fR through \\fIend\\fR of the '
719 'conversion (inclusive). \\fIstart\\fR and \\fIend\\fR can be '
720 'specified by name or by number (see \\fB--help-passes\\fR). '
721 'If \\fIstart\\fR or \\fIend\\fR is missing, it defaults to '
722 'the first or last pass, respectively. For this to work the '
723 'earlier passes must have been completed before on the '
724 'same CVS repository, and the generated data files must be '
725 'in the temporary directory (see \\fB--tmpdir\\fR).'
727 metavar
='[START]:[END]',
732 def _get_information_options_group(self
):
733 group
= OptionGroup(self
.parser
, 'Information options')
734 group
.add_option(ManOption(
736 action
='callback', callback
=self
.callback_version
,
737 help='print the version number',
738 man_help
='Print the version number.',
740 group
.add_option(ManOption(
743 help='print this usage message and exit with success',
744 man_help
='Print the usage message and exit with success.',
746 group
.add_option(ManOption(
748 action
='callback', callback
=self
.callback_help_passes
,
749 help='list the available passes and their numbers',
751 'Print the numbers and names of the conversion passes and '
755 group
.add_option(ManOption(
757 action
='callback', callback
=self
.callback_manpage
,
758 help='write the manpage for this program to standard output',
760 'Output the unix-style manpage for this program to standard '
764 group
.add_option(ManOption(
766 action
='callback', callback
=self
.callback_verbose
,
767 help='verbose (may be specified twice for debug output)',
769 'Print more information while running. This option may be '
770 'specified twice to output voluminous debugging information.'
773 group
.add_option(ManOption(
775 action
='callback', callback
=self
.callback_quiet
,
776 help='quiet (may be specified twice for very quiet)',
778 'Print less information while running. This option may be '
779 'specified twice to suppress all non-error output.'
782 group
.add_option(ContextOption(
783 '--write-symbol-info', type='string',
784 action
='store', dest
='symbol_info_filename',
785 help='write information and statistics about CVS symbols to PATH.',
787 'Write to \\fIpath\\fR symbol statistics and information about '
788 'how symbols were converted during CollateSymbolsPass.'
792 group
.add_option(ContextOption(
795 help='prevent the deletion of intermediate files',
796 man_help
='Prevent the deletion of temporary files.',
798 group
.add_option(ManOption(
800 action
='callback', callback
=self
.callback_profile
,
801 help='profile with \'hotshot\' (into file cvs2svn.hotshot)',
803 'Profile with \'hotshot\' (into file \\fIcvs2svn.hotshot\\fR).'
809 def callback_options(self
, option
, opt_str
, value
, parser
):
810 parser
.values
.options_file_found
= True
811 self
.process_options_file(value
)
813 def callback_encoding(self
, option
, opt_str
, value
, parser
):
817 ctx
.cvs_author_decoder
.add_encoding(value
)
818 ctx
.cvs_log_decoder
.add_encoding(value
)
819 ctx
.cvs_filename_decoder
.add_encoding(value
)
820 except LookupError, e
:
821 raise FatalError(str(e
))
823 def callback_fallback_encoding(self
, option
, opt_str
, value
, parser
):
827 ctx
.cvs_author_decoder
.set_fallback_encoding(value
)
828 ctx
.cvs_log_decoder
.set_fallback_encoding(value
)
829 # Don't use fallback_encoding for filenames.
830 except LookupError, e
:
831 raise FatalError(str(e
))
833 def callback_help_passes(self
, option
, opt_str
, value
, parser
):
834 self
.pass_manager
.help_passes()
837 def callback_manpage(self
, option
, opt_str
, value
, parser
):
838 raise NotImplementedError()
840 def callback_version(self
, option
, opt_str
, value
, parser
):
842 '%s version %s\n' % (self
.progname
, VERSION
)
846 def callback_verbose(self
, option
, opt_str
, value
, parser
):
847 Log().increase_verbosity()
849 def callback_quiet(self
, option
, opt_str
, value
, parser
):
850 Log().decrease_verbosity()
852 def callback_passes(self
, option
, opt_str
, value
, parser
):
853 if value
.find(':') >= 0:
854 start_pass
, end_pass
= value
.split(':')
855 self
.start_pass
= self
.pass_manager
.get_pass_number(start_pass
, 1)
856 self
.end_pass
= self
.pass_manager
.get_pass_number(
857 end_pass
, self
.pass_manager
.num_passes
862 self
.pass_manager
.get_pass_number(value
)
864 def callback_profile(self
, option
, opt_str
, value
, parser
):
865 self
.profiling
= True
867 def callback_symbol_hints(self
, option
, opt_str
, value
, parser
):
868 parser
.values
.symbol_strategy_rules
.append(SymbolHintsFileRule(value
))
870 def callback_force_branch(self
, option
, opt_str
, value
, parser
):
871 parser
.values
.symbol_strategy_rules
.append(
872 ForceBranchRegexpStrategyRule(value
)
875 def callback_force_tag(self
, option
, opt_str
, value
, parser
):
876 parser
.values
.symbol_strategy_rules
.append(
877 ForceTagRegexpStrategyRule(value
)
880 def callback_exclude(self
, option
, opt_str
, value
, parser
):
881 parser
.values
.symbol_strategy_rules
.append(
882 ExcludeRegexpStrategyRule(value
)
885 def callback_cvs_revnums(self
, option
, opt_str
, value
, parser
):
886 Ctx().svn_property_setters
.append(CVSRevisionNumberSetter())
888 def callback_symbol_transform(self
, option
, opt_str
, value
, parser
):
889 [pattern
, replacement
] = value
.split(":")
891 parser
.values
.symbol_transforms
.append(
892 RegexpSymbolTransform(pattern
, replacement
)
895 raise FatalError("'%s' is not a valid regexp." % (pattern
,))
897 def process_symbol_strategy_options(self
):
898 """Process symbol strategy-related options."""
901 options
= self
.options
903 # Add the standard symbol name cleanup rules:
904 self
.options
.symbol_transforms
.extend([
905 ReplaceSubstringsSymbolTransform('\\','/'),
906 # Remove leading, trailing, and repeated slashes:
907 NormalizePathsSymbolTransform(),
911 if options
.symbol_strategy_rules
or options
.keep_trivial_imports
:
912 raise SymbolOptionsWithTrunkOnlyException()
915 if not options
.keep_trivial_imports
:
916 options
.symbol_strategy_rules
.append(ExcludeTrivialImportBranchRule())
918 options
.symbol_strategy_rules
.append(UnambiguousUsageRule())
919 if options
.symbol_default
== 'strict':
921 elif options
.symbol_default
== 'branch':
922 options
.symbol_strategy_rules
.append(AllBranchRule())
923 elif options
.symbol_default
== 'tag':
924 options
.symbol_strategy_rules
.append(AllTagRule())
925 elif options
.symbol_default
== 'heuristic':
926 options
.symbol_strategy_rules
.append(BranchIfCommitsRule())
927 options
.symbol_strategy_rules
.append(HeuristicStrategyRule())
931 # Now add a rule whose job it is to pick the preferred parents of
933 options
.symbol_strategy_rules
.append(HeuristicPreferredParentRule())
935 def process_property_setter_options(self
):
936 """Process the options that set SVN properties."""
939 options
= self
.options
941 for value
in options
.auto_props_files
:
942 ctx
.svn_property_setters
.append(
943 AutoPropsPropertySetter(value
, options
.auto_props_ignore_case
)
946 for value
in options
.mime_types_files
:
947 ctx
.svn_property_setters
.append(MimeMapper(value
))
949 ctx
.svn_property_setters
.append(CVSBinaryFileEOLStyleSetter())
951 ctx
.svn_property_setters
.append(CVSBinaryFileDefaultMimeTypeSetter())
953 if options
.eol_from_mime_type
:
954 ctx
.svn_property_setters
.append(EOLStyleFromMimeTypeSetter())
956 ctx
.svn_property_setters
.append(
957 DefaultEOLStyleSetter(options
.default_eol
)
960 ctx
.svn_property_setters
.append(SVNBinaryFileKeywordsPropertySetter())
962 if not options
.keywords_off
:
963 ctx
.svn_property_setters
.append(
964 KeywordsPropertySetter(config
.SVN_KEYWORDS_VALUE
))
966 ctx
.svn_property_setters
.append(ExecutablePropertySetter())
968 def process_options(self
):
969 """Do the main configuration based on command-line options.
971 This method is only called if the --options option was not
974 raise NotImplementedError()
976 def check_options(self
):
977 """Check the the run options are OK.
979 This should only be called after all options have been processed."""
981 # Convenience var, so we don't have to keep instantiating this Borg.
984 if not self
.start_pass
<= self
.end_pass
:
985 raise InvalidPassError(
986 'Ending pass must not come before starting pass.')
988 if not ctx
.dry_run
and ctx
.output_option
is None:
989 raise FatalError('No output option specified.')
991 if ctx
.output_option
is not None:
992 ctx
.output_option
.check()
994 if not self
.projects
:
995 raise FatalError('No project specified.')
997 def verify_option_compatibility(self
):
998 """Verify that no options incompatible with --options were used.
1000 The --options option was specified. Verify that no incompatible
1001 options or arguments were specified."""
1003 if self
.options
.options_incompatible_options
or self
.args
:
1004 if self
.options
.options_incompatible_options
:
1005 oio
= self
.options
.options_incompatible_options
1007 '%s: The following options cannot be used in combination with '
1011 % (error_prefix
, '\n '.join(oio
))
1015 '%s: No cvs-repos-path arguments are allowed with the --options '
1021 def process_options_file(self
, options_filename
):
1022 """Read options from the file named OPTIONS_FILENAME.
1024 Store the run options to SELF."""
1028 'run_options' : self
,
1030 execfile(options_filename
, g
)
1033 self
.parser
.print_help()