def __init__(self, **global_flags):
        """Creates an object to call dev_appserver.py.

    Args:
      **global_flags: {str:str}, A dictionary of global flags to pass to
        dev_appserver on each invocation.

    Raises:
      NoAppengineSDKError, If the App Engine SDK cannot be located.
    """
        self._global_flags = dict(global_flags)
        self.__executable_path = os.path.join(util.GetAppEngineSDKRoot(),
                                              'dev_appserver.py')

        verbosity_string = self.__GetVerbosityString()
        verbosity = log.VALID_VERBOSITY_STRINGS.get(verbosity_string.lower())
        if verbosity is not None:
            log.SetVerbosity(verbosity)
            # This does nothing without the above statement (since we are not
            # shelling out).
            self.AddGlobalFlagIfSet('dev_appserver_log_level',
                                    verbosity_string)
            # Set this as a default.  Will be overridden later if the flag is given.
            self.AddGlobalFlagIfSet('log_level', verbosity_string)
Exemplo n.º 2
0
    def Run(self,
            args,
            command=None,
            cli_mode=False,
            pre_run_hooks=None,
            post_run_hooks=None):
        """Run this command with the given arguments.

    Args:
      args: The arguments for this command as a namespace.
      command: The bound Command object that is used to run this Command.
      cli_mode: bool, True if running from the command line, False if running
        interactively.
      pre_run_hooks: [_RunHook], Things to run before the command.
      post_run_hooks: [_RunHook], Things to run after the command.

    Returns:
      The object returned by the module's Run() function.

    Raises:
      exceptions.Error: if thrown by the Run() function.
    """
        command_path_string = '.'.join(self._path)

        properties.VALUES.PushArgs(args)
        # Enable user output for CLI mode only if it is not explicitly set in the
        # properties (or given in the provided arguments that were just pushed into
        # the properties object).
        user_output_enabled = properties.VALUES.core.user_output_enabled.GetBool(
        )
        set_user_output_property = cli_mode and user_output_enabled is None
        if set_user_output_property:
            properties.VALUES.core.user_output_enabled.Set(True)
        # Now that we have pushed the args, reload the settings so the flags will
        # take effect.  These will use the values from the properties.
        old_user_output_enabled = log.SetUserOutputEnabled(None)
        old_verbosity = log.SetVerbosity(None)

        try:
            if cli_mode and pre_run_hooks:
                for hook in pre_run_hooks:
                    hook.Run(command_path_string)

            tool_context = self._config_hooks.load_context()
            last_group = None
            for context_filter in self._config_hooks.context_filters:
                last_group = context_filter(tool_context, args)

            command_instance = self._common_type(
                context=tool_context,
                entry_point=command.EntryPoint(),
                command=command,
                group=last_group)

            def OutputFormatter(obj):
                command_instance.Display(args, obj)

            output_formatter = OutputFormatter

            def Format(obj):
                if not obj:
                    return
                resource_printer.Print(obj, args.format or 'yaml', out=log.out)

            command_instance.format = Format
            if args.format:
                output_formatter = command_instance.format

            log.debug('Running %s with %s.', command_path_string, args)
            result = command_instance.Run(args)
            if cli_mode:
                output_formatter(result)

            if cli_mode and post_run_hooks:
                for hook in post_run_hooks:
                    hook.Run(command_path_string)

            return result

        except core_exceptions.Error as exc:
            msg = '({0}) {1}'.format(command_path_string, str(exc))
            log.debug(msg, exc_info=sys.exc_info())
            if cli_mode:
                log.error(msg)
                self._Exit(exc)
            else:
                raise
        except Exception as exc:
            # Make sure any uncaught exceptions still make it into the log file.
            log.file_only_logger.debug(str(exc), exc_info=sys.exc_info())
            raise
        finally:
            if set_user_output_property:
                properties.VALUES.core.user_output_enabled.Set(None)
            log.SetUserOutputEnabled(old_user_output_enabled)
            log.SetVerbosity(old_verbosity)
            properties.VALUES.PopArgs()
