Beispiel #1
0
def SetUpdateMask(ref, args, request):
    """Python hook that computes the update mask for a patch request.

  Args:
    ref: The game server cluster resource reference.
    args: The parsed args namespace.
    request: The update game server cluster request.
  Returns:
    Request with update mask set appropriately.
  Raises:
    NoFieldsSpecifiedError: If no fields were provided for updating.
  """
    del ref
    update_mask = []

    if args.IsSpecified('description'):
        update_mask.append('description')
    if (args.IsSpecified('update_labels') or args.IsSpecified('remove_labels')
            or args.IsSpecified('clear_labels')):
        update_mask.append('labels')

    if not args.dry_run and not update_mask:
        raise NoFieldsSpecifiedError(
            'Must specify at least one parameter to update.')

    request.updateMask = ','.join(update_mask)
    if not args.dry_run:
        log.SetUserOutputEnabled(args.user_output_enabled != 'false')
        log.status.Print('Update request issued for: [{}]'.format(
            args.cluster))
        log.SetUserOutputEnabled(False)
    return request
Beispiel #2
0
def ChooseUpdateOrPreviewMethod(unused_instance_ref, args):
    if args.dry_run:
        log.SetUserOutputEnabled(False)
        return 'previewUpdate'
    if args.preview_time:
        raise PreviewTimeFieldNotRelevantError(
            '`--preview-time` is only relevant if `--dry-run` is set to true.')
    log.SetUserOutputEnabled(False)
    return 'patch'
def CopyFilesToCodeBucket(modules, bucket, source_contexts):
    """Examines modules and copies files to a Google Cloud Storage bucket.

  Args:
    modules: [(str, ModuleYamlInfo)] List of pairs of module name, and parsed
      module information.
    bucket: str A URL to the Google Cloud Storage bucket where the files will be
      uploaded.
    source_contexts: [dict] List of json-serializable source contexts
      associated with the modules.
  Returns:
    A lookup from module name to a dictionary representing the manifest. See
    _BuildStagingDirectory.
  """
    manifests = {}
    with file_utils.TemporaryDirectory() as staging_directory:
        for (module, info) in modules:
            source_directory = os.path.dirname(info.file)
            excluded_files_regex = info.parsed.skip_files.regex

            manifest = _BuildStagingDirectory(source_directory,
                                              staging_directory, bucket,
                                              excluded_files_regex,
                                              source_contexts)
            manifests[module] = manifest

        if any(manifest for manifest in manifests.itervalues()):
            log.status.Print('Copying files to Google Cloud Storage...')
            log.status.Print('Synchronizing files to [{b}].'.format(b=bucket))
            try:
                log.SetUserOutputEnabled(False)

                def _StatusUpdate(result, unused_retry_state):
                    log.info('Error synchronizing files. Return code: {0}. '
                             'Retrying.'.format(result))

                retryer = retry.Retryer(max_retrials=3,
                                        status_update_func=_StatusUpdate)

                def _ShouldRetry(return_code, unused_retry_state):
                    return return_code != 0

                try:
                    retryer.RetryOnResult(cloud_storage.Rsync,
                                          (staging_directory, bucket),
                                          should_retry_if=_ShouldRetry)
                except retry.RetryException as e:
                    raise exceptions.ToolException((
                        'Could not synchronize files. The gsutil command exited with '
                        'status [{s}]. Command output is available in [{l}].'
                    ).format(s=e.last_result, l=log.GetLogFilePath()))
            finally:
                # Reset to the standard log level.
                log.SetUserOutputEnabled(None)

    return manifests
def ChooseUpdateOrPreviewMethod(unused_instance_ref, args):
    if args.dry_run:
        log.SetUserOutputEnabled(False)
        return 'previewUpdate'
    if args.preview_time:
        raise PreviewTimeFieldNotRelevantError(
            '`--preview-time` is only relevant if `--dry-run` is set to true.')
    log.status.Print('Update request issued for: [{}]'.format(args.realm))
    log.SetUserOutputEnabled(False)
    return 'patch'
Beispiel #5
0
def CopyFilesToCodeBucket(service, source_dir, bucket_ref):
  """Examines services and copies files to a Google Cloud Storage bucket.

  Args:
    service: ServiceYamlInfo, The parsed service information.
    source_dir: str, path to the service's source directory
    bucket_ref: str A reference to a GCS bucket where the files will be
      uploaded.

  Returns:
    A dictionary representing the manifest. See _BuildStagingDirectory.
  """
  with file_utils.TemporaryDirectory() as staging_directory:
    excluded_files_regex = service.parsed.skip_files.regex
    manifest = _BuildStagingDirectory(source_dir,
                                      staging_directory,
                                      bucket_ref,
                                      excluded_files_regex)
    if manifest:
      log.status.Print('Copying files to Google Cloud Storage...')
      log.status.Print('Synchronizing files to [{b}].'
                       .format(b=bucket_ref.bucket))
      try:
        log.SetUserOutputEnabled(False)

        def _StatusUpdate(result, unused_retry_state):
          log.info('Error synchronizing files. Return code: {0}. '
                   'Retrying.'.format(result))

        retryer = retry.Retryer(max_retrials=3,
                                status_update_func=_StatusUpdate)
        def _ShouldRetry(return_code, unused_retry_state):
          return return_code != 0

        # gsutil expects a trailing /
        dest_dir = bucket_ref.ToBucketUrl()
        try:
          retryer.RetryOnResult(
              storage_api.Rsync,
              (staging_directory, dest_dir),
              should_retry_if=_ShouldRetry)
        except retry.RetryException as e:
          raise exceptions.StorageError(
              ('Could not synchronize files. The gsutil command exited with '
               'status [{s}]. Command output is available in [{l}].').format(
                   s=e.last_result, l=log.GetLogFilePath()))
      finally:
        # Reset to the standard log level.
        log.SetUserOutputEnabled(None)
      log.status.Print('File upload done.')

  return manifest
