Пример #1
0
  def __init__(self, adb, suffix='', prefix='temp_file', dir='/data/local/tmp'):
    """Find an unused temporary file path in the devices external directory.

    When this object is closed, the file will be deleted on the device.

    Args:
      adb: An instance of AdbWrapper
      suffix: The suffix of the name of the temp file.
      prefix: The prefix of the name of the temp file.
      dir: The directory on the device where to place the temp file.
    """
    self._adb = adb
    # make sure that the temp dir is writable
    self._adb.Shell('test -d %s' % cmd_helper.SingleQuote(dir))
    while True:
      self.name = '{dir}/{prefix}-{time:d}-{nonce:d}{suffix}'.format(
        dir=dir, prefix=prefix, time=int(time.time()),
        nonce=random.randint(0, 1000000), suffix=suffix)
      self.name_quoted = cmd_helper.SingleQuote(self.name)
      try:
        self._adb.Shell('test -e %s' % self.name_quoted)
      except device_errors.AdbCommandFailedError:
        break # file does not exist

    # Immediately touch the file, so other temp files can't get the same name.
    self._adb.Shell('touch %s' % self.name_quoted)
Пример #2
0
    def WriteTextFile(self,
                      device_path,
                      text,
                      as_root=False,
                      timeout=None,
                      retries=None):
        """Writes |text| to a file on the device.

    Assuming that |text| is a small string, this is typically more efficient
    than |WriteFile|, as no files are pushed into the device.

    Args:
      device_path: A string containing the absolute path to the file to write
                   on the device.
      text: A short string of text to write to the file on the device.
      as_root: A boolean indicating whether the write should be executed with
               root privileges.
      timeout: timeout in seconds
      retries: number of retries

    Raises:
      CommandFailedError if the file could not be written on the device.
      CommandTimeoutError on timeout.
      DeviceUnreachableError on missing device.
    """
        cmd = 'echo %s > %s' % (cmd_helper.SingleQuote(text),
                                cmd_helper.SingleQuote(device_path))
        self._RunShellCommandImpl(cmd, as_root=as_root, check_return=True)
Пример #3
0
    def WriteFile(self,
                  device_path,
                  contents,
                  as_root=False,
                  force_push=False,
                  timeout=None,
                  retries=None):
        """Writes |contents| to a file on the device.

    Args:
      device_path: A string containing the absolute path to the file to write
          on the device.
      contents: A string containing the data to write to the device.
      as_root: A boolean indicating whether the write should be executed with
          root privileges (if available).
      force_push: A boolean indicating whether to force the operation to be
          performed by pushing a file to the device. The default is, when the
          contents are short, to pass the contents using a shell script instead.
      timeout: timeout in seconds
      retries: number of retries

    Raises:
      CommandFailedError if the file could not be written on the device.
      CommandTimeoutError on timeout.
      DeviceUnreachableError on missing device.
    """
        if len(contents) < 512 and not force_push:
            cmd = 'echo -n %s > %s' % (cmd_helper.SingleQuote(contents),
                                       cmd_helper.SingleQuote(device_path))
            self.RunShellCommand(cmd, as_root=as_root, check_return=True)
        else:
            with tempfile.NamedTemporaryFile() as host_temp:
                host_temp.write(contents)
                host_temp.flush()
                if as_root and self.NeedsSU():
                    with device_temp_file.DeviceTempFile(
                            self.adb) as device_temp:
                        self.adb.Push(host_temp.name, device_temp.name)
                        # Here we need 'cp' rather than 'mv' because the temp and
                        # destination files might be on different file systems (e.g.
                        # on internal storage and an external sd card)
                        self.RunShellCommand(
                            ['cp', device_temp.name, device_path],
                            as_root=True,
                            check_return=True)
                else:
                    self.adb.Push(host_temp.name, device_path)