Exemplo n.º 3
0
    def Execute(self, args=None, call_arg_complete=True):
        """Execute the CLI tool with the given arguments.

    Args:
      args: [str], The arguments from the command line or None to use sys.argv
      call_arg_complete: Call the _ArgComplete function if True

    Returns:
      The result of executing the command determined by the command
      implementation.

    Raises:
      ValueError: for ill-typed arguments.
    """
        if isinstance(args, basestring):
            raise ValueError(
                'Execute expects an iterable of strings, not a string.')

        # The argparse module does not handle unicode args when run in Python 2
        # because it uses str(x) even when type(x) is unicode. This sets itself up
        # for failure because it converts unicode strings back to byte strings which
        # will trigger ASCII codec exceptions. It works in Python 3 because str() is
        # equivalent to unicode() in Python 3. The next Pythonically magic and dirty
        # statement coaxes the Python 3 behavior out of argparse running in
        # Python 2. Doing it here ensures that the workaround is in place for
        # calliope argparse use cases.
        argparse.str = unicode

        if call_arg_complete:
            _ArgComplete(self.__top_element.ai)

        if not args:
            args = sys.argv[1:]

        # help ... is the same as ... --help or ... --document=style=help. We use
        # --document=style=help to signal the metrics.Help() 'help' label in
        # actions.RenderDocumentAction().Action(). It doesn't matter if we append
        # to a command that already has --help or --document=style=... because the
        # first --help/--document from the left takes effect. Note that
        # `help ... --help` produces help for the help command itself.
        if args and args[0] == 'help' and '--help' not in args:
            args = args[1:] + ['--document=style=help']

        # Look for a --configuration flag and update property state based on
        # that before proceeding to the main argparse parse step.
        named_configs.FLAG_OVERRIDE_STACK.PushFromArgs(args)
        properties.VALUES.PushInvocationValues()

        # Set the command name in case an exception happens before the command name
        # is finished parsing.
        command_path_string = self.__name
        specified_arg_names = None

        argv = self._ConvertNonAsciiArgsToUnicode(args)
        old_user_output_enabled = None
        old_verbosity = None
        try:
            args = self.__parser.parse_args(argv)
            calliope_command = args._GetCommand()  # pylint: disable=protected-access
            command_path_string = '.'.join(calliope_command.GetPath())
            if not calliope_command.IsUnicodeSupported():
                self._EnforceAsciiArgs(argv)
            specified_arg_names = args.GetSpecifiedArgNames()

            # -h|--help|--document are dispatched by parse_args and never get here.

            # Now that we have parsed the args, reload the settings so the flags will
            # take effect.  These will use the values from the properties.
            old_user_output_enabled = log.SetUserOutputEnabled(None)
            old_verbosity = log.SetVerbosity(None)

            # Set the command_name property so it is persisted until the process ends.
            # Only do this for the top level command that can be detected by looking
            # at the stack. It will have one initial level, and another level added by
            # the PushInvocationValues earlier in this method.
            if len(properties.VALUES.GetInvocationStack()) == 2:
                properties.VALUES.metrics.command_name.Set(command_path_string)
            # Set the invocation value for all commands, this is lost when popped
            properties.VALUES.SetInvocationValue(
                properties.VALUES.metrics.command_name, command_path_string,
                None)

            if properties.VALUES.core.capture_session_file.Get() is not None:
                capturer = session_capturer.SessionCapturer()
                capturer.CaptureArgs(args)
                capturer.CaptureState()
                capturer.CaptureProperties(properties.VALUES.AllValues())
                session_capturer.SessionCapturer.capturer = capturer

            for hook in self.__pre_run_hooks:
                hook.Run(command_path_string)

            resources = calliope_command.Run(cli=self, args=args)

            for hook in self.__post_run_hooks:
                hook.Run(command_path_string)

            # Preserve generator or static list resources.

            if isinstance(resources, types.GeneratorType):

                def _Yield():
                    """Activates generator exceptions."""
                    try:
                        for resource in resources:
                            yield resource
                    except Exception as exc:  # pylint: disable=broad-except
                        self._HandleAllErrors(exc, command_path_string,
                                              specified_arg_names)

                return _Yield()

            # Do this last. If there is an error, the error handler will log the
            # command execution along with the error.
            metrics.Commands(command_path_string, config.CLOUD_SDK_VERSION,
                             specified_arg_names)
            return resources

        except Exception as exc:  # pylint: disable=broad-except
            self._HandleAllErrors(exc, command_path_string,
                                  specified_arg_names)

        finally:
            if session_capturer.SessionCapturer.capturer is not None:
                with open(properties.VALUES.core.capture_session_file.Get(),
                          'w') as f:
                    session_capturer.SessionCapturer.capturer.Print(f)
            properties.VALUES.PopInvocationValues()
            named_configs.FLAG_OVERRIDE_STACK.Pop()
            # Reset these values to their previous state now that we popped the flag
            # values.
            if old_user_output_enabled is not None:
                log.SetUserOutputEnabled(old_user_output_enabled)
            if old_verbosity is not None:
                log.SetVerbosity(old_verbosity)
