1 # (Be in -*- python -*- mode.)
3 # ====================================================================
4 # Copyright (c) 2000-2007 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 cvs2svn run options."""
26 from cvs2svn_lib
.version
import VERSION
27 from cvs2svn_lib
import config
28 from cvs2svn_lib
.common
import warning_prefix
29 from cvs2svn_lib
.common
import error_prefix
30 from cvs2svn_lib
.common
import FatalError
31 from cvs2svn_lib
.common
import CVSTextDecoder
32 from cvs2svn_lib
.log
import Log
33 from cvs2svn_lib
.context
import Ctx
34 from cvs2svn_lib
.svn_output_option
import DumpfileOutputOption
35 from cvs2svn_lib
.svn_output_option
import NewRepositoryOutputOption
36 from cvs2svn_lib
.svn_output_option
import ExistingRepositoryOutputOption
37 from cvs2svn_lib
.project
import Project
38 from cvs2svn_lib
.pass_manager
import InvalidPassError
39 from cvs2svn_lib
.revision_manager
import NullRevisionRecorder
40 from cvs2svn_lib
.revision_manager
import NullRevisionExcluder
41 from cvs2svn_lib
.rcs_revision_manager
import RCSRevisionReader
42 from cvs2svn_lib
.cvs_revision_manager
import CVSRevisionReader
43 from cvs2svn_lib
.checkout_internal
import InternalRevisionRecorder
44 from cvs2svn_lib
.checkout_internal
import InternalRevisionExcluder
45 from cvs2svn_lib
.checkout_internal
import InternalRevisionReader
46 from cvs2svn_lib
.symbol_strategy
import AllBranchRule
47 from cvs2svn_lib
.symbol_strategy
import AllTagRule
48 from cvs2svn_lib
.symbol_strategy
import BranchIfCommitsRule
49 from cvs2svn_lib
.symbol_strategy
import ExcludeRegexpStrategyRule
50 from cvs2svn_lib
.symbol_strategy
import ForceBranchRegexpStrategyRule
51 from cvs2svn_lib
.symbol_strategy
import ForceTagRegexpStrategyRule
52 from cvs2svn_lib
.symbol_strategy
import ExcludeTrivialImportBranchRule
53 from cvs2svn_lib
.symbol_strategy
import HeuristicStrategyRule
54 from cvs2svn_lib
.symbol_strategy
import UnambiguousUsageRule
55 from cvs2svn_lib
.symbol_strategy
import HeuristicPreferredParentRule
56 from cvs2svn_lib
.symbol_strategy
import SymbolHintsFileRule
57 from cvs2svn_lib
.symbol_strategy
import TrunkPathRule
58 from cvs2svn_lib
.symbol_strategy
import BranchesPathRule
59 from cvs2svn_lib
.symbol_strategy
import TagsPathRule
60 from cvs2svn_lib
.symbol_transform
import ReplaceSubstringsSymbolTransform
61 from cvs2svn_lib
.symbol_transform
import RegexpSymbolTransform
62 from cvs2svn_lib
.symbol_transform
import NormalizePathsSymbolTransform
63 from cvs2svn_lib
.property_setters
import AutoPropsPropertySetter
64 from cvs2svn_lib
.property_setters
import CVSBinaryFileDefaultMimeTypeSetter
65 from cvs2svn_lib
.property_setters
import CVSBinaryFileEOLStyleSetter
66 from cvs2svn_lib
.property_setters
import CVSRevisionNumberSetter
67 from cvs2svn_lib
.property_setters
import DefaultEOLStyleSetter
68 from cvs2svn_lib
.property_setters
import EOLStyleFromMimeTypeSetter
69 from cvs2svn_lib
.property_setters
import ExecutablePropertySetter
70 from cvs2svn_lib
.property_setters
import KeywordsPropertySetter
71 from cvs2svn_lib
.property_setters
import MimeMapper
72 from cvs2svn_lib
.property_setters
import SVNBinaryFileKeywordsPropertySetter
75 class GetoptOptions(object):
76 """Backwards compatibility adapter for getopt-style options.
78 optparse-compatible options can be created with the __call__()
79 method. When such an option is seen, it appends (opt, value) tuples
80 to self.opts. These can be processed in a getopt-style option
86 def __call__(self
, *args
, **kw
):
87 """Create an optparse-compatible Option object.
89 The arguments are compatible with those of the optparse.Options
90 constructor, except that action is allways set to 'callback' and
91 the callback is always set to self.callback. In particular, if
92 the option should take an argument, then the 'type' keyword
93 argument should be used."""
95 kw
['action'] = 'callback'
96 kw
['callback'] = self
.callback
97 return optparse
.Option(*args
, **kw
)
99 def callback(self
, option
, opt_str
, value
, parser
):
100 self
.opts
.append((opt_str
, value
,))
104 Usage: %prog --options OPTIONFILE
105 %prog [OPTION...] OUTPUT-OPTION CVS-REPOS-PATH"""
108 Convert a CVS repository into a Subversion repository, including history.
113 """A place to store meta-options that are used to start the conversion."""
115 def __init__(self
, progname
, cmd_args
, pass_manager
):
116 """Process the command-line options, storing run options to SELF.
118 PROGNAME is the name of the program, used in the usage string.
119 CMD_ARGS is the list of command-line arguments passed to the
120 program. PASS_MANAGER is an instance of PassManager, needed to
121 help process the -p and --help-passes options."""
123 self
.pass_manager
= pass_manager
125 self
.end_pass
= self
.pass_manager
.num_passes
126 self
.profiling
= False
127 self
.progname
= progname
131 # A list of one list of SymbolStrategyRules for each project:
132 self
.project_symbol_strategy_rules
= []
136 parser
= self
.parser
= optparse
.OptionParser(
138 description
=description
,
139 add_help_option
=False,
143 group
= parser
.add_option_group('Configuration via options file')
145 '--options', type='string',
147 'read the conversion options from PATH. This '
148 'method allows more flexibility than using '
149 'command-line options. See documentation for info'
154 group
= parser
.add_option_group('Output options')
156 '--svnrepos', '-s', type='string',
157 help='path where SVN repos should be created',
161 '--existing-svnrepos',
162 help='load into existing SVN repository (for use with --svnrepos)',
165 '--fs-type', type='string',
167 'pass --fs-type=TYPE to "svnadmin create" (for use with '
175 'pass --bdb-txn-nosync to "svnadmin create" (for use with '
180 '--create-option', type='string',
181 help='pass OPT to "svnadmin create" (for use with --svnrepos)',
185 '--dumpfile', type='string',
186 help='just produce a dumpfile; don\'t commit to a repos',
191 action
='callback', callback
=self
.callback_dry_run
,
193 'do not create a repository or a dumpfile; just print what '
198 # Deprecated options:
199 group
.add_option(go('--dump-only', help=optparse
.SUPPRESS_HELP
))
200 group
.add_option(go('--create', help=optparse
.SUPPRESS_HELP
))
203 group
= parser
.add_option_group('Conversion options')
206 help='convert only trunk commits, not tags nor branches',
209 '--trunk', type='string',
211 'path for trunk (default: %s)'
212 % (config
.DEFAULT_TRUNK_BASE
,)
217 '--branches', type='string',
219 'path for branches (default: %s)'
220 % (config
.DEFAULT_BRANCHES_BASE
,)
225 '--tags', type='string',
227 'path for tags (default: %s)'
228 % (config
.DEFAULT_TAGS_BASE
,)
234 help='don\'t prune empty directories',
237 '--encoding', type='string',
239 'encoding for paths and log messages in CVS repos. '
240 'If option is specified multiple times, encoders '
241 'are tried in order until one succeeds. See '
242 'http://docs.python.org/lib/standard-encodings.html '
243 'for a list of standard Python encodings.'
248 '--fallback-encoding', type='string',
249 help='If all --encodings fail, use lossy encoding with ENC',
253 '--symbol-transform', type='string',
255 'transform symbol names from P to S, where P and S '
256 'use Python regexp and reference syntax '
257 'respectively. P must match the whole symbol name'
262 '--symbol-hints', type='string',
263 help='read symbol conversion hints from PATH',
267 '--force-branch', type='string',
268 help='force symbols matching REGEXP to be branches',
272 '--force-tag', type='string',
273 help='force symbols matching REGEXP to be tags',
277 '--exclude', type='string',
278 help='exclude branches and tags matching REGEXP',
282 '--keep-trivial-imports',
284 'do not exclude branches that were only used for '
285 'a single import (usually these are unneeded)'
289 '--symbol-default', type='string',
291 'specify how ambiguous symbols are converted. '
292 'OPT is "heuristic" (default), "strict", "branch", '
300 'keep .cvsignore files (in addition to creating '
301 'the analogous svn:ignore properties)'
305 '--no-cross-branch-commits',
306 help='prevent the creation of cross-branch commits',
309 '--retain-conflicting-attic-files',
311 'if a file appears both in and out of '
312 'the CVS Attic, then leave the attic version in a '
313 'SVN directory called "Attic"'
317 '--username', type='string',
318 help='username for cvs2svn-synthesized commits',
323 help='record CVS revision numbers as file properties',
326 '--mime-types', type='string',
328 'specify an apache-style mime.types file for setting '
334 '--eol-from-mime-type',
335 help='set svn:eol-style from mime type if known',
338 '--auto-props', type='string',
340 'set file properties from the auto-props section '
341 'of a file in svn config format'
346 '--default-eol', type='string',
348 'default svn:eol-style for non-binary files with '
349 'undetermined mime types. VALUE is "binary" '
350 '(default), "native", "CRLF", "LF", or "CR"'
357 'don\'t set svn:keywords on any files (by default, '
358 'cvs2svn sets svn:keywords on non-binary files to "%s")'
359 % (config
.SVN_KEYWORDS_VALUE
,)
363 # Deprecated options:
364 group
.add_option(go('--no-default-eol', help=optparse
.SUPPRESS_HELP
))
366 '--auto-props-ignore-case', help=optparse
.SUPPRESS_HELP
370 group
= parser
.add_option_group('Extraction options')
373 help='use RCS to extract revision contents',
378 'use CVS to extract revision contents '
379 '(only use this if having problems with RCS)'
385 'use internal code to extract revision contents '
386 '(very fast but disk space intensive) (default)'
391 group
= parser
.add_option_group('Environment options')
393 '--tmpdir', type='string',
395 'directory to use for temporary data files '
396 '(default "cvs2svn-tmp")'
401 '--svnadmin', type='string',
402 help='path to the "svnadmin" program',
406 '--co', type='string',
407 help='path to the "co" program (required if --use-rcs)',
411 '--cvs', type='string',
412 help='path to the "cvs" program (required if --use-cvs)',
416 '--sort', type='string',
417 help='path to the GNU "sort" program',
422 group
= parser
.add_option_group('Partial conversions')
424 '--pass', type='string',
425 action
='callback', callback
=self
.callback_passes
,
426 help='execute only specified PASS of conversion',
430 '--passes', '-p', type='string',
431 action
='callback', callback
=self
.callback_passes
,
433 'execute passes START through END, inclusive (PASS, '
434 'START, and END can be pass names or numbers)'
436 metavar
='[START]:[END]',
440 group
= parser
.add_option_group('Information options')
443 action
='callback', callback
=self
.callback_version
,
444 help='print the version number',
449 help='print this usage message and exit with success',
453 action
='callback', callback
=self
.callback_help_passes
,
454 help='list the available passes and their numbers',
458 action
='callback', callback
=self
.callback_verbose
,
459 help='verbose (may be specified twice for debug output)',
463 action
='callback', callback
=self
.callback_quiet
,
464 help='quiet (may be specified twice for very quiet)',
467 '--write-symbol-info', type='string',
468 help='write information and statistics about CVS symbols to PATH.',
473 help='prevent the deletion of intermediate files',
477 action
='callback', callback
=self
.callback_profile
,
478 help='profile with \'hotshot\' (into file cvs2svn.hotshot)',
481 (self
.options
, self
.args
) = parser
.parse_args()
484 # Next look for any --options options, process them, and remove
485 # them from the list, as they affect the processing of other
487 options_file_found
= False
488 for (opt
, value
) in self
.get_options('--options'):
489 self
.process_options_file(value
)
490 options_file_found
= True
492 # Now the log level has been set; log the time when the run started:
495 'Conversion start time: %Y-%m-%d %I:%M:%S %Z',
496 time
.localtime(Log().start_time
)
500 if options_file_found
:
501 # All of the options that are compatible with --options have
502 # been consumed above. It is an error if any other options or
503 # arguments are left:
504 self
.verify_options_consumed()
506 # --options was not specified. So we can process other options
507 # that are not compatible with --options.
508 self
.process_remaining_options()
510 # Check for problems with the options:
515 project_cvs_repos_path
,
516 trunk_path
=None, branches_path
=None, tags_path
=None,
517 initial_directories
=[],
518 symbol_transforms
=None,
519 symbol_strategy_rules
=[],
521 """Add a project to be converted.
523 Most arguments are passed straight through to the Project
524 constructor. SYMBOL_STRATEGY_RULES is an iterable of
525 SymbolStrategyRules that will be applied to symbols in this
528 initial_directories
= [
530 for path
in [trunk_path
, branches_path
, tags_path
]
532 ] + list(initial_directories
)
534 symbol_strategy_rules
= list(symbol_strategy_rules
)
536 # Add rules to set the SVN paths for LODs depending on whether
537 # they are the trunk, tags, or branches:
538 if trunk_path
is not None:
539 symbol_strategy_rules
.append(TrunkPathRule(trunk_path
))
540 if branches_path
is not None:
541 symbol_strategy_rules
.append(BranchesPathRule(branches_path
))
542 if tags_path
is not None:
543 symbol_strategy_rules
.append(TagsPathRule(tags_path
))
545 id = len(self
.projects
)
548 project_cvs_repos_path
,
549 initial_directories
=initial_directories
,
550 symbol_transforms
=symbol_transforms
,
553 self
.projects
.append(project
)
554 self
.project_symbol_strategy_rules
.append(symbol_strategy_rules
)
556 def clear_projects(self
):
557 """Clear the list of projects to be converted.
559 This method is for the convenience of options files, which may
560 want to import one another."""
563 del self
.project_symbol_strategy_rules
[:]
565 def callback_help_passes(self
, option
, opt_str
, value
, parser
):
566 self
.pass_manager
.help_passes()
569 def callback_version(self
, option
, opt_str
, value
, parser
):
571 '%s version %s\n' % (os
.path
.basename(self
.progname
), VERSION
)
575 def callback_verbose(self
, option
, opt_str
, value
, parser
):
576 Log().increase_verbosity()
578 def callback_quiet(self
, option
, opt_str
, value
, parser
):
579 Log().decrease_verbosity()
581 def callback_passes(self
, option
, opt_str
, value
, parser
):
582 if value
.find(':') >= 0:
583 start_pass
, end_pass
= value
.split(':')
584 self
.start_pass
= self
.pass_manager
.get_pass_number(start_pass
, 1)
585 self
.end_pass
= self
.pass_manager
.get_pass_number(
586 end_pass
, self
.pass_manager
.num_passes
591 self
.pass_manager
.get_pass_number(value
)
593 def callback_dry_run(self
, option
, opt_str
, value
, parser
):
596 def callback_profile(self
, option
, opt_str
, value
, parser
):
597 self
.profiling
= True
599 def process_remaining_options(self
):
600 """Process the options that are not compatible with --options."""
602 # Convenience var, so we don't have to keep instantiating this Borg.
605 options
= self
.options
607 options
.svnrepos
= None
608 options
.existing_svnrepos
= False
609 options
.fs_type
= None
610 options
.bdb_txn_nosync
= False
611 options
.create_options
= []
612 options
.dump_only
= False
613 options
.dumpfile
= None
614 options
.use_rcs
= False
615 options
.use_cvs
= False
616 options
.use_internal_co
= False
617 options
.keep_trivial_imports
= False
618 options
.symbol_strategy_default
= 'heuristic'
619 options
.mime_types_file
= None
620 options
.auto_props_file
= None
621 options
.auto_props_ignore_case
= True
622 options
.eol_from_mime_type
= False
623 options
.default_eol
= None
624 options
.keywords_off
= False
625 options
.co_executable
= config
.CO_EXECUTABLE
626 options
.cvs_executable
= config
.CVS_EXECUTABLE
627 options
.trunk_base
= config
.DEFAULT_TRUNK_BASE
628 options
.branches_base
= config
.DEFAULT_BRANCHES_BASE
629 options
.tags_base
= config
.DEFAULT_TAGS_BASE
630 options
.encodings
= ['ascii']
631 options
.fallback_encoding
= None
632 options
.force_branch
= False
633 options
.force_tag
= False
634 options
.symbol_transforms
= []
635 options
.symbol_strategy_rules
= []
637 for opt
, value
in self
.opts
:
638 if opt
in ['-s', '--svnrepos']:
639 options
.svnrepos
= value
640 elif opt
== '--existing-svnrepos':
641 options
.existing_svnrepos
= True
642 elif opt
== '--dumpfile':
643 options
.dumpfile
= value
644 elif opt
== '--use-rcs':
645 options
.use_rcs
= True
646 elif opt
== '--use-cvs':
647 options
.use_cvs
= True
648 elif opt
== '--use-internal-co':
649 options
.use_internal_co
= True
650 elif opt
== '--trunk-only':
651 ctx
.trunk_only
= True
652 elif opt
== '--trunk':
653 options
.trunk_base
= value
654 elif opt
== '--branches':
655 options
.branches_base
= value
656 elif opt
== '--tags':
657 options
.tags_base
= value
658 elif opt
== '--no-prune':
660 elif opt
== '--encoding':
661 options
.encodings
.insert(-1, value
)
662 elif opt
== '--fallback-encoding':
663 options
.fallback_encoding
= value
664 elif opt
== '--symbol-hints':
665 options
.symbol_strategy_rules
.append(SymbolHintsFileRule(value
))
666 elif opt
== '--force-branch':
667 options
.symbol_strategy_rules
.append(
668 ForceBranchRegexpStrategyRule(value
)
670 options
.force_branch
= True
671 elif opt
== '--force-tag':
672 options
.symbol_strategy_rules
.append(
673 ForceTagRegexpStrategyRule(value
)
675 options
.force_tag
= True
676 elif opt
== '--exclude':
677 options
.symbol_strategy_rules
.append(ExcludeRegexpStrategyRule(value
))
678 elif opt
== '--keep-trivial-imports':
679 options
.keep_trivial_imports
= True
680 elif opt
== '--symbol-default':
681 if value
not in ['branch', 'tag', 'heuristic', 'strict']:
683 '%r is not a valid option for --symbol_default.' % (value
,))
684 options
.symbol_strategy_default
= value
685 elif opt
== '--keep-cvsignore':
686 ctx
.keep_cvsignore
= True
687 elif opt
== '--no-cross-branch-commits':
688 ctx
.cross_branch_commits
= False
689 elif opt
== '--retain-conflicting-attic-files':
690 ctx
.retain_conflicting_attic_files
= True
691 elif opt
== '--symbol-transform':
692 [pattern
, replacement
] = value
.split(":")
694 options
.symbol_transforms
.append(
695 RegexpSymbolTransform(pattern
, replacement
))
697 raise FatalError("'%s' is not a valid regexp." % (pattern
,))
698 elif opt
== '--username':
700 elif opt
== '--fs-type':
701 options
.fs_type
= value
702 elif opt
== '--bdb-txn-nosync':
703 options
.bdb_txn_nosync
= True
704 elif opt
== '--create-option':
705 options
.create_options
.append(value
)
706 elif opt
== '--cvs-revnums':
707 ctx
.svn_property_setters
.append(CVSRevisionNumberSetter())
708 elif opt
== '--mime-types':
709 options
.mime_types_file
= value
710 elif opt
== '--auto-props':
711 options
.auto_props_file
= value
712 elif opt
== '--auto-props-ignore-case':
713 # "ignore case" is now the default, so this option doesn't
715 options
.auto_props_ignore_case
= True
716 elif opt
== '--eol-from-mime-type':
717 options
.eol_from_mime_type
= True
718 elif opt
== '--default-eol':
720 # Check that value is valid, and translate it to the proper case
721 options
.default_eol
= {
722 'binary' : None, 'native' : 'native',
723 'crlf' : 'CRLF', 'lf' : 'LF', 'cr' : 'CR',
727 'Illegal value specified for --default-eol: %s' % (value
,)
729 elif opt
== '--no-default-eol':
730 # For backwards compatibility:
731 options
.default_eol
= None
732 elif opt
== '--keywords-off':
733 options
.keywords_off
= True
734 elif opt
== '--tmpdir':
736 elif opt
== '--write-symbol-info':
737 ctx
.symbol_info_filename
= value
738 elif opt
== '--skip-cleanup':
739 ctx
.skip_cleanup
= True
740 elif opt
== '--svnadmin':
741 ctx
.svnadmin_executable
= value
743 options
.co_executable
= value
745 options
.cvs_executable
= value
746 elif opt
== '--sort':
747 ctx
.sort_executable
= value
748 elif opt
== '--dump-only':
749 options
.dump_only
= True
752 ': The --dump-only option is deprecated (it is implied\n'
755 elif opt
== '--create':
758 ': The behaviour produced by the --create option is now the '
759 'default,\nand passing the option is deprecated.\n'
762 # Consistency check for options and arguments.
763 if len(self
.args
) == 0:
767 if len(self
.args
) > 1:
768 Log().error(error_prefix
+ ": must pass only one CVS repository.\n")
772 cvsroot
= self
.args
[0]
774 if options
.dump_only
and not options
.dumpfile
:
775 raise FatalError("'--dump-only' requires '--dumpfile' to be specified.")
777 if not options
.svnrepos
and not options
.dumpfile
and not ctx
.dry_run
:
778 raise FatalError("must pass one of '-s' or '--dumpfile'.")
780 def not_both(opt1val
, opt1name
, opt2val
, opt2name
):
781 if opt1val
and opt2val
:
782 raise FatalError("cannot pass both '%s' and '%s'."
783 % (opt1name
, opt2name
,))
785 not_both(options
.svnrepos
, '-s',
786 options
.dumpfile
, '--dumpfile')
788 not_both(options
.dumpfile
, '--dumpfile',
789 options
.existing_svnrepos
, '--existing-svnrepos')
791 not_both(options
.bdb_txn_nosync
, '--bdb-txn-nosync',
792 options
.existing_svnrepos
, '--existing-svnrepos')
794 not_both(options
.dumpfile
, '--dumpfile',
795 options
.bdb_txn_nosync
, '--bdb-txn-nosync')
797 not_both(options
.fs_type
, '--fs-type',
798 options
.existing_svnrepos
, '--existing-svnrepos')
800 not_both(options
.use_rcs
, '--use-rcs',
801 options
.use_cvs
, '--use-cvs')
803 not_both(options
.use_rcs
, '--use-rcs',
804 options
.use_internal_co
, '--use-internal-co')
806 not_both(options
.use_cvs
, '--use-cvs',
807 options
.use_internal_co
, '--use-internal-co')
809 not_both(ctx
.trunk_only
, '--trunk-only',
810 options
.force_branch
, '--force-branch')
812 not_both(ctx
.trunk_only
, '--trunk-only',
813 options
.force_tag
, '--force-tag')
817 and options
.fs_type
!= 'bdb'
818 and options
.bdb_txn_nosync
820 raise FatalError("cannot pass --bdb-txn-nosync with --fs-type=%s."
824 if options
.existing_svnrepos
:
825 ctx
.output_option
= ExistingRepositoryOutputOption(options
.svnrepos
)
827 ctx
.output_option
= NewRepositoryOutputOption(
829 fs_type
=options
.fs_type
, bdb_txn_nosync
=options
.bdb_txn_nosync
,
830 create_options
=options
.create_options
)
832 ctx
.output_option
= DumpfileOutputOption(options
.dumpfile
)
835 ctx
.revision_recorder
= NullRevisionRecorder()
836 ctx
.revision_excluder
= NullRevisionExcluder()
837 ctx
.revision_reader
= RCSRevisionReader(options
.co_executable
)
838 elif options
.use_cvs
:
839 ctx
.revision_recorder
= NullRevisionRecorder()
840 ctx
.revision_excluder
= NullRevisionExcluder()
841 ctx
.revision_reader
= CVSRevisionReader(options
.cvs_executable
)
843 # --use-internal-co is the default:
844 ctx
.revision_recorder
= InternalRevisionRecorder(compress
=True)
845 ctx
.revision_excluder
= InternalRevisionExcluder()
846 ctx
.revision_reader
= InternalRevisionReader(compress
=True)
849 ctx
.cvs_author_decoder
= CVSTextDecoder(
850 options
.encodings
, options
.fallback_encoding
852 ctx
.cvs_log_decoder
= CVSTextDecoder(
853 options
.encodings
, options
.fallback_encoding
855 # Don't use fallback_encoding for filenames:
856 ctx
.cvs_filename_decoder
= CVSTextDecoder(options
.encodings
)
857 except LookupError, e
:
858 raise FatalError(str(e
))
860 # Add the standard symbol name cleanup rules:
861 options
.symbol_transforms
.extend([
862 ReplaceSubstringsSymbolTransform('\\','/'),
863 # Remove leading, trailing, and repeated slashes:
864 NormalizePathsSymbolTransform(),
867 if not options
.keep_trivial_imports
:
868 options
.symbol_strategy_rules
.append(ExcludeTrivialImportBranchRule())
870 options
.symbol_strategy_rules
.append(UnambiguousUsageRule())
871 if options
.symbol_strategy_default
== 'strict':
873 elif options
.symbol_strategy_default
== 'branch':
874 options
.symbol_strategy_rules
.append(AllBranchRule())
875 elif options
.symbol_strategy_default
== 'tag':
876 options
.symbol_strategy_rules
.append(AllTagRule())
877 elif options
.symbol_strategy_default
== 'heuristic':
878 options
.symbol_strategy_rules
.append(BranchIfCommitsRule())
879 options
.symbol_strategy_rules
.append(HeuristicStrategyRule())
883 # Now add a rule whose job it is to pick the preferred parents of
885 options
.symbol_strategy_rules
.append(HeuristicPreferredParentRule())
887 if options
.auto_props_file
:
888 ctx
.svn_property_setters
.append(AutoPropsPropertySetter(
889 options
.auto_props_file
, options
.auto_props_ignore_case
))
891 if options
.mime_types_file
:
892 ctx
.svn_property_setters
.append(MimeMapper(options
.mime_types_file
))
894 ctx
.svn_property_setters
.append(CVSBinaryFileEOLStyleSetter())
896 ctx
.svn_property_setters
.append(CVSBinaryFileDefaultMimeTypeSetter())
898 if options
.eol_from_mime_type
:
899 ctx
.svn_property_setters
.append(EOLStyleFromMimeTypeSetter())
901 ctx
.svn_property_setters
.append(
902 DefaultEOLStyleSetter(options
.default_eol
)
905 ctx
.svn_property_setters
.append(SVNBinaryFileKeywordsPropertySetter())
907 if not options
.keywords_off
:
908 ctx
.svn_property_setters
.append(
909 KeywordsPropertySetter(config
.SVN_KEYWORDS_VALUE
))
911 ctx
.svn_property_setters
.append(ExecutablePropertySetter())
913 # Create the default project (using ctx.trunk, ctx.branches, and
917 trunk_path
=options
.trunk_base
,
918 branches_path
=options
.branches_base
,
919 tags_path
=options
.tags_base
,
920 symbol_transforms
=options
.symbol_transforms
,
921 symbol_strategy_rules
=options
.symbol_strategy_rules
,
924 def check_options(self
):
925 """Check the the run options are OK.
927 This should only be called after all options have been processed."""
929 # Convenience var, so we don't have to keep instantiating this Borg.
932 if not self
.start_pass
<= self
.end_pass
:
933 raise InvalidPassError(
934 'Ending pass must not come before starting pass.')
936 if not ctx
.dry_run
and ctx
.output_option
is None:
937 raise FatalError('No output option specified.')
939 if ctx
.output_option
is not None:
940 ctx
.output_option
.check()
942 if not self
.projects
:
943 raise FatalError('No project specified.')
945 def get_options(self
, *names
):
946 """Return a list of (option,value) pairs for options in NAMES.
948 Return a list containing any (opt, value) pairs from self.opts
949 where opt is in NAMES. The matching options are removed from
954 while i
< len(self
.opts
):
955 (opt
, value
) = self
.opts
[i
]
958 retval
.append( (opt
, value
) )
963 def verify_options_consumed(self
):
964 """Verify that all command line options and arguments have been used.
966 The --options option was specified, and all options that are
967 compatible with that option have already been consumed. Verify
968 that there are no remaining (i.e., incompatible) options or
971 if self
.opts
or self
.args
:
974 '%s: The following options cannot be used in combination with '
980 '\n '.join([opt
for (opt
,value
) in self
.opts
])
985 '%s: No cvs-repos-path arguments are allowed with the --options '
991 def process_options_file(self
, options_filename
):
992 """Read options from the file named OPTIONS_FILENAME.
994 Store the run options to SELF."""
999 'run_options' : self
,
1001 execfile(options_filename
, g
, l
)
1004 self
.parser
.print_help()