Пример #4
0
    def _RunShellCommandImpl(self,
                             cmd,
                             check_return=False,
                             cwd=None,
                             env=None,
                             as_root=False,
                             single_line=False,
                             timeout=None):
        def env_quote(key, value):
            if not DeviceUtils._VALID_SHELL_VARIABLE.match(key):
                raise KeyError('Invalid shell variable name %r' % key)
            # using double quotes here to allow interpolation of shell variables
            return '%s=%s' % (key, cmd_helper.DoubleQuote(value))

        if not isinstance(cmd, basestring):
            cmd = ' '.join(cmd_helper.SingleQuote(s) for s in cmd)
        if as_root and not self._HasRootImpl():
            cmd = 'su -c %s' % cmd
        if env:
            env = ' '.join(env_quote(k, v) for k, v in env.iteritems())
            cmd = '%s %s' % (env, cmd)
        if cwd:
            cmd = 'cd %s && %s' % (cmd_helper.SingleQuote(cwd), cmd)
        if timeout is None:
            timeout = self._default_timeout

        try:
            # TODO(perezju) still need to make sure that we call a version of
            # adb.Shell without a timeout-and-retries wrapper.
            output = self.adb.Shell(cmd,
                                    expect_rc=0,
                                    timeout=timeout,
                                    retries=0)
        except device_errors.AdbShellCommandFailedError as e:
            if check_return:
                raise
            else:
                output = e.output

        output = output.splitlines()
        if single_line:
            if len(output) != 1:
                msg = 'exactly one line of output expected, but got: %s'
                raise device_errors.CommandFailedError(msg % output)
            return output[0]
        else:
            return output
Пример #5
0
  def WriteFile(self, device_path, contents, as_root=False, force_push=False,
                timeout=None, retries=None):
    """Writes |contents| to a file on the device.

    Args:
      device_path: A string containing the absolute path to the file to write
          on the device.
      contents: A string containing the data to write to the device.
      as_root: A boolean indicating whether the write should be executed with
          root privileges (if available).
      force_push: A boolean indicating whether to force the operation to be
          performed by pushing a file to the device. The default is, when the
          contents are short, to pass the contents using a shell script instead.
      timeout: timeout in seconds
      retries: number of retries

    Raises:
      CommandFailedError if the file could not be written on the device.
      CommandTimeoutError on timeout.
      DeviceUnreachableError on missing device.
    """
    if not force_push and len(contents) < self._MAX_ADB_COMMAND_LENGTH:
      # If the contents are small, for efficieny we write the contents with
      # a shell command rather than pushing a file.
      cmd = 'echo -n %s > %s' % (cmd_helper.SingleQuote(contents),
                                 cmd_helper.SingleQuote(device_path))
      self.RunShellCommand(cmd, as_root=as_root, check_return=True)
    elif as_root and self.NeedsSU():
      # Adb does not allow to "push with su", so we first push to a temp file
      # on a safe location, and then copy it to the desired location with su.
      with device_temp_file.DeviceTempFile(self.adb) as device_temp:
        self._WriteFileWithPush(device_temp.name, contents)
        # Here we need 'cp' rather than 'mv' because the temp and
        # destination files might be on different file systems (e.g.
        # on internal storage and an external sd card).
        self.RunShellCommand(['cp', device_temp.name, device_path],
                             as_root=True, check_return=True)
    else:
      # If root is not needed, we can push directly to the desired location.
      self._WriteFileWithPush(device_path, contents)
Пример #6
0
    def __init__(self,
                 adb,
                 suffix='',
                 prefix='temp_file',
                 dir='/data/local/tmp'):
        """Find an unused temporary file path in the devices external directory.

    When this object is closed, the file will be deleted on the device.

    Args:
      adb: An instance of AdbWrapper
      suffix: The suffix of the name of the temp file.
      prefix: The prefix of the name of the temp file.
      dir: The directory on the device where to place the temp file.
    """
        self._adb = adb
        command = _COMMAND_TEMPLATE.format(
            dir=cmd_helper.SingleQuote(dir),
            suffix=cmd_helper.SingleQuote(suffix),
            prefix=cmd_helper.SingleQuote(prefix))
        self.name = self._adb.Shell(command)
        self.name_quoted = cmd_helper.SingleQuote(self.name)
Пример #7
0
 def __init__(self, args, output, status=None, device_serial=None,
              message=None):
   self.args = args
   self.output = output
   self.status = status
   if not message:
     adb_cmd = ' '.join(cmd_helper.SingleQuote(arg) for arg in self.args)
     message = ['adb %s: failed ' % adb_cmd]
     if status:
       message.append('with exit status %s ' % self.status)
     if output:
       message.append('and output:\n')
       message.extend('- %s\n' % line for line in output.splitlines())
     else:
       message.append('and no output.')
     message = ''.join(message)
   super(AdbCommandFailedError, self).__init__(message, device_serial)