Exemplo n.º 4
0
  def Execute(self, args=None, call_arg_complete=True):
    """Execute the CLI tool with the given arguments.

    Args:
      args: The arguments from the command line or None to use sys.argv
      call_arg_complete: Call the _ArgComplete function if True

    Returns:
      The result of executing the command determined by the command
      implementation.
    """
    if call_arg_complete:
      self._ArgComplete()

    if not args:
      args = sys.argv[1:]

    for s in args:
      try:
        s.decode('ascii')
      except UnicodeError:
        raise exceptions.InvalidStringException(s)

    # Set the command name in case an exception happens before the command name
    # is finished parsing.
    command_path_string = self.__name
    try:
      properties.VALUES.PushInvocationValues()
      args = self.__parser.parse_args(args)
      # -h|--help|--document are dispatched by parse_args and never get here.

      # Now that we have parsed the args, reload the settings so the flags will
      # take effect.  These will use the values from the properties.
      log.SetUserOutputEnabled(None)
      log.SetVerbosity(None)

      command_path_string = '.'.join(args.command_path)
      # TODO(user): put a real version here
      metrics.Commands(command_path_string, None)

      for hook in self.__pre_run_hooks:
        hook.Run(command_path_string)

      result = args.cmd_func(cli=self, args=args)

      for hook in self.__post_run_hooks:
        hook.Run(command_path_string)

      return result

    except exceptions.ExitCodeNoError as exc:
      self._HandleKnownError(command_path_string, exc, print_error=False)
    except core_exceptions.Error as exc:
      self._HandleKnownError(command_path_string, exc, print_error=True)
    except Exception as exc:
      # Make sure any uncaught exceptions still make it into the log file.
      log.file_only_logger.debug(str(exc), exc_info=sys.exc_info())
      metrics.Error(command_path_string, exc)
      raise
    finally:
      properties.VALUES.PopInvocationValues()
      # Reset these values to their previous state now that we popped the flag
      # values.
      log.SetUserOutputEnabled(None)
      log.SetVerbosity(None)
Exemplo n.º 5
0
 def TearDown(self):
   log.SetVerbosity(self.original_verbosity)
