예제 #1
0
def get_setup():
    optinfo = CLIENT_COMMON_OPTIONS
    optinfo['nouids'] = Option("Do not include UID numbers for users",
                               default=False,
                               cmd='--no-uids',
                               long_arg=True,
                               cook=get_bool)
    optinfo['nogids'] = Option("Do not include GID numbers for groups",
                               default=False,
                               cmd='--no-gids',
                               long_arg=True,
                               cook=get_bool)
    setup = OptionParser(optinfo)
    setup.parse(sys.argv[1:])

    if setup['args']:
        print("posixuser_[baseline.py takes no arguments, only options")
        print(setup.buildHelpMessage())
        raise SystemExit(1)
    level = 30
    if setup['verbose']:
        level = 20
    if setup['debug']:
        level = 0
    Bcfg2.Logger.setup_logging('posixusers_baseline.py',
                               to_syslog=False,
                               level=level,
                               to_file=setup['logging'])
    return setup
예제 #2
0
    def __init__(self, setup):
        super(RedisTransport, self).__init__(setup)
        self._redis = None
        self._commands = None

        self.logger.error("Warning: RedisTransport is experimental")

        if not HAS_REDIS:
            self.logger.error("redis python module is not available")
            raise TransportError

        setup.update(
            dict(
                reporting_redis_host=Option('Redis Host',
                                            default='127.0.0.1',
                                            cf=('reporting', 'redis_host')),
                reporting_redis_port=Option('Redis Port',
                                            default=6379,
                                            cf=('reporting', 'redis_port')),
                reporting_redis_db=Option('Redis DB',
                                          default=0,
                                          cf=('reporting', 'redis_db')),
            ))
        setup.reparse()

        self._redis_host = setup.get('reporting_redis_host', '127.0.0.1')
        try:
            self._redis_port = int(setup.get('reporting_redis_port', 6379))
        except ValueError:
            self.logger.error("Redis port must be an integer")
            raise TransportError
        self._redis_db = setup.get('reporting_redis_db', 0)
        self._redis = redis.Redis(host=self._redis_host,
                                  port=self._redis_port,
                                  db=self._redis_db)
예제 #3
0
    def setUp(self):
        self.options = [
            Option("--cls", cf=("config", "cls"),
                   action=ImportComponentAction),
            Option("--module", action=ImportModuleAction)
        ]

        self.result = argparse.Namespace()
        new_parser()
        self.parser = get_parser(components=[self], namespace=self.result)
예제 #4
0
 def setUp(self):
     # parsing options can modify the Option objects themselves.
     # that's probably bad -- and it's definitely bad if we ever
     # want to do real on-the-fly config changes -- but it's easier
     # to leave it as is and set the options on each test.
     self.options = [
         Option(cf=("foo", "*"), dest="all"),
         Option(cf=("foo", "test*"), dest="test"),
         Option(cf=("foo", "bogus*"), dest="unmatched"),
         Option(cf=("bar", "*"), dest="no_section"),
         Option(cf=("foo", "foo"))]
예제 #5
0
파일: TestConfigFiles.py 프로젝트: 0/bcfg2
 def setUp(self):
     self.options = [
         PathOption(cf=("test", "config2"), action=ConfigFileAction),
         PathOption(cf=("test", "config3"), action=ConfigFileAction),
         Option(cf=("test", "foo")),
         Option(cf=("test", "bar")),
         Option(cf=("test", "baz"))
     ]
     self.results = argparse.Namespace()
     new_parser()
     self.parser = get_parser(components=[self], namespace=self.results)
예제 #6
0
 def setUp(self):
     self.options = [
         WildcardSectionGroup(Option(cf=("four:*", "foo")),
                              Option(cf=("four:*", "bar"))),
         WildcardSectionGroup(Option(cf=("five:*", "foo")),
                              Option(cf=("five:*", "bar")),
                              prefix="",
                              dest="sections")
     ]
     self.results = argparse.Namespace()
     new_parser()
     self.parser = get_parser(components=[self], namespace=self.results)
