Commit dc58a97f authored by tandrii@chromium.org's avatar tandrii@chromium.org

Finally get rid of depot_tools' breakpad.

Reland of http://crrev.com/1689633002#ps20001 without breaking other
repos by means of keeping breakpad.py importable, but otherwise a no-op.

R=maruel@chromium.org
BUG=585837

Review URL: https://codereview.chromium.org/1687923002

git-svn-id: svn://svn.chromium.org/chrome/trunk/tools/depot_tools@298731 0039d316-1c4b-4281-b951-d872f2087c98
parent 1dda36db
......@@ -14,7 +14,6 @@ import subprocess
import sys
import urllib2
import breakpad # pylint: disable=W0611
import annotated_gclient
import auth
......
......@@ -2,146 +2,11 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Breakpad for Python.
"""This file remains here because of multiple find_depot_tools.py scripts
that attempt to import it as a way to find depot_tools.
Sends a notification when a process stops on an exception.
It is only enabled when all these conditions are met:
1. hostname finishes with '.google.com' or 'chromium.org'
2. main module name doesn't contain the word 'test'
3. no NO_BREAKPAD environment variable is defined
See also:
* http://crbug.com/585837
* Example of find_depot_tools in build repo:
https://chromium.googlesource.com/chromium/tools/build/+/2680bd4/scripts/common/find_depot_tools.py
"""
import atexit
import getpass
import os
import socket
import sys
import time
import traceback
import urllib
import urllib2
# Configure these values.
DEFAULT_URL = 'https://chromium-status.appspot.com'
# Global variable to prevent double registration.
_REGISTERED = False
_TIME_STARTED = time.time()
_HOST_NAME = socket.getfqdn()
# Skip unit tests and we don't want anything from non-googler.
IS_ENABLED = (
not 'test' in getattr(sys.modules['__main__'], '__file__', '') and
not 'NO_BREAKPAD' in os.environ and
_HOST_NAME.endswith(('.google.com', '.chromium.org')))
def post(url, params):
"""HTTP POST with timeout when it's supported."""
if not IS_ENABLED:
# Make sure to not send anything for non googler.
return
kwargs = {}
if (sys.version_info[0] * 10 + sys.version_info[1]) >= 26:
kwargs['timeout'] = 4
try:
request = urllib2.urlopen(url, urllib.urlencode(params), **kwargs)
out = request.read()
request.close()
return out
except IOError:
return 'There was a failure while trying to send the stack trace. Too bad.'
def FormatException(e):
"""Returns a human readable form of an exception.
Adds the maximum number of interesting information in the safest way."""
try:
out = repr(e)
except Exception:
out = ''
try:
out = str(e)
if isinstance(e, Exception):
# urllib exceptions, usually the HTTP headers.
if hasattr(e, 'headers'):
out += '\nHeaders: %s' % e.headers
if hasattr(e, 'url'):
out += '\nUrl: %s' % e.url
if hasattr(e, 'msg'):
out += '\nMsg: %s' % e.msg
# The web page in some urllib exceptions.
if hasattr(e, 'read') and callable(e.read):
out += '\nread(): %s' % e.read()
if hasattr(e, 'info') and callable(e.info):
out += '\ninfo(): %s' % e.info()
except Exception:
pass
return out
def SendStack(last_tb, stack, url=None, maxlen=50, verbose=True):
"""Sends the stack trace to the breakpad server."""
if not IS_ENABLED:
return
def p(o):
if verbose:
print(o)
p('Sending crash report ...')
params = {
'args': sys.argv,
'cwd': os.getcwd(),
'exception': FormatException(last_tb),
'host': _HOST_NAME,
'stack': stack[0:4096],
'user': getpass.getuser(),
'version': sys.version,
}
p('\n'.join(' %s: %s' % (k, params[k][0:maxlen]) for k in sorted(params)))
p(post(url or DEFAULT_URL + '/breakpad', params))
def SendProfiling(duration, url=None):
params = {
'argv': ' '.join(sys.argv),
# Strip the hostname.
'domain': _HOST_NAME.split('.', 1)[-1],
'duration': duration,
'platform': sys.platform,
}
post(url or DEFAULT_URL + '/profiling', params)
def CheckForException():
"""Runs at exit. Look if there was an exception active."""
last_value = getattr(sys, 'last_value', None)
if last_value:
if not isinstance(last_value, KeyboardInterrupt):
last_tb = getattr(sys, 'last_traceback', None)
if last_tb:
SendStack(last_value, ''.join(traceback.format_tb(last_tb)))
else:
duration = time.time() - _TIME_STARTED
if duration > 90:
SendProfiling(duration)
def Register():
"""Registers the callback at exit. Calling it multiple times is no-op."""
global _REGISTERED
if _REGISTERED:
return
_REGISTERED = True
atexit.register(CheckForException)
if IS_ENABLED:
Register()
# Uncomment this line if you want to test it out.
#Register()
......@@ -16,8 +16,6 @@ import os
import sys
import urllib2
import breakpad # pylint: disable=W0611
import auth
import fix_encoding
import rietveld
......
......@@ -10,7 +10,6 @@ import re
import sys
import urlparse
import breakpad # pylint: disable=W0611
import gclient_utils
import subprocess2
......@@ -377,7 +376,7 @@ def getSVNAuthInfo(folder=None):
try:
for auth_file in os.listdir(svn_simple_folder):
# Read the SVN auth file, convert it into a dictionary, and store it.
results[auth_file] = dict(re.findall(r'K [0-9]+\n(.*)\nV [0-9]+\n(.*)\n',
results[auth_file] = dict(re.findall(r'K [0-9]+\n(.*)\nV [0-9]+\n(.*)\n',
open(os.path.join(svn_simple_folder, auth_file)).read()))
except Exception as _:
pass
......@@ -391,7 +390,7 @@ def getCurrentSVNUsers(url):
auth_infos = getSVNAuthInfo()
results = []
for _, auth_info in auth_infos.iteritems():
if ('svn:realmstring' in auth_info
if ('svn:realmstring' in auth_info
and netloc in auth_info['svn:realmstring']):
username = auth_info['username']
results.append(username)
......
......@@ -20,8 +20,6 @@ import tempfile
import time
import urllib2
import breakpad # pylint: disable=W0611
import auth
import fix_encoding
......@@ -743,12 +741,6 @@ def GetTreeStatus():
def OptionallyDoPresubmitChecks(change_info, committing, args):
if FilterFlag(args, "--no_presubmit") or FilterFlag(args, "--force"):
breakpad.SendStack(
breakpad.DEFAULT_URL + '/breakpad',
'GclHooksBypassedCommit',
'Issue %s/%s bypassed hook when committing (tree status was "%s")' %
(change_info.rietveld, change_info.issue, GetTreeStatus()),
verbose=False)
return presubmit_support.PresubmitOutput()
return DoPresubmitChecks(change_info, committing, True)
......
......@@ -95,8 +95,6 @@ import time
import urllib
import urlparse
import breakpad # pylint: disable=W0611
import fix_encoding
import gclient_scm
import gclient_utils
......
......@@ -40,7 +40,6 @@ from third_party import httplib2
from third_party import upload
import auth
from luci_hacks import trigger_luci_job as luci_trigger
import breakpad # pylint: disable=W0611
import clang_format
import commit_queue
import dart_format
......@@ -2619,12 +2618,6 @@ def SendUpstream(parser, args, cmd):
print('Unable to determine tree status. Please verify manually and '
'use "git cl %s --bypass-hooks" to commit on a closed tree.' % cmd)
return 1
else:
breakpad.SendStack(
'GitClHooksBypassedCommit',
'Issue %s/%s bypassed hook when committing (tree status was "%s")' %
(cl.GetRietveldServer(), cl.GetIssue(), GetTreeStatus()),
verbose=False)
change_desc = ChangeDescription(options.message)
if not change_desc.description and cl.GetIssue():
......
......@@ -7,8 +7,6 @@
import logging
import sys
import breakpad # pylint: disable=W0611
from scm import GIT
import subprocess2
import third_party.upload
......
#!/usr/bin/env python
# Copyright (c) 2012 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Unit tests for breakpad.py."""
import os
import sys
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from testing_support.super_mox import SuperMoxTestBase
import breakpad
class Breakpad(SuperMoxTestBase):
"""Setups and tear downs the mocks but doesn't test anything as-is."""
def setUp(self):
super(Breakpad, self).setUp()
self.mox.StubOutWithMock(breakpad.atexit, 'register')
self.mox.StubOutWithMock(breakpad.getpass, 'getuser')
self.mox.StubOutWithMock(breakpad.urllib2, 'urlopen')
breakpad._HOST_NAME = 'bozo'
self.assertEquals(False, breakpad.IS_ENABLED)
breakpad.IS_ENABLED = True
self._old_sys_argv = breakpad.sys.argv
breakpad.sys.argv = ['my_test']
self._old_sys_version = breakpad.sys.version
breakpad.sys.version = 'random python'
def tearDown(self):
breakpad.IS_ENABLED = False
breakpad.sys.version = self._old_sys_version
breakpad.sys.argv = self._old_sys_argv
super(Breakpad, self).tearDown()
def testMembersChanged(self):
members = [
'CheckForException', 'DEFAULT_URL', 'FormatException', 'IS_ENABLED',
'Register', 'SendProfiling', 'SendStack',
'atexit', 'getpass', 'os', 'post', 'socket', 'sys', 'time', 'traceback',
'urllib', 'urllib2',
]
# If this test fails, you should add the relevant test.
self.compareMembers(breakpad, members)
def _part_1_setup_mocks(self, exception):
breakpad.os.getcwd().AndReturn('/tmp/asdf')
breakpad.getpass.getuser().AndReturn('georges')
obj = self.mox.CreateMockAnything()
kwargs = {}
if (breakpad.sys.version_info[0] * 10 + breakpad.sys.version_info[1]) >= 26:
kwargs['timeout'] = 4
breakpad.urllib2.urlopen(
'https://chromium-status.appspot.com/breakpad',
breakpad.urllib.urlencode([('exception', exception)]) + (
'&args=%5B%27my_test%27%5D'
'&stack=bar'
'&host=bozo'
'&version=random+python'
'&user=georges'
'&cwd=%2Ftmp%2Fasdf'),
**kwargs).AndReturn(obj)
obj.read().AndReturn('ok')
obj.close()
def _part_2_verify_stdout(self, exception):
self.checkstdout(
( "Sending crash report ...\n"
" args: ['my_test']\n"
" cwd: /tmp/asdf\n"
" exception: %s\n"
" host: bozo\n"
" stack: bar\n"
" user: georges\n"
" version: random python\n"
"ok\n") % exception)
def _check(self, obj, result):
self._part_1_setup_mocks(result)
self.mox.ReplayAll()
breakpad.SendStack(obj, 'bar')
self._part_2_verify_stdout(result)
def testSendBase(self):
self._check('foo', 'foo')
def testSendReprThrows(self):
class Throws(object):
def __repr__(self):
raise NotImplementedError()
def __str__(self):
return '[foo]'
self._check(Throws(), '[foo]')
def testSendStrThrows(self):
class Throws(object):
def __repr__(self):
return '[foo]'
def __str__(self):
raise NotImplementedError()
self._check(Throws(), '[foo]')
def testSendBoth(self):
class Both(object):
def __repr__(self):
return '[foo]'
def __str__(self):
return '[bar]'
self._check(Both(), '[bar]')
def testSendException(self):
obj = Exception('foo')
obj.msg = 'a message'
self._check(obj, 'foo\nMsg: a message')
if __name__ == '__main__':
import unittest
unittest.main()
......@@ -88,8 +88,6 @@ class TestGitCl(TestCase):
self.mock(git_cl, 'BranchExists', lambda _: True)
self.mock(git_cl, 'FindCodereviewSettingsFile', lambda: '')
self.mock(git_cl, 'ask_for_data', self._mocked_call)
self.mock(git_cl.breakpad, 'post', self._mocked_call)
self.mock(git_cl.breakpad, 'SendStack', self._mocked_call)
self.mock(git_cl.presubmit_support, 'DoPresubmitChecks', PresubmitMock)
self.mock(git_cl.rietveld, 'Rietveld', RietveldMock)
self.mock(git_cl.rietveld, 'CachingRietveld', RietveldMock)
......@@ -333,10 +331,6 @@ class TestGitCl(TestCase):
'config', 'branch.working.rietveldissue'],), '12345'),
((['git', 'config', 'branch.working.rietveldserver'],),
'codereview.example.com'),
((['git', 'config', 'rietveld.tree-status-url'],), ''),
(('GitClHooksBypassedCommit',
'Issue https://codereview.example.com/12345 bypassed hook when '
'committing (tree status was "unset")'), None),
]
@classmethod
......
......@@ -51,7 +51,6 @@ class TryChangeUnittest(TryChangeTestsBase):
'HELP_STRING', 'Error', 'InvalidScript', 'NoTryServerAccess',
'OptionParser', 'PrintSuccess',
'RunCommand', 'RunGit', 'SCM', 'SVN', 'TryChange', 'USAGE', 'contextlib',
'breakpad',
'datetime', 'errno', 'fix_encoding', 'gcl', 'gclient_utils',
'gerrit_util', 'gen_parser',
'getpass', 'itertools', 'json', 'logging', 'optparse', 'os', 'posixpath',
......
......@@ -26,8 +26,6 @@ import urllib
import urllib2
import urlparse
import breakpad # pylint: disable=W0611
import fix_encoding
import gcl
import gclient_utils
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment