コード例 #1
0
 def setUp(self):
     mock.patch('gclient_utils.FileRead',
                return_value=self._GITCOOKIES).start()
     mock.patch('os.getenv', return_value={}).start()
     mock.patch('os.environ', {'HOME': '$HOME'}).start()
     mock.patch('os.path.exists', return_value=True).start()
     mock.patch(
         'subprocess2.check_output',
         side_effect=[
             subprocess2.CalledProcessError(1, ['cmd'], 'cwd', 'out', 'err')
         ],
     ).start()
     self.addCleanup(mock.patch.stopall)
     self.maxDiff = None
コード例 #2
0
def run_stream_with_retcode(*cmd, **kwargs):
    """Runs a git command as context manager yielding stdout as a PIPE.

  stderr is dropped to avoid races if the process outputs to both stdout and
  stderr.

  Raises subprocess2.CalledProcessError on nonzero return code.
  """
    kwargs.setdefault('stderr', subprocess2.VOID)
    kwargs.setdefault('stdout', subprocess2.PIPE)
    cmd = (GIT_EXE, '-c', 'color.ui=never') + cmd
    try:
        proc = subprocess2.Popen(cmd, **kwargs)
        yield proc.stdout
    finally:
        retcode = proc.wait()
        if retcode != 0:
            raise subprocess2.CalledProcessError(retcode, cmd, os.getcwd(),
                                                 None, None)
コード例 #3
0
def run_svn(*cmd, **kwargs):
  """Runs an svn command.

  Returns (stdout, stderr) as a pair of strings.

  Raises subprocess2.CalledProcessError on nonzero return code.
  """
  kwargs.setdefault('stdin', subprocess2.PIPE)
  kwargs.setdefault('stdout', subprocess2.PIPE)
  kwargs.setdefault('stderr', subprocess2.PIPE)

  cmd = (SVN_EXE,) + cmd
  proc = subprocess2.Popen(cmd, **kwargs)
  ret, err = proc.communicate()
  retcode = proc.wait()
  if retcode != 0:
    raise subprocess2.CalledProcessError(retcode, cmd, os.getcwd(), ret, err)

  return ret, err
コード例 #4
0
ファイル: git_cl_test.py プロジェクト: xincun/gypdemo
    def test_gerrit_patch_conflict(self):
        self._patch_common(is_gerrit=True)
        self.mock(git_cl, 'DieWithError',
                  lambda msg: self._mocked_call(['DieWithError', msg]))

        class SystemExitMock(Exception):
            pass

        self.calls += [
            (([
                'git', 'fetch', 'https://chromium.googlesource.com/my/repo',
                'refs/changes/56/123456/1'
            ], ), ''),
            ((['git', 'cherry-pick', 'FETCH_HEAD'], ), '',
             subprocess2.CalledProcessError(1, '', '', '', '')),
            ((['DieWithError', 'git cherry-pick FETCH_HEAD" failed.\n'], ), '',
             SystemExitMock()),
        ]
        with self.assertRaises(SystemExitMock):
            git_cl.main([
                'patch',
                'https://chromium-review.googlesource.com/#/c/123456/1'
            ])