예제 #7
0
 def test_anchored_regex_list(self):
     """parse regex lists."""
     self.options = [Option("--test", type=Types.anchored_regex_list)]
     self.assertItemsEqual(
         [r.pattern for r in self._test_options(["--test", r'\d+  \s*'])],
         [r'^\d+$', r'^\s*$'])
     self.assertRaises(SystemExit, self._test_options, ["--test", '(]'])
예제 #8
0
 def setUp(self):
     # parsing options can modify the Option objects themselves.
     # that's probably bad -- and it's definitely bad if we ever
     # want to do real on-the-fly config changes -- but it's easier
     # to leave it as is and set the options on each test.
     OptionTestCase.setUp(self)
     self.options = [
         BooleanOption("--test-true-boolean",
                       env="TEST_TRUE_BOOLEAN",
                       cf=("test", "true_boolean"),
                       default=True),
         BooleanOption("--test-false-boolean",
                       env="TEST_FALSE_BOOLEAN",
                       cf=("test", "false_boolean"),
                       default=False),
         BooleanOption(cf=("test", "true_config_boolean"), default=True),
         BooleanOption(cf=("test", "false_config_boolean"), default=False),
         Option("--test-option",
                env="TEST_OPTION",
                cf=("test", "option"),
                default="foo"),
         PathOption("--test-path-option",
                    env="TEST_PATH_OPTION",
                    cf=("test", "path"),
                    default="/test")
     ]
예제 #9
0
 def test_username(self, mock_getpwnam):
     """parse username options."""
     self.options = [Option("--test", type=Types.username)]
     mock_getpwnam.return_value = ("test", '********', 1001, 1001,
                                   "Test user", "/home/test", "/bin/bash")
     self.assertEqual(self._test_options(["--test", "1001"]), 1001)
     self.assertEqual(self._test_options(["--test", "test"]), 1001)
예제 #10
0
 def reporting_storage(cls):
     """ Load a Reporting storage backend """
     if cls._reporting_storage is None:
         cls._reporting_storage = Option(cf=('reporting', 'storage'),
                                         dest="reporting_storage",
                                         help='Reporting storage engine',
                                         action=ReportingStorageAction,
                                         default='DjangoORM')
     return cls._reporting_storage
예제 #11
0
 def reporting_transport(cls):
     """ Load a Reporting transport backend """
     if cls._reporting_transport is None:
         cls._reporting_transport = Option(cf=('reporting', 'transport'),
                                           dest="reporting_transport",
                                           help='Reporting transport',
                                           action=ReportingTransportAction,
                                           default='DirectStore')
     return cls._reporting_transport
예제 #12
0
 def __init__(self, *items, **kwargs):
     r"""
     :param \*args: Child options
     :type \*args: Bcfg2.Options.Option
     :param prefix: The prefix to use for options generated by this
                    option group.  By default this is generated
                    automatically from the config glob; see above
                    for details.
     :type prefix: string
     :param dest: The destination for the list of known sections
                  that match the glob.
     :param dest: string
     """
     OptionContainer.__init__(self, [])
     self._section_glob = items[0].cf[0]
     # get a default destination
     self._prefix = kwargs.get("prefix",
                               self._dest_re.sub('_', self._section_glob))
     Option.__init__(self, dest=kwargs.get('dest',
                                           self._prefix + "sections"))
     self._options = items
예제 #13
0
 def plugins(cls):
     """ Load a list of Bcfg2 server plugins """
     if cls._plugins is None:
         cls._plugins = Option(cf=('server', 'plugins'),
                               type=Types.comma_list,
                               help="Server plugin list",
                               action=PluginsAction,
                               default=[
                                   'Bundler', 'Cfg', 'Metadata', 'Pkgmgr',
                                   'Rules', 'SSHbase'
                               ])
     return cls._plugins
예제 #14
0
 def __init__(self, *items, **kwargs):
     r"""
     :param \*args: Child options
     :type \*args: Bcfg2.Options.Option
     :param prefix: The prefix to use for options generated by this
                    option group.  By default this is generated
                    automatically from the config glob; see above
                    for details.
     :type prefix: string
     :param dest: The destination for the list of known sections
                  that match the glob.
     :param dest: string
     """
     _OptionContainer.__init__(self, [])
     self._section_glob = items[0].cf[0]
     # get a default destination
     self._prefix = kwargs.get("prefix",
                               self._dest_re.sub('_', self._section_glob))
     Option.__init__(self,
                     dest=kwargs.get('dest', self._prefix + "sections"))
     self.option_templates = items
