예제 #1
0
    def _HandleExceptionAsWarning(self, exception):
        """Use instead of HandleStageException to treat an exception as a warning.

    This is used by the ForgivingBuilderStage's to treat any exceptions as
    warnings instead of stage failures.
    """
        cros_build_lib.PrintBuildbotStepWarnings()
        cros_build_lib.Warning(self._StringifyException(exception))
        return results_lib.Results.FORGIVEN, None
예제 #2
0
def GrabRemotePackageIndex(binhost_url):
    """Grab the latest binary package database from the specified URL.

  Args:
    binhost_url: Base URL of remote packages (PORTAGE_BINHOST).

  Returns:
    A PackageIndex object, if the Packages file can be retrieved. If the
    packages file cannot be retrieved, then None is returned.
  """
    url = '%s/Packages' % binhost_url.rstrip('/')
    pkgindex = PackageIndex()
    if binhost_url.startswith('http'):
        try:
            f = _RetryUrlOpen(url)
        except urllib2.HTTPError as e:
            if e.code in HTTP_FORBIDDEN_CODES:
                cros_build_lib.PrintBuildbotStepWarnings()
                cros_build_lib.Error('Cannot GET %s: %s' % (url, str(e)))
                return None
            # Not found errors are normal if old prebuilts were cleaned out.
            if e.code in HTTP_NOT_FOUND_CODES:
                return None
            raise
    elif binhost_url.startswith('gs://'):
        cmd = [gs.GSUTIL_BIN, 'cat', url]
        try:
            output = cros_build_lib.RunCommand(cmd,
                                               redirect_stdout=True,
                                               print_cmd=False).output
        except cros_build_lib.RunCommandError as e:
            cros_build_lib.PrintBuildbotStepWarnings()
            cros_build_lib.Error('Cannot GET %s: %s' % (url, str(e)))
            return None
        f = cStringIO.StringIO(output)
    else:
        return None
    pkgindex.Read(f)
    pkgindex.header.setdefault('URI', binhost_url)
    f.close()
    return pkgindex
예제 #3
0
def UploadSymbol(sym_file,
                 upload_url,
                 file_limit=DEFAULT_FILE_LIMIT,
                 sleep=0,
                 num_errors=None):
    """Upload |sym_file| to |upload_url|

  Args:
    sym_file: The full path to the breakpad symbol to upload
    upload_url: The crash server to upload things to
    file_limit: The max file size of a symbol file before we try to strip it
    sleep: Number of seconds to sleep before running
    num_errors: An object to update with the error count (needs a .value member)
  Returns:
    The number of errors that were encountered.
  """
    if num_errors is None:
        num_errors = ctypes.c_int()
    elif num_errors.value > MAX_TOTAL_ERRORS_FOR_RETRY:
        # Abandon ship!  It's on fire!  NOoooooooooooOOOoooooo.
        return 0

    upload_file = sym_file

    if sleep:
        # Keeps us from DoS-ing the symbol server.
        time.sleep(sleep)

    cros_build_lib.Debug('uploading %s' % sym_file)

    # Ideally there'd be a tempfile.SpooledNamedTemporaryFile that we could use.
    with tempfile.NamedTemporaryFile(prefix='upload_symbols',
                                     bufsize=0) as temp_sym_file:
        if file_limit:
            # If the symbols size is too big, strip out the call frame info.  The CFI
            # is unnecessary for 32bit x86 targets where the frame pointer is used (as
            # all of ours have) and it accounts for over half the size of the symbols
            # uploaded.
            file_size = os.path.getsize(sym_file)
            if file_size > file_limit:
                cros_build_lib.Warning(
                    'stripping CFI from %s due to size %s > %s', sym_file,
                    file_size, file_limit)
                temp_sym_file.writelines([
                    x for x in open(sym_file, 'rb').readlines()
                    if not x.startswith('STACK CFI')
                ])
                upload_file = temp_sym_file.name

        # Hopefully the crash server will let it through.  But it probably won't.
        # Not sure what the best answer is in this case.
        file_size = os.path.getsize(upload_file)
        if file_size > CRASH_SERVER_FILE_LIMIT:
            cros_build_lib.PrintBuildbotStepWarnings()
            cros_build_lib.Error(
                'upload file %s is awfully large, risking rejection '
                'by symbol server (%s > %s)', sym_file, file_size,
                CRASH_SERVER_FILE_LIMIT)
            num_errors.value += 1

        # Upload the symbol file.
        try:
            cros_build_lib.RetryCommand(SymUpload,
                                        MAX_RETRIES,
                                        upload_file,
                                        upload_url,
                                        sleep=INITIAL_RETRY_DELAY)
            cros_build_lib.Info('successfully uploaded %10i bytes: %s',
                                file_size, os.path.basename(sym_file))
        except cros_build_lib.RunCommandError as e:
            cros_build_lib.Warning(
                'could not upload: %s:\n{stdout} %s\n{stderr} %s',
                os.path.basename(sym_file), e.result.output, e.result.error)
            num_errors.value += 1

    return num_errors.value
