Exemple #1
0
    def parse_args(self, *args, **kwargs):
        """Overwrite default values based on global configuration."""

        # mapping of all verbs to parsers
        def collect_parsers_by_verb(root, parsers, parent_verbs=()):
            for sp in root._subparsers:
                for name, p in sp._parsers.items():
                    verbs = parent_verbs + (name, )
                    parsers[verbs] = p
                    collect_parsers_by_verb(p, parsers, verbs)

        all_parsers = {}
        collect_parsers_by_verb(self, all_parsers)

        # collect passed verbs to determine relevant configuration options
        with SuppressUsageOutput([self._parser] + list(all_parsers.values())):
            known_args, _ = self._parser.parse_known_args(*args, **kwargs)

        data = self._get_defaults_values(self._config_path)

        # determine data keys and parsers for passed verbs (including the root)
        keys_and_parsers = []
        nested_verbs = ()
        parser = self
        while True:
            keys_and_parsers.append(('.'.join(nested_verbs), parser))
            if len(parser._recursive_decorators) != 1:
                break
            if not hasattr(parser._recursive_decorators[0], 'dest'):
                break
            verb = getattr(known_args, parser._recursive_decorators[0].dest,
                           None)
            if verb is None:
                break
            nested_verbs = nested_verbs + (verb, )
            parser = all_parsers[nested_verbs]

        for key, parser in keys_and_parsers:
            parser._set_parser_defaults(data.get(key, {}), parser_name=key)

        return self._parser.parse_args(*args, **kwargs)
    def parse_args(self, *args, **kwargs):
        """Add mixin argument for each parser."""
        global VERB_BLOCKLIST

        # mapping of all "leaf" verbs to parsers
        def collect_parsers_by_verb(root, parsers, parent_verbs=()):
            found_any = False
            for sp in root._subparsers:
                for name, p in sp._parsers.items():
                    verbs = parent_verbs + (name, )
                    found_children = collect_parsers_by_verb(p, parsers, verbs)
                    # only add verbs which don't have subverbs
                    if not found_children:
                        parsers[verbs] = p
                        found_any = True
            return found_any

        parsers = {}
        collect_parsers_by_verb(self, parsers)

        mixins_by_verb = get_mixins()

        # add mixin arguments to these parsers
        # doing this here instead of in the add_parser() method makes sure
        # the arguments are documented at the very end of the help message
        groups = {}
        for k, p in parsers.items():
            # match all slices starting from index 0 of k against the blocklist
            # e.g. k=(a,b,c) it checks against (a), (a,b), (a,b,c)
            k_prefixes = {k[0:index] for index in range(1, len(k) + 1)}
            if not k_prefixes & VERB_BLOCKLIST:
                groups[p] = self._add_mixin_argument_group(p)

        # add dummy --mixin argument to prevent parse_known_args to interpret
        # --mixin arguments as --mixin-files
        mixin_arguments = {}
        for verb, p in parsers.items():
            if p in groups:
                mixin_arguments[verb] = self._add_mixin_argument(
                    p, groups[p], verb)

        with SuppressUsageOutput([self._parser] + list(parsers.values())):
            known_args, _ = self._parser.parse_known_args(*args, **kwargs)

        for mixin_file in (getattr(known_args, 'mixin_files', None) or []):
            # add mixins from explicitly provided file
            add_mixins(Path(mixin_file), mixins_by_verb)

        # update the --mixin argument help and completer with available mixins
        for verb, argument in mixin_arguments.items():
            self._update_mixin_argument(argument, mixins_by_verb.get(verb, {}))

        args = self._parser.parse_args(*args, **kwargs)

        # update args based on selected mixins
        if 'mixin_verb' in args:
            mixins = mixins_by_verb.get(args.mixin_verb, {})
            for mixin in args.mixin or ():
                if mixin not in mixins:
                    context = '.'.join(args.mixin_verb)
                    self._parser.error(
                        "Mixin '{mixin}' is not available for '{context}'".
                        format_map(locals()))
                mixin_args = mixins[mixin]
                logger.debug("Using mixin '{mixin}': {mixin_args}".format_map(
                    locals()))
                self._update_args(args, mixin_args, '.'.join(args.mixin_verb))

        # undo default value wrapping injected in the add_argument() method
        for k, v in args.__dict__.items():
            if is_default_value(v):
                setattr(args, k, _custom_unwrap_default_value(v))

        return args