예제 #15
0
    def test_comma_list(self):
        """parse comma-list values."""
        self.options = [Option("--test", type=Types.comma_list)]

        expected = ["one", "two", "three"]
        self.assertItemsEqual(self._test_options(["--test", "one,two,three"]),
                              expected)
        self.assertItemsEqual(
            self._test_options(["--test", "one, two, three"]), expected)
        self.assertItemsEqual(
            self._test_options(["--test", "one   , two  ,three"]), expected)
        self.assertItemsEqual(self._test_options(["--test", "one two, three"]),
                              ["one two", "three"])
예제 #16
0
    def setUp(self):
        OptionTestCase.setUp(self)
        self.options = [
            Option("--parent",
                   type=Types.comma_list,
                   default=["one", "two"],
                   action=ParentComponentAction)
        ]

        self.result = argparse.Namespace()
        new_parser()
        self.parser = get_parser(components=[self],
                                 namespace=self.result,
                                 description="component testing parser")
예제 #17
0
    def _test_dest(self, *args, **kwargs):
        """helper to test that ``dest`` is set properly."""
        args = list(args)
        expected = args.pop(0)
        config_file = args.pop()

        sentinel = object()
        kwargs["default"] = sentinel

        result = argparse.Namespace()
        parser = Parser(namespace=result)
        parser.add_options([Option(*args, **kwargs)])
        parser.parse(["-C", config_file])

        self.assertTrue(hasattr(result, expected))
        self.assertEqual(getattr(result, expected), sentinel)
예제 #18
0
    def filemonitor(cls):
        """ Load a single Bcfg2 file monitor (from
        :attr:`Bcfg2.Server.FileMonitor.available`) """
        if cls._filemonitor is None:
            import Bcfg2.Server.FileMonitor

            class FileMonitorAction(ComponentAction):
                """ ComponentAction for loading a single FAM backend
                class """
                islist = False
                mapping = Bcfg2.Server.FileMonitor.available

            cls._filemonitor = Option(cf=('server', 'filemonitor'),
                                      action=FileMonitorAction,
                                      default='default',
                                      help='Server file monitoring driver')
        return cls._filemonitor
예제 #19
0
 def test_literal_dict(self):
     """parse literal-dict values."""
     self.options = [Option("--test", type=Types.literal_dict)]
     expected = {
         "one": True,
         "two": 2,
         "three": "three",
         "four": False,
         "five": {
             "a": 1,
             "b": 2
         }
     }
     self.assertDictEqual(
         self._test_options([
             "--test", '''{ "one": True, "two": 2,
                                  "three": "three", "four": False,
                                  "five": { "a": 1, "b": 2 }}'''
         ]), expected)
예제 #20
0
 def test_duplicate_env_option(self):
     """add duplicate environment option."""
     parser = Parser(components=[self])
     self.assertRaises(OptionParserException, parser.add_options,
                       [Option(env="TEST_OPTION")])
예제 #21
0
 def test_duplicate_cf_option(self):
     """add duplicate config file option."""
     parser = Parser(components=[self])
     self.assertRaises(OptionParserException, parser.add_options,
                       [Option(cf=("test", "option"))])
예제 #22
0
파일: Two.py 프로젝트: xschlef/bcfg2
class Two(object):
    """Test class for component loading."""
    options = [
        Option('--test', cf=("config", "test"), dest="test", default="bar")
    ]