Exemplo n.º 6
0
    def Execute(self, args=None, call_arg_complete=True):
        """Execute the CLI tool with the given arguments.

    Args:
      args: [str], The arguments from the command line or None to use sys.argv
      call_arg_complete: Call the _ArgComplete function if True

    Returns:
      The result of executing the command determined by the command
      implementation.

    Raises:
      ValueError: for ill-typed arguments.
    """
        if type(args) is str:
            raise ValueError(
                'Execute expects an iterable of strings, not a string.')

        if call_arg_complete:
            self._ArgComplete()

        if not args:
            args = sys.argv[1:]

        # Set the command name in case an exception happens before the command name
        # is finished parsing.
        command_path_string = self.__name

        # Look for a --configuration flag and update property state based on
        # that before proceeding to the main argparse parse step.
        named_configs.FLAG_OVERRIDE_STACK.PushFromArgs(args)
        properties.VALUES.PushInvocationValues()

        flag_names = None
        try:
            for s in args:
                try:
                    s.decode('ascii')
                except UnicodeDecodeError:
                    raise exceptions.InvalidCharacterInArgException(
                        [sys.argv[0]] + args, s)

            args = self.__parser.parse_args(args)
            flag_names = self.__parser.GetFlagCollection()
            # -h|--help|--document are dispatched by parse_args and never get here.

            # Now that we have parsed the args, reload the settings so the flags will
            # take effect.  These will use the values from the properties.
            log.SetUserOutputEnabled(None)
            log.SetVerbosity(None)

            command_path_string = '.'.join(args.command_path)
            properties.VALUES.SetInvocationValue(
                properties.VALUES.metrics.command_name, command_path_string,
                None)
            metrics.Commands(command_path_string, config.CLOUD_SDK_VERSION,
                             flag_names)

            for hook in self.__pre_run_hooks:
                hook.Run(command_path_string)

            result = args.cmd_func(cli=self, args=args)

            for hook in self.__post_run_hooks:
                hook.Run(command_path_string)

            return result

        except exceptions.ExitCodeNoError as exc:
            self._HandleKnownError(command_path_string,
                                   exc,
                                   flag_names,
                                   print_error=False)
        except core_exceptions.Error as exc:
            self._HandleKnownError(command_path_string,
                                   exc,
                                   flag_names,
                                   print_error=True)
        except Exception as exc:
            if type(exc) in KNOWN_ERRORS:
                self._HandleKnownError(command_path_string,
                                       exc,
                                       flag_names,
                                       print_error=True)
            else:
                # Make sure any uncaught exceptions still make it into the log file.
                exc_printable = self.SafeExceptionToString(exc)
                log.debug(exc_printable, exc_info=sys.exc_info())
                metrics.Error(command_path_string, exc, flag_names)
                raise
        finally:
            properties.VALUES.PopInvocationValues()
            named_configs.FLAG_OVERRIDE_STACK.Pop()
            # Reset these values to their previous state now that we popped the flag
            # values.
            log.SetUserOutputEnabled(None)
            log.SetVerbosity(None)
Exemplo n.º 7
0
    def Run(self, args):
        """Creates a new Cloud SQL instance.

    Args:
      args: argparse.Namespace, The arguments that this command was invoked
          with.

    Returns:
      A dict object representing the operations resource describing the create
      operation if the create was successful.
    Raises:
      HttpException: A http error response was received while executing api
          request.
      ToolException: An error other than http error occured while executing the
          command.
    """

        # Added this temporarily for debugging SQL instance creation failures
        log.SetVerbosity(logging.DEBUG)
        sql_client = self.context['sql_client']
        sql_messages = self.context['sql_messages']
        resources = self.context['registry']

        util.ValidateInstanceName(args.instance)
        instance_ref = resources.Parse(args.instance,
                                       collection='sql.instances')

        instance_resource = util.ConstructInstanceFromArgs(sql_messages, args)

        if args.master_instance_name:
            replication = 'ASYNCHRONOUS'
            activation_policy = 'ALWAYS'
        else:
            replication = 'SYNCHRONOUS'
            activation_policy = 'ON_DEMAND'
        if not args.replication:
            instance_resource.settings.replicationType = replication
        if not args.activation_policy:
            instance_resource.settings.activationPolicy = activation_policy

        instance_resource.project = instance_ref.project
        instance_resource.instance = instance_ref.instance
        operation_ref = None

        if args.pricing_plan == 'PACKAGE':
            if not console_io.PromptContinue(
                    'Charges will begin accruing immediately. Really create Cloud '
                    'SQL instance?'):
                raise exceptions.ToolException('canceled by the user.')

        try:
            result = sql_client.instances.Insert(instance_resource)

            operation_ref = resources.Create(
                'sql.operations',
                operation=result.operation,
                project=instance_ref.project,
                instance=instance_ref.instance,
            )

            if args. async:
                return sql_client.operations.Get(operation_ref.Request())

            util.WaitForOperation(sql_client, operation_ref,
                                  'Creating Cloud SQL instance')

            log.CreatedResource(instance_ref)

            rsource = sql_client.instances.Get(instance_ref.Request())
            cache = remote_completion.RemoteCompletion()
            cache.AddToCache(instance_ref.SelfLink())
            return rsource
        except apitools_base.HttpError:
            log.debug('operation : %s', str(operation_ref))
            raise