コード例 #5
0
def CheckCallAndFilter(args,
                       print_stdout=False,
                       filter_fn=None,
                       show_header=False,
                       always_show_header=False,
                       retry=False,
                       **kwargs):
    """Runs a command and calls back a filter function if needed.

  Accepts all subprocess2.Popen() parameters plus:
    print_stdout: If True, the command's stdout is forwarded to stdout.
    filter_fn: A function taking a single string argument called with each line
               of the subprocess2's output. Each line has the trailing newline
               character trimmed.
    show_header: Whether to display a header before the command output.
    always_show_header: Show header even when the command produced no output.
    retry: If the process exits non-zero, sleep for a brief interval and try
           again, up to RETRY_MAX times.

  stderr is always redirected to stdout.

  Returns the output of the command as a binary string.
  """
    def show_header_if_necessary(needs_header, attempt):
        """Show the header at most once."""
        if not needs_header[0]:
            return

        needs_header[0] = False
        # Automatically generated header. We only prepend a newline if
        # always_show_header is false, since it usually indicates there's an
        # external progress display, and it's better not to clobber it in that case.
        header = '' if always_show_header else '\n'
        header += '________ running \'%s\' in \'%s\'' % (
            ' '.join(args), kwargs.get('cwd', '.'))
        if attempt:
            header += ' attempt %s / %s' % (attempt + 1, RETRY_MAX + 1)
        header += '\n'

        if print_stdout:
            stdout_write = getattr(sys.stdout, 'buffer', sys.stdout).write
            stdout_write(header.encode())
        if filter_fn:
            filter_fn(header)

    def filter_line(command_output, line_start):
        """Extract the last line from command output and filter it."""
        if not filter_fn or line_start is None:
            return
        command_output.seek(line_start)
        filter_fn(command_output.read().decode('utf-8'))

    # Initialize stdout writer if needed. On Python 3, sys.stdout does not accept
    # byte inputs and sys.stdout.buffer must be used instead.
    if print_stdout:
        sys.stdout.flush()
        stdout_write = getattr(sys.stdout, 'buffer', sys.stdout).write
    else:
        stdout_write = lambda _: None

    sleep_interval = RETRY_INITIAL_SLEEP
    run_cwd = kwargs.get('cwd', os.getcwd())
    for attempt in range(RETRY_MAX + 1):
        kid = subprocess2.Popen(args,
                                bufsize=0,
                                stdout=subprocess2.PIPE,
                                stderr=subprocess2.STDOUT,
                                **kwargs)

        GClientChildren.add(kid)

        # Store the output of the command regardless of the value of print_stdout or
        # filter_fn.
        command_output = io.BytesIO()

        # Passed as a list for "by ref" semantics.
        needs_header = [show_header]
        if always_show_header:
            show_header_if_necessary(needs_header, attempt)

        # Also, we need to forward stdout to prevent weird re-ordering of output.
        # This has to be done on a per byte basis to make sure it is not buffered:
        # normally buffering is done for each line, but if the process requests
        # input, no end-of-line character is output after the prompt and it would
        # not show up.
        try:
            line_start = None
            while True:
                in_byte = kid.stdout.read(1)
                is_newline = in_byte in (b'\n', b'\r')
                if not in_byte:
                    break

                show_header_if_necessary(needs_header, attempt)

                if is_newline:
                    filter_line(command_output, line_start)
                    line_start = None
                elif line_start is None:
                    line_start = command_output.tell()

                stdout_write(in_byte)
                command_output.write(in_byte)

            # Flush the rest of buffered output.
            sys.stdout.flush()
            if line_start is not None:
                filter_line(command_output, line_start)

            rv = kid.wait()
            kid.stdout.close()

            # Don't put this in a 'finally,' since the child may still run if we get
            # an exception.
            GClientChildren.remove(kid)

        except KeyboardInterrupt:
            print('Failed while running "%s"' % ' '.join(args),
                  file=sys.stderr)
            raise

        if rv == 0:
            return command_output.getvalue()

        if not retry:
            break

        print(
            "WARNING: subprocess '%s' in %s failed; will retry after a short "
            'nap...' % (' '.join('"%s"' % x for x in args), run_cwd))
        time.sleep(sleep_interval)
        sleep_interval *= 2

    raise subprocess2.CalledProcessError(rv, args, kwargs.get('cwd', None),
                                         None, None)