예제 #23
0
class Common(object):
    """ Common options used in multiple different contexts. """
    _plugins = None
    _filemonitor = None
    _reporting_storage = None
    _reporting_transport = None

    @classproperty
    def plugins(cls):
        """ Load a list of Bcfg2 server plugins """
        if cls._plugins is None:
            cls._plugins = Option(cf=('server', 'plugins'),
                                  type=Types.comma_list,
                                  help="Server plugin list",
                                  action=PluginsAction,
                                  default=[
                                      'Bundler', 'Cfg', 'Metadata', 'Pkgmgr',
                                      'Rules', 'SSHbase'
                                  ])
        return cls._plugins

    @classproperty
    def filemonitor(cls):
        """ Load a single Bcfg2 file monitor (from
        :attr:`Bcfg2.Server.FileMonitor.available`) """
        if cls._filemonitor is None:
            import Bcfg2.Server.FileMonitor

            class FileMonitorAction(ComponentAction):
                """ ComponentAction for loading a single FAM backend
                class """
                islist = False
                mapping = Bcfg2.Server.FileMonitor.available

            cls._filemonitor = Option(cf=('server', 'filemonitor'),
                                      action=FileMonitorAction,
                                      default='default',
                                      help='Server file monitoring driver')
        return cls._filemonitor

    @classproperty
    def reporting_storage(cls):
        """ Load a Reporting storage backend """
        if cls._reporting_storage is None:
            cls._reporting_storage = Option(cf=('reporting', 'storage'),
                                            dest="reporting_storage",
                                            help='Reporting storage engine',
                                            action=ReportingStorageAction,
                                            default='DjangoORM')
        return cls._reporting_storage

    @classproperty
    def reporting_transport(cls):
        """ Load a Reporting transport backend """
        if cls._reporting_transport is None:
            cls._reporting_transport = Option(cf=('reporting', 'transport'),
                                              dest="reporting_transport",
                                              help='Reporting transport',
                                              action=ReportingTransportAction,
                                              default='DirectStore')
        return cls._reporting_transport

    #: Set the path to the Bcfg2 repository
    repository = _repository_option

    #: Daemonize process, storing PID
    daemon = PathOption('-D',
                        '--daemon',
                        help="Daemonize process, storing PID")

    #: Run interactively, prompting the user for each change
    interactive = BooleanOption(
        "-I",
        "--interactive",
        help='Run interactively, prompting the user for each change')

    #: Log to syslog
    syslog = BooleanOption(cf=('logging', 'syslog'),
                           help="Log to syslog",
                           default=True)

    #: Server location
    location = Option('-S',
                      '--server',
                      cf=('components', 'bcfg2'),
                      default='https://localhost:6789',
                      metavar='<https://server:port>',
                      help="Server location")

    #: Communication password
    password = Option('-x',
                      '--password',
                      cf=('communication', 'password'),
                      metavar='<password>',
                      help="Communication Password")

    #: Path to SSL key
    ssl_key = PathOption('--ssl-key',
                         cf=('communication', 'key'),
                         dest="key",
                         help='Path to SSL key',
                         default="/etc/pki/tls/private/bcfg2.key")

    #: Path to SSL certificate
    ssl_cert = PathOption(cf=('communication', 'certificate'),
                          dest="cert",
                          help='Path to SSL certificate',
                          default="/etc/pki/tls/certs/bcfg2.crt")

    #: Path to SSL CA certificate
    ssl_ca = PathOption(cf=('communication', 'ca'), help='Path to SSL CA Cert')

    #: Default Path paranoid setting
    default_paranoid = Option(cf=('mdata', 'paranoid'),
                              dest="default_paranoid",
                              default='true',
                              choices=['true', 'false'],
                              help='Default Path paranoid setting')

    #: Client timeout
    client_timeout = Option("-t",
                            "--timeout",
                            type=float,
                            default=90.0,
                            dest="client_timeout",
                            cf=('communication', 'timeout'),
                            help='Set the client XML-RPC timeout')
예제 #24
0
class One(MockSubcommand):
    """fake subcommand for testing."""
    options = [Option("--test-one")]
예제 #25
0
class Parser(argparse.ArgumentParser):
    """ The Bcfg2 option parser.  Most interfaces should not need to
    instantiate a parser, but should instead use
    :func:`Bcfg2.Options.get_parser` to get the parser that already
    exists."""

    #: Option for specifying the path to the Bcfg2 config file
    configfile = PathOption('-C',
                            '--config',
                            env="BCFG2_CONFIG_FILE",
                            help="Path to configuration file",
                            default="/etc/bcfg2.conf")

    #: Verbose version string that is printed if executed with --version
    _version_string = "%s %s on Python %s" % (os.path.basename(
        sys.argv[0]), __version__, ".".join(
            str(v) for v in sys.version_info[0:3]))

    #: Builtin options that apply to all commands
    options = [
        configfile,
        Option('--version',
               help="Print the version and exit",
               action="version",
               version=_version_string),
        Option('-E',
               '--encoding',
               metavar='<encoding>',
               default='UTF-8',
               help="Encoding of config files",
               cf=('components', 'encoding'))
    ]

    #: Flag used in unit tests to disable actual config file reads
    unit_test = False

    def __init__(self, **kwargs):
        """ See :class:`argparse.ArgumentParser` for a full list of
        accepted parameters.

        In addition to supporting all arguments and keyword arguments
        from :class:`argparse.ArgumentParser`, several additional
        keyword arguments are allowed.

        :param components: A list of components to add to the parser.
        :type components: list
        :param namespace: The namespace to store options in.  Default
                          is :attr:`Bcfg2.Options.setup`.
        :type namespace: argparse.Namespace
        :param add_base_options: Whether or not to add the options in
                                 :attr:`Bcfg2.Options.Parser.options`
                                 to the parser.  Setting this to False
                                 is default for subparsers. Default is
                                 True.
        :type add_base_options: bool
        """
        self._cfp = ConfigParser.ConfigParser()
        components = kwargs.pop('components', [])

        #: The namespace options will be stored in.
        self.namespace = kwargs.pop('namespace', setup)
        if self.namespace is None:
            self.namespace = setup
        add_base_options = kwargs.pop('add_base_options', True)

        #: Flag to indicate that this is the pre-parsing 'early' run
        #: for important options like database settings that must be
        #: loaded before other components can be.
        self._early = kwargs.pop('early', False)

        if 'add_help' not in kwargs:
            kwargs['add_help'] = add_base_options
        argparse.ArgumentParser.__init__(self, **kwargs)

        #: Whether or not parsing has completed on all current options.
        self.parsed = False

        #: The argument list that was parsed.
        self.argv = None

        #: Components that have been added to the parser
        self.components = []

        #: Options that have been added to the parser
        self.option_list = []
        self._defaults_set = []
        self._config_files = []
        if add_base_options:
            self.add_component(self)
        if components:
            for component in components:
                self.add_component(component)

    def _check_duplicate_cf(self, option):
        """Check for a duplicate config file option."""

    def add_options(self, options):
        """ Add an explicit list of options to the parser.  When
        possible, prefer :func:`Bcfg2.Options.Parser.add_component` to
        add a whole component instead."""
        _debug("Adding options: %s" % options)
        self.parsed = False
        for option in options:
            if option not in self.option_list:
                # check for duplicates
                if (hasattr(option, "env") and option.env
                        and option.env in [o.env for o in self.option_list]):
                    raise OptionParserException(
                        "Duplicate environment variable option: %s" %
                        option.env)
                if (hasattr(option, "cf") and option.cf
                        and option.cf in [o.cf for o in self.option_list]):
                    raise OptionParserException(
                        "Duplicate config file option: %s" % (option.cf, ))

                self.option_list.extend(option.list_options())
                option.add_to_parser(self)
                for opt in option.list_options():
                    opt.default_from_config(self._cfp)
                    self._defaults_set.append(opt)

    def add_component(self, component):
        """ Add a component (and all of its options) to the
        parser. """
        if component not in self.components:
            _debug("Adding component %s to %s" % (component, self))
            self.components.append(component)
            if hasattr(component, "options"):
                self.add_options(getattr(component, "options"))

    def _set_defaults_from_config(self):
        """ Set defaults from the config file for all options that can
        come from the config file, but haven't yet had their default
        set """
        _debug("Setting defaults on all options")
        for opt in self.option_list:
            if opt not in self._defaults_set:
                opt.default_from_config(self._cfp)
                self._defaults_set.append(opt)

    def _parse_config_options(self):
        """ populate the namespace with default values for any options
        that aren't already in the namespace (i.e., options without
        CLI arguments) """
        _debug("Parsing config file-only options")
        for opt in self.option_list[:]:
            if not opt.args and opt.dest not in self.namespace:
                value = opt.default
                if value:
                    for _, action in opt.actions.items():
                        _debug("Setting config file-only option %s to %s" %
                               (opt, value))
                        action(self, self.namespace, value)
                else:
                    _debug("Setting config file-only option %s to %s" %
                           (opt, value))
                    setattr(self.namespace, opt.dest, value)

    def _finalize(self):
        """ Finalize the value of any options that require that
        additional post-processing step.  (Mostly
        :class:`Bcfg2.Options.Actions.ComponentAction` subclasses.)
        """
        _debug("Finalizing options")
        for opt in self.option_list[:]:
            opt.finalize(self.namespace)

    def _reset_namespace(self):
        """ Delete all options from the namespace except for a few
        predefined values and config file options. """
        self.parsed = False
        _debug("Resetting namespace")
        for attr in dir(self.namespace):
            if (not attr.startswith("_")
                    and attr not in ['uri', 'version', 'name']
                    and attr not in self._config_files):
                _debug("Deleting %s" % attr)
                delattr(self.namespace, attr)

    def _parse_early_options(self):
        """Parse early options.

        Early options are options that need to be parsed before other
        options for some reason. These fall into two basic cases:

        1. Database options, which need to be parsed so that Django
           modules can be imported, since Django configuration is all
           done at import-time;
        2. The repository (``-Q``) option, so that ``<repository>``
           macros in other options can be resolved.
        """
        _debug("Option parsing phase 2: Parse early options")
        early_opts = argparse.Namespace()
        early_parser = Parser(add_help=False, namespace=early_opts, early=True)

        # add the repo option so we can resolve <repository>
        # macros
        early_parser.add_options([repository])

        early_components = []
        for component in self.components:
            if getattr(component, "parse_first", False):
                early_components.append(component)
                early_parser.add_component(component)
        early_parser.parse(self.argv)

        _debug("Fixing up <repository> macros in early options")
        for attr_name in dir(early_opts):
            if not attr_name.startswith("_"):
                attr = getattr(early_opts, attr_name)
                if hasattr(attr, "replace"):
                    setattr(
                        early_opts, attr_name,
                        attr.replace("<repository>", early_opts.repository))

        _debug("Early parsing complete, calling hooks")
        for component in early_components:
            if hasattr(component, "component_parsed_hook"):
                _debug("Calling component_parsed_hook on %s" % component)
                getattr(component, "component_parsed_hook")(early_opts)
        _debug("Calling early parsing hooks; early options: %s" % early_opts)
        for option in self.option_list:
            option.early_parsing_hook(early_opts)

    def add_config_file(self, dest, cfile, reparse=True):
        """ Add a config file, which triggers a full reparse of all
        options. """
        if dest not in self._config_files:
            _debug("Adding new config file %s for %s" % (cfile, dest))
            self._reset_namespace()
            self._cfp.read([cfile])
            self._defaults_set = []
            self._set_defaults_from_config()
            if reparse:
                self._parse_config_options()
            self._config_files.append(dest)

    def reparse(self, argv=None):
        """ Reparse options after they have already been parsed.

        :param argv: The argument list to parse. By default,
                     :attr:`Bcfg2.Options.Parser.argv` is reused.
                     (I.e., the argument list that was initially
                     parsed.)
        :type argv: list
        """
        _debug("Reparsing all options")
        self._reset_namespace()
        self.parse(argv or self.argv)

    def parse(self, argv=None):
        """ Parse options.

        :param argv: The argument list to parse.  By default,
                     ``sys.argv[1:]`` is used.  This is stored in
                     :attr:`Bcfg2.Options.Parser.argv` for reuse by
                     :func:`Bcfg2.Options.Parser.reparse`.
        :type argv: list
        """
        _debug("Parsing options")
        if argv is None:
            argv = sys.argv[1:]  # pragma: nocover
        if self.parsed and self.argv == argv:
            _debug("Returning already parsed namespace")
            return self.namespace
        self.argv = argv

        # phase 1: get and read config file
        _debug("Option parsing phase 1: Get and read main config file")
        bootstrap_parser = argparse.ArgumentParser(add_help=False)
        self.configfile.add_to_parser(bootstrap_parser)
        self.configfile.default_from_config(self._cfp)
        bootstrap = bootstrap_parser.parse_known_args(args=self.argv)[0]

        # check whether the specified bcfg2.conf exists
        if not self.unit_test and not os.path.exists(bootstrap.config):
            sys.stderr.write("Could not read %s\n" % bootstrap.config)
        self.add_config_file(self.configfile.dest,
                             bootstrap.config,
                             reparse=False)

        # phase 2: re-parse command line for early options; currently,
        # that's database options
        if not self._early:
            self._parse_early_options()
        else:
            _debug("Skipping parsing phase 2 in early mode")

        # phase 3: re-parse command line, loading additional
        # components, until all components have been loaded.  On each
        # iteration, set defaults from config file/environment
        # variables
        _debug("Option parsing phase 3: Main parser loop")
        # _set_defaults_from_config must be called before _parse_config_options
        # This is due to a tricky interaction between the two methods:
        #
        # (1) _set_defaults_from_config does what its name implies, it updates
        # the "default" property of each Option based on the value that exists
        # in the config.
        #
        # (2)  _parse_config_options will look at each option and set it to the
        # default value that is _currently_ defined.  If the option does not
        # exist in the namespace, it will be added.  The method carefully
        # avoids overwriting the value of an option that is already defined in
        # the namespace.
        #
        # Thus, if _set_defaults_from_config has not been called yet when
        # _parse_config_options is called, all config file options will get set
        # to their hardcoded defaults.  This process defines the options in the
        # namespace and _parse_config_options will never look at them again.
        #
        # we have to do the parsing in two loops: first, we squeeze as
        # much data out of the config file as we can to ensure that
        # all config file settings are read before we use any default
        # values. then we can start looking at the command line.
        while not self.parsed:
            self.parsed = True
            self._set_defaults_from_config()
            self._parse_config_options()
        self.parsed = False
        remaining = []
        while not self.parsed:
            self.parsed = True
            _debug("Parsing known arguments")
            try:
                _, remaining = self.parse_known_args(args=self.argv,
                                                     namespace=self.namespace)
            except OptionParserException:
                self.error(sys.exc_info()[1])
            self._set_defaults_from_config()
            self._parse_config_options()
            self._finalize()
        if len(remaining) and not self._early:
            self.error("Unknown options: %s" % " ".join(remaining))

        # phase 4: call post-parsing hooks
        if not self._early:
            _debug("Option parsing phase 4: Call hooks")
            for component in self.components:
                if hasattr(component, "options_parsed_hook"):
                    _debug("Calling post-parsing hook on %s" % component)
                    getattr(component, "options_parsed_hook")()

        return self.namespace
예제 #26
0
class ConfigFileComponent(object):
    """fake component for testing component loading."""
    options = [
        Option("--config2", action=ConfigFileAction),
        Option(cf=("config", "test"), dest="config2_test", default="bar")
    ]
예제 #27
0
class ComponentTwo(object):
    """fake component for testing component loading."""
    options = [Option("--child", default="one", action=ChildComponentAction)]
예제 #28
0
class Two(MockSubcommand):
    """fake subcommand for testing."""
    options = [Option("--test-two")]
예제 #29
0
 def add_to_parser(self, parser):
     Option.add_to_parser(self, parser)
     _OptionContainer.add_to_parser(self, parser)
예제 #30
0
 def add_to_parser(self, parser):
     Option.add_to_parser(self, parser)
     OptionContainer.add_to_parser(self, parser)
예제 #31
0
class ChildTwo(object):
    """fake component for testing component loading."""
    options = [Option("--child-two")]
예제 #32
0
class ChildOne(object):
    """fake component for testing component loading."""
    options = [Option("--child-one")]