Exemplo n.º 8
0
    def Execute(self, args=None, call_arg_complete=True):
        """Execute the CLI tool with the given arguments.

    Args:
      args: [str], The arguments from the command line or None to use sys.argv
      call_arg_complete: Call the _ArgComplete function if True

    Returns:
      The result of executing the command determined by the command
      implementation.

    Raises:
      ValueError: for ill-typed arguments.
    """
        if isinstance(args, six.string_types):
            raise ValueError(
                'Execute expects an iterable of strings, not a string.')

        # The argparse module does not handle unicode args when run in Python 2
        # because it uses str(x) even when type(x) is unicode. This sets itself up
        # for failure because it converts unicode strings back to byte strings which
        # will trigger ASCII codec exceptions. It works in Python 3 because str() is
        # equivalent to unicode() in Python 3. The next Pythonically magic and dirty
        # statement coaxes the Python 3 behavior out of argparse running in
        # Python 2. Doing it here ensures that the workaround is in place for
        # calliope argparse use cases.
        argparse.str = six.text_type
        # We need the argparse 1.2.1 patch in _SubParsersActionCall.
        # TODO(b/77288697) delete after py3 tests use non-hermetic python
        if argparse.__version__ == '1.1':
            argparse._SubParsersAction.__call__ = _SubParsersActionCall  # pylint: disable=protected-access

        if call_arg_complete:
            _ArgComplete(self.__top_element.ai)

        if not args:
            args = sys.argv[1:]

        # Look for a --configuration flag and update property state based on
        # that before proceeding to the main argparse parse step.
        named_configs.FLAG_OVERRIDE_STACK.PushFromArgs(args)
        properties.VALUES.PushInvocationValues()

        # Set the command name in case an exception happens before the command name
        # is finished parsing.
        command_path_string = self.__name
        specified_arg_names = None

        # Convert py2 args to text.
        argv = [console_attr.Decode(arg) for arg in args] if six.PY2 else args
        old_user_output_enabled = None
        old_verbosity = None
        try:
            args = self.__parser.parse_args(_ApplyFlagsFile(argv))
            if args.CONCEPT_ARGS is not None:
                args.CONCEPT_ARGS.ParseConcepts()
            calliope_command = args._GetCommand()  # pylint: disable=protected-access
            command_path_string = '.'.join(calliope_command.GetPath())
            specified_arg_names = args.GetSpecifiedArgNames()
            # If the CLI has not been reloaded since the last command execution (e.g.
            # in test runs), args.CONCEPTS may contain cached values.
            if args.CONCEPTS is not None:
                args.CONCEPTS.Reset()

            # -h|--help|--document are dispatched by parse_args and never get here.

            # Now that we have parsed the args, reload the settings so the flags will
            # take effect.  These will use the values from the properties.
            old_user_output_enabled = log.SetUserOutputEnabled(None)
            old_verbosity = log.SetVerbosity(None)

            # Set the command_name property so it is persisted until the process ends.
            # Only do this for the top level command that can be detected by looking
            # at the stack. It will have one initial level, and another level added by
            # the PushInvocationValues earlier in this method.
            if len(properties.VALUES.GetInvocationStack()) == 2:
                properties.VALUES.metrics.command_name.Set(command_path_string)
            # Set the invocation value for all commands, this is lost when popped
            properties.VALUES.SetInvocationValue(
                properties.VALUES.metrics.command_name, command_path_string,
                None)

            for hook in self.__pre_run_hooks:
                hook.Run(command_path_string)

            resources = calliope_command.Run(cli=self, args=args)

            for hook in self.__post_run_hooks:
                hook.Run(command_path_string)

            # Preserve generator or static list resources.

            if isinstance(resources, types.GeneratorType):

                def _Yield():
                    """Activates generator exceptions."""
                    try:
                        for resource in resources:
                            yield resource
                    except Exception as exc:  # pylint: disable=broad-except
                        self._HandleAllErrors(exc, command_path_string,
                                              specified_arg_names)

                return _Yield()

            # Do this last. If there is an error, the error handler will log the
            # command execution along with the error.
            metrics.Commands(command_path_string, config.CLOUD_SDK_VERSION,
                             specified_arg_names)
            return resources

        except Exception as exc:  # pylint: disable=broad-except
            self._HandleAllErrors(exc, command_path_string,
                                  specified_arg_names)

        finally:
            properties.VALUES.PopInvocationValues()
            named_configs.FLAG_OVERRIDE_STACK.Pop()
            # Reset these values to their previous state now that we popped the flag
            # values.
            if old_user_output_enabled is not None:
                log.SetUserOutputEnabled(old_user_output_enabled)
            if old_verbosity is not None:
                log.SetVerbosity(old_verbosity)