コード例 #6
0
def CheckCallAndFilter(args, stdout=None, filter_fn=None,
                       print_stdout=None, call_filter_on_first_line=False,
                       retry=False, **kwargs):
  """Runs a command and calls back a filter function if needed.

  Accepts all subprocess2.Popen() parameters plus:
    print_stdout: If True, the command's stdout is forwarded to stdout.
    filter_fn: A function taking a single string argument called with each line
               of the subprocess2's output. Each line has the trailing newline
               character trimmed.
    stdout: Can be any bufferable output.
    retry: If the process exits non-zero, sleep for a brief interval and try
           again, up to RETRY_MAX times.

  stderr is always redirected to stdout.
  """
  assert print_stdout or filter_fn
  stdout = stdout or sys.stdout
  output = cStringIO.StringIO()
  filter_fn = filter_fn or (lambda x: None)

  sleep_interval = RETRY_INITIAL_SLEEP
  run_cwd = kwargs.get('cwd', os.getcwd())
  for _ in xrange(RETRY_MAX + 1):
    kid = subprocess2.Popen(
        args, bufsize=0, stdout=subprocess2.PIPE, stderr=subprocess2.STDOUT,
        **kwargs)

    GClientChildren.add(kid)

    # Do a flush of stdout before we begin reading from the subprocess2's stdout
    stdout.flush()

    # Also, we need to forward stdout to prevent weird re-ordering of output.
    # This has to be done on a per byte basis to make sure it is not buffered:
    # normally buffering is done for each line, but if svn requests input, no
    # end-of-line character is output after the prompt and it would not show up.
    try:
      in_byte = kid.stdout.read(1)
      if in_byte:
        if call_filter_on_first_line:
          filter_fn(None)
        in_line = ''
        while in_byte:
          output.write(in_byte)
          if print_stdout:
            stdout.write(in_byte)
          if in_byte not in ['\r', '\n']:
            in_line += in_byte
          else:
            filter_fn(in_line)
            in_line = ''
          in_byte = kid.stdout.read(1)
        # Flush the rest of buffered output. This is only an issue with
        # stdout/stderr not ending with a \n.
        if len(in_line):
          filter_fn(in_line)
      rv = kid.wait()

      # Don't put this in a 'finally,' since the child may still run if we get
      # an exception.
      GClientChildren.remove(kid)

    except KeyboardInterrupt:
      print >> sys.stderr, 'Failed while running "%s"' % ' '.join(args)
      raise

    if rv == 0:
      return output.getvalue()
    if not retry:
      break
    print ("WARNING: subprocess '%s' in %s failed; will retry after a short "
           'nap...' % (' '.join('"%s"' % x for x in args), run_cwd))
    time.sleep(sleep_interval)
    sleep_interval *= 2
  raise subprocess2.CalledProcessError(
      rv, args, kwargs.get('cwd', None), None, None)
コード例 #7
0
def callError(code=1, cmd='', cwd='', stdout=b'', stderr=b''):
    return subprocess2.CalledProcessError(code, cmd, cwd, stdout, stderr)
コード例 #8
0
  def testGetUsableRevGitSvn(self):
    # pylint: disable=E1101
    options = self.Options()
    too_big = str(1e7)

    # Pretend like the git-svn repo's HEAD is at r2.
    self.mox.StubOutWithMock(gclient_scm.scm.GIT, 'GetGitSvnHeadRev', True)
    gclient_scm.scm.GIT.GetGitSvnHeadRev(cwd=self.base_path).MultipleTimes(
        ).AndReturn(2)

    self.mox.StubOutWithMock(
        gclient_scm.scm.GIT, 'GetBlessedSha1ForSvnRev', True)
    # r1 -> first fake hash, r3 -> second fake hash.
    gclient_scm.scm.GIT.GetBlessedSha1ForSvnRev(cwd=self.base_path, rev='1'
        ).AndReturn(self.fake_hash_1)
    gclient_scm.scm.GIT.GetBlessedSha1ForSvnRev(cwd=self.base_path, rev='3'
        ).MultipleTimes().AndReturn(self.fake_hash_2)

    # Ensure that we call git svn fetch if our LKGR is > the git-svn HEAD rev.
    self.mox.StubOutWithMock(gclient_scm.scm.GIT, 'Capture', True)
    gclient_scm.scm.GIT.Capture(['config', '--get', 'svn-remote.svn.fetch'],
                                cwd=self.base_path).AndReturn('blah')
    gclient_scm.scm.GIT.Capture(['fetch'], cwd=self.base_path)
    gclient_scm.scm.GIT.Capture(['svn', 'fetch'], cwd=self.base_path)
    error = subprocess2.CalledProcessError(1, 'cmd', '/cwd', 'stdout', 'stderr')
    gclient_scm.scm.GIT.Capture(['config', '--get', 'svn-remote.svn.fetch'],
                                cwd=self.base_path).AndRaise(error)
    gclient_scm.scm.GIT.Capture(['svn', 'fetch'], cwd=self.base_path)
    gclient_scm.scm.GIT.Capture(['fetch', 'origin'], cwd=self.base_path)

    self.mox.StubOutWithMock(gclient_scm.scm.GIT, 'IsGitSvn', True)
    gclient_scm.scm.GIT.IsGitSvn(cwd=self.base_path).MultipleTimes(
        ).AndReturn(True)

    self.mox.StubOutWithMock(gclient_scm.scm.GIT, 'IsValidRevision', True)
    gclient_scm.scm.GIT.IsValidRevision(cwd=self.base_path, rev=self.fake_hash_1
        ).AndReturn(True)
    gclient_scm.scm.GIT.IsValidRevision(cwd=self.base_path, rev=too_big
        ).MultipleTimes(2).AndReturn(False)

    gclient_scm.os.path.isdir(self.base_path).AndReturn(False)
    gclient_scm.os.path.isdir(self.base_path).MultipleTimes().AndReturn(True)

    self.mox.ReplayAll()

    git_svn_scm = self._scm_wrapper(url=self.url, root_dir=self.root_dir,
                                    relpath=self.relpath)
    # Without an existing checkout, this should fail.
    # TODO(dbeam) Fix this. http://crbug.com/109184
    self.assertRaises(gclient_scm.gclient_utils.Error,
                      git_svn_scm.GetUsableRev, '1', options)
    # Given an SVN revision with a git-svn checkout, it should be translated to
    # a git sha1 and be usable.
    self.assertEquals(git_svn_scm.GetUsableRev('1', options),
                      self.fake_hash_1)
    # Our fake HEAD rev is r2, so this should call git fetch and git svn fetch
    # to get more revs (pymox will complain if this doesn't happen). We mock an
    # optimized checkout the first time, so this run should call git fetch.
    self.assertEquals(git_svn_scm.GetUsableRev('3', options),
                      self.fake_hash_2)
    # The time we pretend we're not optimized, so no git fetch should fire.
    self.assertEquals(git_svn_scm.GetUsableRev('3', options),
                      self.fake_hash_2)
    # Given a git sha1 with a git-svn checkout, it should be used as is.
    self.assertEquals(git_svn_scm.GetUsableRev(self.fake_hash_1, options),
                      self.fake_hash_1)
    # We currently check for seemingly valid SVN revisions by assuming 6 digit
    # numbers, so assure that numeric revs >= 1000000 don't work.
    self.assertRaises(gclient_scm.gclient_utils.Error,
                      git_svn_scm.GetUsableRev, too_big, options)