def main(*, command_name='colcon', argv=None):
    """
    Execute the main logic of the command.

    The overview of the process:
    * Configure logging level based on an environment variable
    * Configure the configuration path
    * Create the argument parser

      * Document all environment variables
      * Decorate the parsers with additional functionality
      * Add the available verbs and their arguments

    * Configure logging level based on an arguments
    * Create an invocation specific log directory
    * Invoke the logic of the selected verb (if applicable)

    :param str command_name: The name of the command invoked
    :param list argv: The list of arguments
    :returns: The return code
    """
    global colcon_logger
    # default log level
    colcon_logger.setLevel(logging.WARN)
    set_logger_level_from_env(
        colcon_logger, '{command_name}_LOG_LEVEL'.format_map(locals()).upper())
    colcon_logger.debug('Command line arguments: {argv}'.format(
        argv=argv if argv is not None else sys.argv))

    # set default locations for config files
    set_default_config_path(
        path=(Path('~') / '.{command_name}'.format_map(locals())).expanduser(),
        env_var='{command_name}_HOME'.format_map(locals()).upper())

    parser = create_parser('colcon_core.environment_variable')

    verb_extensions = get_verb_extensions()

    # add subparsers for all verb extensions but without arguments for now
    subparser = create_subparser(parser,
                                 command_name,
                                 verb_extensions,
                                 attribute='verb_name')
    verb_parsers = add_parsers_without_arguments(parser,
                                                 subparser,
                                                 verb_extensions,
                                                 attribute='verb_name')

    with SuppressUsageOutput([parser] + list(verb_parsers.values())):
        known_args, _ = parser.parse_known_args(args=argv)

    # add the arguments for the requested verb
    if known_args.verb_name:
        add_parser_arguments(known_args.verb_parser, known_args.verb_extension)

    args = parser.parse_args(args=argv)
    context = CommandContext(command_name=command_name, args=args)

    if args.log_level:
        colcon_logger.setLevel(args.log_level)

    colcon_logger.debug('Parsed command line arguments: {args}'.format_map(
        locals()))

    # error: no verb provided
    if args.verb_name is None:
        print(parser.format_usage())
        return 'Error: No verb provided'

    # set default locations for log files
    now = datetime.datetime.now()
    now_str = str(now)[:-7].replace(' ', '_').replace(':', '-')
    set_default_log_path(
        base_path=args.log_base,
        env_var='{command_name}_LOG_PATH'.format_map(locals()).upper(),
        subdirectory='{args.verb_name}_{now_str}'.format_map(locals()))

    # add a file handler writing all levels
    create_log_path(args.verb_name)
    handler = add_file_handler(colcon_logger,
                               get_log_path() / 'logger_all.log')
    # write previous log messages to the file handler
    log_record = colcon_logger.makeRecord(
        colcon_logger.name, logging.DEBUG, __file__, 0,
        'Command line arguments: {argv}'.format(
            argv=argv if argv is not None else sys.argv), None, None)
    handler.handle(log_record)
    log_record = colcon_logger.makeRecord(
        colcon_logger.name, logging.DEBUG, __file__, 0,
        'Parsed command line arguments: {args}'.format_map(locals()), None,
        None)
    handler.handle(log_record)

    # invoke verb
    return verb_main(context, colcon_logger)