Exemplo n.º 9
0
    def Execute(self, args=None, call_arg_complete=True):
        """Execute the CLI tool with the given arguments.

    Args:
      args: [str], The arguments from the command line or None to use sys.argv
      call_arg_complete: Call the _ArgComplete function if True

    Returns:
      The result of executing the command determined by the command
      implementation.

    Raises:
      ValueError: for ill-typed arguments.
    """
        if isinstance(args, basestring):
            raise ValueError(
                'Execute expects an iterable of strings, not a string.')

        # The argparse module does not handle unicode args when run in Python 2
        # because it uses str(x) even when type(x) is unicode. This sets itself up
        # for failure because it converts unicode strings back to byte strings which
        # will trigger ASCII codec exceptions. It works in Python 3 because str() is
        # equivalent to unicode() in Python 3. The next Pythonically magic and dirty
        # statement coaxes the Python 3 behavior out of argparse running in
        # Python 2. Doing it here ensures that the workaround is in place for
        # calliope argparse use cases.
        argparse.str = unicode

        if call_arg_complete:
            self._ArgComplete()

        if not args:
            args = sys.argv[1:]

        # help ... is the same as ... --help or ... --document=style=help. We use
        # --document=style=help to signal the metrics.Help() 'help' label in
        # actions.RenderDocumentAction().Action(). It doesn't matter if we append
        # to a command that already has --help or --document=style=... because the
        # first --help/--document from the left takes effect. Note that
        # `help ... --help` produces help for the help command itself.
        if args and args[0] == 'help' and '--help' not in args:
            args = args[1:] + ['--document=style=help']

        # Look for a --configuration flag and update property state based on
        # that before proceeding to the main argparse parse step.
        named_configs.FLAG_OVERRIDE_STACK.PushFromArgs(args)
        properties.VALUES.PushInvocationValues()

        # Set the command name in case an exception happens before the command name
        # is finished parsing.
        command_path_string = self.__name
        flag_collection = None

        argv = self._ConvertNonAsciiArgsToUnicode(args)
        try:
            args = self.__parser.parse_args(argv)
            command_path_string = '.'.join(args.command_path)
            if not args.calliope_command.IsUnicodeSupported():
                self._EnforceAsciiArgs(argv)
            flag_collection = self.__parser.GetFlagCollection()

            # -h|--help|--document are dispatched by parse_args and never get here.

            # Now that we have parsed the args, reload the settings so the flags will
            # take effect.  These will use the values from the properties.
            log.SetUserOutputEnabled(None)
            log.SetVerbosity(None)

            properties.VALUES.SetInvocationValue(
                properties.VALUES.metrics.command_name, command_path_string,
                None)
            metrics.Commands(command_path_string, config.CLOUD_SDK_VERSION,
                             flag_collection)

            for hook in self.__pre_run_hooks:
                hook.Run(command_path_string)

            resources = args.calliope_command.Run(cli=self, args=args)

            for hook in self.__post_run_hooks:
                hook.Run(command_path_string)

            # Preserve generator or static list resources.

            if isinstance(resources, types.GeneratorType):

                def _Yield():
                    """Activates generator exceptions."""
                    try:
                        for resource in resources:
                            yield resource
                    except Exception as exc:  # pylint: disable=broad-except
                        self._HandleAllErrors(exc, command_path_string,
                                              flag_collection)

                return _Yield()

            return resources

        except Exception as exc:  # pylint: disable=broad-except
            self._HandleAllErrors(exc, command_path_string, flag_collection)

        finally:
            properties.VALUES.PopInvocationValues()
            named_configs.FLAG_OVERRIDE_STACK.Pop()
            # Reset these values to their previous state now that we popped the flag
            # values.
            log.SetUserOutputEnabled(None)
            log.SetVerbosity(None)