def GenerateBreakpadSymbol(elf_file,
                           debug_file=None,
                           breakpad_dir=None,
                           board=None,
                           strip_cfi=False,
                           num_errors=None):
    """Generate the symbols for |elf_file| using |debug_file|

  Args:
    elf_file: The file to dump symbols for
    debug_file: Split debug file to use for symbol information
    breakpad_dir: The dir to store the output symbol file in
    board: If |breakpad_dir| is not specified, use |board| to find it
    strip_cfi: Do not generate CFI data
    num_errors: An object to update with the error count (needs a .value member)
  Returns:
    The number of errors that were encountered.
  """
    if breakpad_dir is None:
        breakpad_dir = FindBreakpadDir(board)
    if num_errors is None:
        num_errors = ctypes.c_int()

    cmd_base = ['dump_syms']
    if strip_cfi:
        cmd_base += ['-c']
    # Some files will not be readable by non-root (e.g. set*id /bin/su).
    needs_sudo = not os.access(elf_file, os.R_OK)

    def _DumpIt(cmd_args):
        if needs_sudo:
            run_command = cros_build_lib.SudoRunCommand
        else:
            run_command = cros_build_lib.RunCommand
        return run_command(cmd_base + cmd_args,
                           redirect_stderr=True,
                           log_stdout_to_file=temp.name,
                           error_code_ok=True,
                           debug_level=logging.DEBUG)

    def _CrashCheck(ret, msg):
        if ret < 0:
            cros_build_lib.PrintBuildbotStepWarnings()
            cros_build_lib.Warning('dump_syms crashed with %s; %s',
                                   osutils.StrSignal(-ret), msg)

    osutils.SafeMakedirs(breakpad_dir)
    with tempfile.NamedTemporaryFile(dir=breakpad_dir, bufsize=0) as temp:
        if debug_file:
            # Try to dump the symbols using the debug file like normal.
            cmd_args = [elf_file, os.path.dirname(debug_file)]
            result = _DumpIt(cmd_args)

            if result.returncode:
                # Sometimes dump_syms can crash because there's too much info.
                # Try dumping and stripping the extended stuff out.  At least
                # this way we'll get the extended symbols.  http://crbug.com/266064
                _CrashCheck(result.returncode, 'retrying w/out CFI')
                cmd_args = ['-c', '-r'] + cmd_args
                result = _DumpIt(cmd_args)
                _CrashCheck(result.returncode, 'retrying w/out debug')

            basic_dump = result.returncode
        else:
            basic_dump = True

        if basic_dump:
            # If that didn't work (no debug, or dump_syms still failed), try
            # dumping just the file itself directly.
            result = _DumpIt([elf_file])
            if result.returncode:
                # A lot of files (like kernel files) contain no debug information,
                # do not consider such occurrences as errors.
                cros_build_lib.PrintBuildbotStepWarnings()
                _CrashCheck(result.returncode, 'giving up entirely')
                if 'file contains no debugging information' in result.error:
                    cros_build_lib.Warning('no symbols found for %s', elf_file)
                else:
                    num_errors.value += 1
                    cros_build_lib.Error('dumping symbols for %s failed:\n%s',
                                         elf_file, result.error)
                return num_errors.value

        # Move the dumped symbol file to the right place:
        # /build/$BOARD/usr/lib/debug/breakpad/<module-name>/<id>/<module-name>.sym
        header = ReadSymsHeader(temp)
        cros_build_lib.Info('Dumped %s as %s : %s', elf_file, header.name,
                            header.id)
        sym_file = os.path.join(breakpad_dir, header.name, header.id,
                                header.name + '.sym')
        osutils.SafeMakedirs(os.path.dirname(sym_file))
        os.rename(temp.name, sym_file)
        os.chmod(sym_file, 0644)
        temp.delete = False

    return num_errors.value
 def _CrashCheck(ret, msg):
     if ret < 0:
         cros_build_lib.PrintBuildbotStepWarnings()
         cros_build_lib.Warning('dump_syms crashed with %s; %s',
                                osutils.StrSignal(-ret), msg)