コード例 #9
0
def CheckCallAndFilter(args,
                       stdout=None,
                       filter_fn=None,
                       print_stdout=None,
                       call_filter_on_first_line=False,
                       **kwargs):
    """Runs a command and calls back a filter function if needed.

  Accepts all subprocess2.Popen() parameters plus:
    print_stdout: If True, the command's stdout is forwarded to stdout.
    filter_fn: A function taking a single string argument called with each line
               of the subprocess2's output. Each line has the trailing newline
               character trimmed.
    stdout: Can be any bufferable output.

  stderr is always redirected to stdout.
  """
    assert print_stdout or filter_fn
    stdout = stdout or sys.stdout
    filter_fn = filter_fn or (lambda x: None)
    kid = subprocess2.Popen(args,
                            bufsize=0,
                            stdout=subprocess2.PIPE,
                            stderr=subprocess2.STDOUT,
                            **kwargs)

    # Do a flush of stdout before we begin reading from the subprocess2's stdout
    stdout.flush()

    # Also, we need to forward stdout to prevent weird re-ordering of output.
    # This has to be done on a per byte basis to make sure it is not buffered:
    # normally buffering is done for each line, but if svn requests input, no
    # end-of-line character is output after the prompt and it would not show up.
    try:
        in_byte = kid.stdout.read(1)
        if in_byte:
            if call_filter_on_first_line:
                filter_fn(None)
            in_line = ''
            while in_byte:
                if in_byte != '\r':
                    if print_stdout:
                        stdout.write(in_byte)
                    if in_byte != '\n':
                        in_line += in_byte
                    else:
                        filter_fn(in_line)
                        in_line = ''
                else:
                    filter_fn(in_line)
                    in_line = ''
                in_byte = kid.stdout.read(1)
            # Flush the rest of buffered output. This is only an issue with
            # stdout/stderr not ending with a \n.
            if len(in_line):
                filter_fn(in_line)
        rv = kid.wait()
    except KeyboardInterrupt:
        print >> sys.stderr, 'Failed while running "%s"' % ' '.join(args)
        raise

    if rv:
        raise subprocess2.CalledProcessError(rv, args, kwargs.get('cwd', None),
                                             None, None)
    return 0