Exemple #4
0
def _main(*, command_name, argv):
    global colcon_logger
    # default log level
    colcon_logger.setLevel(logging.WARNING)
    set_logger_level_from_env(
        colcon_logger, '{command_name}_LOG_LEVEL'.format_map(locals()).upper())
    colcon_logger.debug(
        'Command line arguments: {argv}'
        .format(argv=argv if argv is not None else sys.argv))

    # set default locations for config files
    set_default_config_path(
        path=(
            Path('~') / '.{command_name}'.format_map(locals())).expanduser(),
        env_var='{command_name}_HOME'.format_map(locals()).upper())

    parser = create_parser('colcon_core.environment_variable')

    verb_extensions = get_verb_extensions()

    # add subparsers for all verb extensions but without arguments for now
    subparser = create_subparser(
        parser, command_name, verb_extensions, attribute='verb_name')
    verb_parsers = add_parsers_without_arguments(
        parser, subparser, verb_extensions, attribute='verb_name')

    with SuppressUsageOutput([parser] + list(verb_parsers.values())):
        known_args, _ = parser.parse_known_args(args=argv)

    # add the arguments for the requested verb
    if known_args.verb_name:
        add_parser_arguments(known_args.verb_parser, known_args.verb_extension)

    args = parser.parse_args(args=argv)
    context = CommandContext(command_name=command_name, args=args)

    if args.log_level:
        colcon_logger.setLevel(args.log_level)

    colcon_logger.debug(
        'Parsed command line arguments: {args}'.format_map(locals()))

    # error: no verb provided
    if args.verb_name is None:
        print(parser.format_usage())
        return 'Error: No verb provided'

    # set default locations for log files
    now = datetime.datetime.now()
    now_str = str(now)[:-7].replace(' ', '_').replace(':', '-')
    set_default_log_path(
        base_path=args.log_base,
        env_var='{command_name}_LOG_PATH'.format_map(locals()).upper(),
        subdirectory='{args.verb_name}_{now_str}'.format_map(locals()))

    # add a file handler writing all levels if logging isn't disabled
    log_path = get_log_path()
    if log_path is not None:
        create_log_path(args.verb_name)
        handler = add_file_handler(
            colcon_logger, log_path / 'logger_all.log')
        # write previous log messages to the file handler
        log_record = colcon_logger.makeRecord(
            colcon_logger.name, logging.DEBUG, __file__, 0,
            'Command line arguments: {argv}'
            .format(argv=argv if argv is not None else sys.argv),
            None, None)
        handler.handle(log_record)
        log_record = colcon_logger.makeRecord(
            colcon_logger.name, logging.DEBUG, __file__, 0,
            'Parsed command line arguments: {args}'.format_map(locals()),
            None, None)
        handler.handle(log_record)

    # invoke verb
    return verb_main(context, colcon_logger)
    def parse_args(self, *args, **kwargs):
        """Add mixin argument for each parser."""

        # mapping of all "leaf" verbs to parsers
        def collect_parsers_by_verb(root, parsers, parent_verbs=()):
            found_any = False
            for sp in root._subparsers:
                for name, p in sp._parsers.items():
                    verbs = parent_verbs + (name, )
                    found_children = collect_parsers_by_verb(p, parsers, verbs)
                    # only add verbs which don't have subverbs
                    if not found_children:
                        parsers[verbs] = p
                        found_any = True
            return found_any

        parsers = {}
        collect_parsers_by_verb(self, parsers)

        mixins_by_verb = get_mixins()

        # add mixin arguments to these parsers
        # doing this here instead of in the add_parser() method makes sure
        # the arguments are documented at the very end of the help message
        groups = {}
        for p in parsers.values():
            groups[p] = self._add_mixin_argument_group(p)

        # add dummy --mixin argument to prevent parse_known_args to interpret
        # --mixin arguments as --mixin-files
        mixin_arguments = {}
        for verb, p in parsers.items():
            mixin_arguments[verb] = self._add_mixin_argument(
                p, groups[p], verb)

        with SuppressUsageOutput([self._parser] + list(parsers.values())):
            known_args, _ = self._parser.parse_known_args(*args, **kwargs)

        for mixin_file in (getattr(known_args, 'mixin_files', None) or []):
            # add mixins from explicitly provided file
            add_mixins(Path(mixin_file), mixins_by_verb)

        # update the --mixin argument help and completer with available mixins
        for verb, argument in mixin_arguments.items():
            self._update_mixin_argument(argument, mixins_by_verb.get(verb, {}))

        args = self._parser.parse_args(*args, **kwargs)

        # update args based on selected mixins
        if 'mixin_verb' in args:
            # unwrap the mixin_verb which is a default value
            args.mixin_verb = args.mixin_verb.value
            mixins = mixins_by_verb.get(args.mixin_verb, {})
            for mixin in args.mixin or ():
                if mixin not in mixins:
                    context = '.'.join(args.mixin_verb)
                    logger.warning(
                        "Mixin '{mixin}' is not available for '{context}'".
                        format_map(locals()))
                    continue
                mixin_args = mixins[mixin]
                logger.debug("Using mixin '{mixin}': {mixin_args}".format_map(
                    locals()))
                self._update_args(args, mixin_args, '.'.join(args.mixin_verb))

        # undo default value wrapping injected in the add_argument() method
        for k, v in args.__dict__.items():
            if isinstance(v, DefaultValue):
                setattr(args, k, v.value)

        return args