Exemplo n.º 10
0
    def Run(self, cli, args, pre_run_hooks=None, post_run_hooks=None):
        """Run this command with the given arguments.

    Args:
      cli: The cli.CLI object for this command line tool.
      args: The arguments for this command as a namespace.
      pre_run_hooks: [_RunHook], Things to run before the command.
      post_run_hooks: [_RunHook], Things to run after the command.

    Returns:
      The object returned by the module's Run() function.

    Raises:
      exceptions.Error: if thrown by the Run() function.
    """
        command_path_string = '.'.join(self._path)

        # TODO(user): user-output-enabled was mostly needed for interactive
        # mode.  There should still be the option to disable output (for things
        # like completion) but it can be cleaned up to be on by default.
        # Enable user output for CLI mode only if it is not explicitly set in the
        # properties (or given in the provided arguments that were just pushed into
        # the properties object).
        user_output_enabled = properties.VALUES.core.user_output_enabled.GetBool(
        )
        set_user_output_property = user_output_enabled is None
        if set_user_output_property:
            properties.VALUES.core.user_output_enabled.Set(True)
        # Now that we have pushed the args, reload the settings so the flags will
        # take effect.  These will use the values from the properties.
        old_user_output_enabled = log.SetUserOutputEnabled(None)
        old_verbosity = log.SetVerbosity(None)

        try:
            if pre_run_hooks:
                for hook in pre_run_hooks:
                    hook.Run(command_path_string)

            def Http(**kwargs):
                # TODO(user) This check is required due to tests that use interactive
                # mode. Remove this check when all tests are converted to use cli mode.
                if hasattr(args, 'trace_token'):
                    return core_cli.Http(cmd_path=command_path_string,
                                         trace_token=args.trace_token,
                                         **kwargs)
                else:
                    return core_cli.Http(cmd_path=command_path_string,
                                         **kwargs)

            tool_context = self._config_hooks.load_context()
            last_group = None
            for context_filter in self._config_hooks.context_filters:
                last_group = context_filter(tool_context, Http, args)

            command_instance = self._common_type(cli=cli,
                                                 context=tool_context,
                                                 group=last_group,
                                                 http_func=Http)

            def OutputFormatter(obj):
                command_instance.Display(args, obj)

            output_formatter = OutputFormatter

            def Format(obj):
                if not obj:
                    return
                resource_printer.Print(obj, args.format or 'yaml', out=log.out)

            command_instance.format = Format
            if args.format:
                output_formatter = command_instance.format

            log.debug('Running %s with %s.', command_path_string, args)
            result = command_instance.Run(args)
            if properties.VALUES.core.user_output_enabled.GetBool():
                output_formatter(result)

            if post_run_hooks:
                for hook in post_run_hooks:
                    hook.Run(command_path_string)

            return result

        except exceptions.ExitCodeNoError as exc:
            msg = '({0}) {1}'.format(command_path_string, str(exc))
            log.debug(msg, exc_info=sys.exc_info())
            self._Exit(exc)
        except core_exceptions.Error as exc:
            msg = '({0}) {1}'.format(command_path_string, str(exc))
            log.debug(msg, exc_info=sys.exc_info())
            log.error(msg)
            self._Exit(exc)
        except Exception as exc:
            # Make sure any uncaught exceptions still make it into the log file.
            log.file_only_logger.debug(str(exc), exc_info=sys.exc_info())
            raise
        finally:
            if set_user_output_property:
                properties.VALUES.core.user_output_enabled.Set(None)
            log.SetUserOutputEnabled(old_user_output_enabled)
            log.SetVerbosity(old_verbosity)
