def testInvalidCharacterInArgException(self):
     args = ['command', '--foo', b'\xce\x94']
     exc = exceptions.InvalidCharacterInArgException(args, args[-1])
     self.assertRegexpMatches(
         six.text_type(exc),
         'Failed to read command line argument \\[\\\\u0394\\]')
     self.assertTrue(
         six.text_type(exc).endswith(('\n'
                                      'command --foo \\u0394\n'
                                      '              ^ invalid character')))
Example #2
0
    def _ConvertNonAsciiArgsToUnicode(self, args):
        """Converts non-ascii args to unicode.

    The args most likely came from sys.argv, and Python 2.7 passes them in as
    bytestrings instead of unicode.

    Args:
      args: [str], The list of args to convert.

    Raises:
      InvalidCharacterInArgException if a non-ascii arg cannot be converted to
      unicode.

    Returns:
      A new list of args with non-ascii args converted to unicode.
    """
        console_encoding = console_attr.GetConsoleAttr().GetEncoding()
        filesystem_encoding = sys.getfilesystemencoding()
        argv = []
        for arg in args:

            try:
                arg.encode('ascii')
                # Already ascii.
                argv.append(arg)
                continue
            except UnicodeError:
                pass

            try:
                # Convert bytestring to unicode using the console encoding.
                argv.append(unicode(arg, console_encoding))
                continue
            except TypeError:
                # Already unicode.
                argv.append(arg)
                continue
            except UnicodeError:
                pass

            try:
                # Convert bytestring to unicode using the filesystem encoding.
                # A pathname could have been passed in rather than typed, and
                # might not match the user terminal encoding, but still be a valid
                # path. For example: $ foo $(grep -l bar *)
                argv.append(unicode(arg, filesystem_encoding))
                continue
            except UnicodeError:
                pass

            # Can't convert to unicode -- bail out.
            raise exceptions.InvalidCharacterInArgException([self.name] + args,
                                                            arg)

        return argv
 def testInvalidCharacterInArgException_ComplexPath(self):
     command_path = os.path.join('path', 'to', 'command.py')
     args = [command_path, '--foo', b'\xce\x94']
     exc = exceptions.InvalidCharacterInArgException(args, args[-1])
     self.assertRegexpMatches(
         six.text_type(exc),
         'Failed to read command line argument \\[\\\\u0394\\]')
     self.assertTrue(
         six.text_type(exc).endswith(('\n'
                                      'command --foo \\u0394\n'
                                      '              ^ invalid character')))
     self.assertNotIn('path', six.text_type(exc))
  def _EnforceAsciiArgs(self, argv):
    """Fail if any arg in argv is not ascii.

    Args:
      argv: [str], The list of args to check.

    Raises:
      InvalidCharacterInArgException if there is a non-ascii arg.
    """
    for arg in argv:
      try:
        arg.decode('ascii')
      except UnicodeError:
        raise exceptions.InvalidCharacterInArgException([self.name] + argv, arg)
Example #5
0
  def _ConvertNonAsciiArgsToUnicode(self, args):
    """Converts non-ascii args to unicode.

    The args most likely came from sys.argv, and Python 2.7 passes them in as
    bytestrings instead of unicode.

    Args:
      args: [str], The list of args to convert.

    Raises:
      InvalidCharacterInArgException if a non-ascii arg cannot be converted to
      unicode.

    Returns:
      A new list of args with non-ascii args converted to unicode.
    """
    argv = []
    for arg in args:
      if isinstance(arg, six.text_type):
        # Arg is already a text string, just use it.
        argv.append(arg)
      else:
        # Argument is a byte string.
        try:
          # For now we want to leave byte strings as is if they are only ascii
          # characters. Later we should always convert everything to text.
          decoded_arg = arg.decode('ascii')  # If this passes, it's ascii only.
          # Add the original byte string if on PY2, for PY3 start living in the
          # text only world.
          argv.append(arg if six.PY2 else decoded_arg)
        except UnicodeError:
          # There are unicode characters in the byte string.
          try:
            argv.append(console_attr.Decode(arg))
          except UnicodeError:
            raise exceptions.InvalidCharacterInArgException(
                [self.name] + args, arg)
    return argv
Example #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)