Beispiel #6
0
 def testOutputDisabled(self):
   self.SetConsoleSize(20)
   log.SetUserOutputEnabled(False)
   with progress_tracker.ProgressTracker('tracker', autotick=True) as t:
     t.Tick()
   self.AssertOutputEquals('')
   self.AssertErrEquals('')
def ConvertOutput(response, args):
    # Try to reenable the log output which was disabled in the request hook
    log.SetUserOutputEnabled(args.user_output_enabled != 'false')
    if not args.dry_run:
        utils.WaitForOperation(response, utils.GetApiVersionFromArgs(args))
        log.status.Print('Updated realm: [{}]'.format(args.realm))
        return GetExistingResource(args)

    return response
Beispiel #8
0
def ChooseUpdateOrPreviewMethod(unused_instance_ref, args):
    """Python hook that decides to call previewUpdate or update api.

  Args:
    unused_instance_ref: The unused instace reference.
    args: The parsed args namespace.
  Returns:
    Method to be called.
  Raises:
    PreviewTimeFieldNotRelevantError: If preview-time provided when `--dry-run`
    is set to false.
  """
    if args.dry_run:
        log.SetUserOutputEnabled(False)
        return 'previewUpdate'
    if args.preview_time:
        raise PreviewTimeFieldNotRelevantError(
            '`--preview-time` is only relevant if `--dry-run` is set to true.')
    log.SetUserOutputEnabled(False)
    return 'patch'
def CopyFilesToCodeBucket(modules, bucket):
  """Examines modules and copies files to a Google Cloud Storage bucket.

  Args:
    modules: [(str, ModuleYamlInfo)] List of pairs of module name, and parsed
      module information.
    bucket: str A URL to the Google Cloud Storage bucket where the files will be
      uploaded.
  Returns:
    A lookup from module name to a dictionary representing the manifest. See
    _BuildStagingDirectory.
  """
  manifests = {}
  with file_utils.TemporaryDirectory() as staging_directory:
    for (module, info) in modules:
      source_directory = os.path.dirname(info.file)
      excluded_files_regex = info.parsed.skip_files.regex

      manifest = _BuildStagingDirectory(source_directory,
                                        staging_directory,
                                        bucket,
                                        excluded_files_regex)
      manifests[module] = manifest

    if any(manifest for manifest in manifests.itervalues()):
      log.status.Print('Copying files to Google Cloud Storage...')
      log.status.Print('Synchronizing files to [{b}].'.format(b=bucket))
      try:
        log.SetUserOutputEnabled(False)
        exit_code = cloud_storage.Rsync(staging_directory, bucket)
        if exit_code:
          raise exceptions.ToolException(
              ('Could not synchronize files. The gsutil command exited with '
               'status [{s}]. Command output is available in [{l}].').format(
                   s=exit_code, l=log.GetLogFilePath()))
      finally:
        # Reset to the standard log level.
        log.SetUserOutputEnabled(None)

  return manifests
Beispiel #10
0
def ChooseCreateOrPreviewMethod(unused_instance_ref, args):
    """Python hook that decides to call previewCreate or create api.

  Args:
    unused_instance_ref: The unused instace reference.
    args: The parsed args namespace.
  Returns:
    Method to be called.
  Raises:
    PreviewTimeFieldNotRelevantError: If preview-time provided when `--dry-run`
    is set to false.
  """
    if args.dry_run:
        log.SetUserOutputEnabled(False)
        if not args.format:
            args.format = 'yaml'
        return 'previewCreate'
    if args.preview_time:
        raise PreviewTimeFieldNotRelevantError(
            '`--preview-time` is only relevant if `--dry-run` is set to true.')
    log.status.Print('Create request issued for: [{}]'.format(args.cluster))
    log.SetUserOutputEnabled(False)
    return 'create'
Beispiel #11
0
def ConvertOutput(response, args):
    """Python hook that converts the output depending on preview or not both create and update api calls.

  Args:
    response: The reference to response instace.
    args: The parsed args namespace.
  Returns:
    Output response.
  """
    # Try to reenable the log output which was disabled in the request hook
    log.SetUserOutputEnabled(args.user_output_enabled != 'false')
    if not args.dry_run:
        utils.WaitForOperation(response, utils.GetApiVersionFromArgs(args))
        if 'update' in args.command_path:
            log.status.Print('Updated game server cluster: [{}]'.format(
                args.cluster))
        else:
            log.status.Print('Created game server cluster: [{}]'.format(
                args.cluster))
        return GetExistingResource(args)
    return response
Beispiel #12
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)
Beispiel #13
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)
Beispiel #14
0
 def SetUp(self):
     log.Reset()
     log.SetUserOutputEnabled(True)
Beispiel #15
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)
Beispiel #16
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)
Beispiel #17
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)
Beispiel #18
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)
Beispiel #19
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)
Beispiel #20
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()
Beispiel #21
0
 def SetUp(self):
   log.SetUserOutputEnabled(True)
   # Disable console_io.PromptContinue long line folding.
   self.StartObjectPatch(console_io, '_DoWrap', lambda x: x)