Exemplo n.º 11
0
    def Execute(self, args=None, call_arg_complete=True):
        """Execute the CLI tool with the given arguments.

    Args:
      args: [str], The arguments from the command line or None to use sys.argv
      call_arg_complete: Call the _ArgComplete function if True

    Returns:
      The result of executing the command determined by the command
      implementation.

    Raises:
      ValueError: for ill-typed arguments.
    """
        if type(args) is str:
            raise ValueError(
                'Execute expects an iterable of strings, not a string.')

        if call_arg_complete:
            self._ArgComplete()

        if not args:
            args = sys.argv[1:]

        for s in args:
            try:
                s.decode('ascii')
            except (UnicodeEncodeError, UnicodeError):
                try:
                    s_printable = s.decode('utf-8')
                except (UnicodeEncodeError, UnicodeError):
                    s_printable = repr(s)

                raise exceptions.InvalidStringException(s_printable)

        # Set the command name in case an exception happens before the command name
        # is finished parsing.
        command_path_string = self.__name

        named_configs.FLAG_OVERRIDE_STACK.AllocateFrame()
        properties.VALUES.PushInvocationValues()
        try:
            # Look for a --configuration flag and update property state based on
            # that before proceeding to the main argparse parse step.
            named_configs.FLAG_OVERRIDE_STACK.ReplaceTop(
                named_configs.AdhocConfigFlagParse(args),
                properties.PropertiesFile.Invalidate)
            args = self.__parser.parse_args(args)

            # -h|--help|--document are dispatched by parse_args and never get here.

            # In principle it's possible that the initial round of ad-hoc parsing of
            # --configuration would not agree with the later parse by argparse.  The
            # following warning is intended to be dead code, but just in case...
            if named_configs.FLAG_OVERRIDE_STACK.Peek() != args.configuration:
                log.warn('Problem parsing --configration flag.  Using named '
                         'flag value --configuration=[{0}].'.format(
                             named_configs.FLAG_OVERRIDE_STACK.Peek()))

            # Now that we have parsed the args, reload the settings so the flags will
            # take effect.  These will use the values from the properties.
            log.SetUserOutputEnabled(None)
            log.SetVerbosity(None)

            command_path_string = '.'.join(args.command_path)
            metrics.Commands(command_path_string, config.CLOUD_SDK_VERSION)

            for hook in self.__pre_run_hooks:
                hook.Run(command_path_string)

            result = args.cmd_func(cli=self, args=args)

            for hook in self.__post_run_hooks:
                hook.Run(command_path_string)

            return result

        except exceptions.ExitCodeNoError as exc:
            self._HandleKnownError(command_path_string, exc, print_error=False)
        except core_exceptions.Error as exc:
            self._HandleKnownError(command_path_string, exc, print_error=True)
        except Exception as exc:
            if type(exc) in KNOWN_ERRORS:
                self._HandleKnownError(command_path_string,
                                       exc,
                                       print_error=True)
            else:
                # Make sure any uncaught exceptions still make it into the log file.
                exc_printable = self.SafeExceptionToString(exc)
                log.file_only_logger.debug(exc_printable,
                                           exc_info=sys.exc_info())
                metrics.Error(command_path_string, exc)
                raise
        finally:
            properties.VALUES.PopInvocationValues()
            named_configs.FLAG_OVERRIDE_STACK.Pop()
            # Reset these values to their previous state now that we popped the flag
            # values.
            log.SetUserOutputEnabled(None)
            log.SetVerbosity(None)