コード例 #10
0
 def testHasCachedCredentials_NotLoggedIn(self):
     subprocess2.check_call_out.side_effect = [
         subprocess2.CalledProcessError(1, ['cmd'], 'cwd', 'stdout',
                                        'stderr')
     ]
     self.assertFalse(auth.Authenticator().has_cached_credentials())
コード例 #11
0
def CheckCallAndFilter(args,
                       stdout=None,
                       filter_fn=None,
                       print_stdout=None,
                       call_filter_on_first_line=False,
                       nag_timer=None,
                       nag_max=None,
                       **kwargs):
    """Runs a command and calls back a filter function if needed.

  Accepts all subprocess2.Popen() parameters plus:
    print_stdout: If True, the command's stdout is forwarded to stdout.
    filter_fn: A function taking a single string argument called with each line
               of the subprocess2's output. Each line has the trailing newline
               character trimmed.
    stdout: Can be any bufferable output.

  stderr is always redirected to stdout.
  """
    assert print_stdout or filter_fn
    stdout = stdout or sys.stdout
    filter_fn = filter_fn or (lambda x: None)
    kid = subprocess2.Popen(args,
                            bufsize=0,
                            stdout=subprocess2.PIPE,
                            stderr=subprocess2.STDOUT,
                            **kwargs)

    GClientChildren.add(kid)

    # Do a flush of stdout before we begin reading from the subprocess2's stdout
    stdout.flush()

    nag = None
    if nag_timer:
        # Hack thread.index to force correct annotation.
        index = getattr(threading.currentThread(), 'index', 0)

        def _nag_cb(elapsed):
            setattr(threading.currentThread(), 'index', index)
            stdout.write('  No output for %.0f seconds from command:\n' %
                         elapsed)
            stdout.write('    %s\n' % kid.cmd_str)
            if (nag_max and int('%.0f' % (elapsed / nag_timer)) >= nag_max):
                stdout.write('  ... killing it!\n')
                kid.kill()

        nag = subprocess2.NagTimer(nag_timer, _nag_cb)
        nag.start()

    # Also, we need to forward stdout to prevent weird re-ordering of output.
    # This has to be done on a per byte basis to make sure it is not buffered:
    # normally buffering is done for each line, but if svn requests input, no
    # end-of-line character is output after the prompt and it would not show up.
    try:
        in_byte = kid.stdout.read(1)
        if in_byte:
            if nag:
                nag.event()
            if call_filter_on_first_line:
                filter_fn(None)
            in_line = ''
            while in_byte:
                if in_byte != '\r':
                    if print_stdout:
                        stdout.write(in_byte)
                    if in_byte != '\n':
                        in_line += in_byte
                    else:
                        filter_fn(in_line)
                        in_line = ''
                else:
                    filter_fn(in_line)
                    in_line = ''
                in_byte = kid.stdout.read(1)
                if in_byte and nag:
                    nag.event()
            # Flush the rest of buffered output. This is only an issue with
            # stdout/stderr not ending with a \n.
            if len(in_line):
                filter_fn(in_line)
        rv = kid.wait()

        # Don't put this in a 'finally,' since the child may still run if we get an
        # exception.
        GClientChildren.remove(kid)

    except KeyboardInterrupt:
        print >> sys.stderr, 'Failed while running "%s"' % ' '.join(args)
        raise
    finally:
        if nag:
            nag.cancel()

    if rv:
        raise subprocess2.CalledProcessError(rv, args, kwargs.get('cwd', None),
                                             None, None)
    return 0
コード例 #12
0
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

import gclient_paths
import gclient_utils
import subprocess2

if sys.version_info.major == 2:
  from StringIO import StringIO
  import mock
else:
  from io import StringIO
  from unittest import mock


EXCEPTION = subprocess2.CalledProcessError(
    128, ['cmd'], 'cwd', 'stdout', 'stderr')


class TestBase(unittest.TestCase):
  def setUp(self):
    super(TestBase, self).setUp()
    self.file_tree = {}
    self.root = 'C:\\' if sys.platform == 'win32' else '/'
    self.cwd = self.root
    mock.patch('gclient_utils.FileRead', self.read).start()
    mock.patch('os.environ', {}).start()
    mock.patch('os.getcwd', self.getcwd).start()
    mock.patch('os.path.exists', self.exists).start()
    mock.patch('os.path.realpath', side_effect=lambda path: path).start()
    mock.patch('subprocess2.check_output').start()
    mock.patch('sys.platform', '').start()