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
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
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)
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)
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)