예제 #6
0
def GenerateBlameList(source_repo, lkgm_path, only_print_chumps=False):
    """Generate the blamelist since the specified manifest.

  Arguments:
    source_repo: Repository object for the source code.
    lkgm_path: Path to LKGM manifest.
    only_print_chumps: If True, only print changes that were chumped.
  """
    handler = git.Manifest(lkgm_path)
    reviewed_on_re = re.compile(r'\s*Reviewed-on:\s*(\S+)')
    author_re = re.compile(r'\s*Author:.*<(\S+)@\S+>\s*')
    committer_re = re.compile(r'\s*Commit:.*<(\S+)@\S+>\s*')
    for project in handler.projects.keys():
        rel_src_path = handler.projects[project].get('path')

        # If it's not part of our source tree, it doesn't affect our build.
        if not rel_src_path:
            continue

        # Additional case in case the repo has been removed from the manifest.
        src_path = source_repo.GetRelativePath(rel_src_path)
        if not os.path.exists(src_path):
            cros_build_lib.Info('Detected repo removed from manifest %s' %
                                project)
            continue

        revision = handler.projects[project]['revision']
        try:
            result = cros_build_lib.RunCommand(
                ['git', 'log', '--pretty=full',
                 '%s..HEAD' % revision],
                print_cmd=False,
                redirect_stdout=True,
                cwd=src_path)
        except cros_build_lib.RunCommandError as ex:
            # Git returns 128 when the revision does not exist.
            if ex.result.returncode != 128:
                raise
            cros_build_lib.Warning(
                'Detected branch removed from local checkout.')
            cros_build_lib.PrintBuildbotStepWarnings()
            return
        current_author = None
        current_committer = None
        for line in unicode(result.output, 'ascii', 'ignore').splitlines():
            author_match = author_re.match(line)
            if author_match:
                current_author = author_match.group(1)

            committer_match = committer_re.match(line)
            if committer_match:
                current_committer = committer_match.group(1)

            review_match = reviewed_on_re.match(line)
            if review_match:
                review = review_match.group(1)
                _, _, change_number = review.rpartition('/')
                items = [
                    os.path.basename(project),
                    current_author,
                    change_number,
                ]
                if current_committer != 'chrome-bot':
                    items.insert(0, 'CHUMP')
                elif only_print_chumps:
                    continue
                cros_build_lib.PrintBuildbotLink(' | '.join(items), review)
예제 #7
0
    def Report(self, out, archive_urls=None, current_version=None):
        """Generate a user friendly text display of the results data."""
        results = self._results_log

        line = '*' * 60 + '\n'
        edge = '*' * 2

        if current_version:
            out.write(line)
            out.write(edge + ' RELEASE VERSION: ' + current_version + '\n')

        out.write(line)
        out.write(edge + ' Stage Results\n')
        warnings = False

        for name, result, _, run_time in results:
            timestr = datetime.timedelta(seconds=math.ceil(run_time))

            # Don't print data on skipped stages.
            if result == self.SKIPPED:
                continue

            out.write(line)
            details = ''
            if result == self.SUCCESS:
                status = 'PASS'
            elif result == self.FORGIVEN:
                status = 'FAILED BUT FORGIVEN'
                warnings = True
            else:
                status = 'FAIL'
                if isinstance(result, cros_build_lib.RunCommandError):
                    # If there was a RunCommand error, give just the command that
                    # failed, not its full argument list, since those are usually
                    # too long.
                    details = ' in %s' % result.result.cmd[0]
                elif isinstance(result, BuildScriptFailure):
                    # BuildScriptFailure errors publish a 'short' name of the
                    # command that failed.
                    details = ' in %s' % result.shortname
                else:
                    # There was a normal error. Give the type of exception.
                    details = ' with %s' % type(result).__name__

            out.write('%s %s %s (%s)%s\n' %
                      (edge, status, name, timestr, details))

        out.write(line)

        if archive_urls:
            out.write('%s BUILD ARTIFACTS FOR THIS BUILD CAN BE FOUND AT:\n' %
                      edge)
            for board, url in sorted(archive_urls.iteritems()):
                out.write('%s  %s: %s' % (edge, board, url))
                cros_build_lib.PrintBuildbotLink('Artifacts[%s]' % board,
                                                 url,
                                                 handle=out)
            out.write(line)

        for x in self.GetTracebacks():
            if x.failed_stage and x.traceback:
                out.write('\nFailed in stage %s:\n\n' % x.failed_stage)
                out.write(x.traceback)
                out.write('\n')

        if warnings:
            cros_build_lib.PrintBuildbotStepWarnings(out)