Пример #8
0
 def __init__(self, cmd, output, status=None, device_serial=None):
     self.cmd = cmd
     self.output = output
     self.status = status
     message = []
     if self.cmd[0] == 'shell':
         assert len(self.cmd) == 2
         message.append('adb shell command %r failed with' % self.cmd[1])
     else:
         command = ' '.join(cmd_helper.SingleQuote(arg) for arg in self.cmd)
         message.append('adb command %r failed with' % command)
     if status:
         message.append(' exit status %d and' % self.status)
     if output:
         message.append(' output:\n')
         message.extend('> %s\n' % line for line in output.splitlines())
     else:
         message.append(' no output')
     super(AdbCommandFailedError, self).__init__(''.join(message),
                                                 device_serial)
Пример #9
0
    def RunShellCommand(self,
                        cmd,
                        check_return=False,
                        cwd=None,
                        env=None,
                        as_root=False,
                        single_line=False,
                        timeout=None,
                        retries=None):
        """Run an ADB shell command.

    The command to run |cmd| should be a sequence of program arguments or else
    a single string.

    When |cmd| is a sequence, it is assumed to contain the name of the command
    to run followed by its arguments. In this case, arguments are passed to the
    command exactly as given, without any further processing by the shell. This
    allows to easily pass arguments containing spaces or special characters
    without having to worry about getting quoting right. Whenever possible, it
    is recomended to pass |cmd| as a sequence.

    When |cmd| is given as a string, it will be interpreted and run by the
    shell on the device.

    This behaviour is consistent with that of command runners in cmd_helper as
    well as Python's own subprocess.Popen.

    TODO(perezju) Change the default of |check_return| to True when callers
      have switched to the new behaviour.

    Args:
      cmd: A string with the full command to run on the device, or a sequence
        containing the command and its arguments.
      check_return: A boolean indicating whether or not the return code should
        be checked.
      cwd: The device directory in which the command should be run.
      env: The environment variables with which the command should be run.
      as_root: A boolean indicating whether the shell command should be run
        with root privileges.
      single_line: A boolean indicating if only a single line of output is
        expected.
      timeout: timeout in seconds
      retries: number of retries

    Returns:
      If single_line is False, the output of the command as a list of lines,
      otherwise, a string with the unique line of output emmited by the command
      (with the optional newline at the end stripped).

    Raises:
      AdbCommandFailedError if check_return is True and the exit code of
        the command run on the device is non-zero.
      CommandFailedError if single_line is True but the output contains two or
        more lines.
      CommandTimeoutError on timeout.
      DeviceUnreachableError on missing device.
    """
        def env_quote(key, value):
            if not DeviceUtils._VALID_SHELL_VARIABLE.match(key):
                raise KeyError('Invalid shell variable name %r' % key)
            # using double quotes here to allow interpolation of shell variables
            return '%s=%s' % (key, cmd_helper.DoubleQuote(value))

        if not isinstance(cmd, basestring):
            cmd = ' '.join(cmd_helper.SingleQuote(s) for s in cmd)
        if env:
            env = ' '.join(env_quote(k, v) for k, v in env.iteritems())
            cmd = '%s %s' % (env, cmd)
        if cwd:
            cmd = 'cd %s && %s' % (cmd_helper.SingleQuote(cwd), cmd)
        if as_root and self.NeedsSU():
            # "su -c sh -c" allows using shell features in |cmd|
            cmd = 'su -c sh -c %s' % cmd_helper.SingleQuote(cmd)
        if timeout is None:
            timeout = self._default_timeout

        try:
            output = self.adb.Shell(cmd)
        except device_errors.AdbCommandFailedError as e:
            if check_return:
                raise
            else:
                output = e.output

        output = output.splitlines()
        if single_line:
            if not output:
                return ''
            elif len(output) == 1:
                return output[0]
            else:
                msg = 'one line of output was expected, but got: %s'
                raise device_errors.CommandFailedError(msg % output, str(self))
        else:
            return output
Пример #10
0
 def testSingleQuote_dontExpand(self):
     test_string = 'hello $TEST_VAR'
     cmd = 'TEST_VAR=world; echo %s' % cmd_helper.SingleQuote(test_string)
     self.assertEquals(test_string,
                       cmd_helper.GetCmdOutput(cmd, shell=True).rstrip())
Пример #11
0
 def testSingleQuote_withUnsafeChars(self):
     self.assertEquals("""'hello'"'"'; rm -rf /'""",
                       cmd_helper.SingleQuote("hello'; rm -rf /"))
Пример #12
0
 def testSingleQuote_withSpaces(self):
     self.assertEquals("'hello world'",
                       cmd_helper.SingleQuote('hello world'))
Пример #13
0
 def testSingleQuote_basic(self):
     self.assertEquals('hello', cmd_helper.SingleQuote('hello'))