diff options
Diffstat (limited to 'infra/bots/recipe_modules/flavor')
4 files changed, 104 insertions, 12 deletions
diff --git a/infra/bots/recipe_modules/flavor/api.py b/infra/bots/recipe_modules/flavor/api.py index 5820e0b27b..9d64a329f5 100644 --- a/infra/bots/recipe_modules/flavor/api.py +++ b/infra/bots/recipe_modules/flavor/api.py @@ -58,21 +58,21 @@ class SkiaFlavorApi(recipe_api.RecipeApi): def get_flavor(self, builder_cfg): """Return a flavor utils object specific to the given builder.""" if is_flutter(builder_cfg): - return flutter_flavor.FlutterFlavorUtils(self.m) + return flutter_flavor.FlutterFlavorUtils(self) if is_chromecast(builder_cfg): - return gn_chromecast_flavor.GNChromecastFlavorUtils(self.m) + return gn_chromecast_flavor.GNChromecastFlavorUtils(self) if is_chromebook(builder_cfg): - return gn_chromebook_flavor.GNChromebookFlavorUtils(self.m) + return gn_chromebook_flavor.GNChromebookFlavorUtils(self) if is_android(builder_cfg): - return gn_android_flavor.GNAndroidFlavorUtils(self.m) + return gn_android_flavor.GNAndroidFlavorUtils(self) elif is_ios(builder_cfg): - return ios_flavor.iOSFlavorUtils(self.m) + return ios_flavor.iOSFlavorUtils(self) elif is_pdfium(builder_cfg): - return pdfium_flavor.PDFiumFlavorUtils(self.m) + return pdfium_flavor.PDFiumFlavorUtils(self) elif is_valgrind(builder_cfg): - return valgrind_flavor.ValgrindFlavorUtils(self.m) + return valgrind_flavor.ValgrindFlavorUtils(self) else: - return gn_flavor.GNFlavorUtils(self.m) + return gn_flavor.GNFlavorUtils(self) def setup(self): self._f = self.get_flavor(self.m.vars.builder_cfg) diff --git a/infra/bots/recipe_modules/flavor/default_flavor.py b/infra/bots/recipe_modules/flavor/default_flavor.py index dacb0fd056..079cbc458d 100644 --- a/infra/bots/recipe_modules/flavor/default_flavor.py +++ b/infra/bots/recipe_modules/flavor/default_flavor.py @@ -75,8 +75,9 @@ class DefaultFlavorUtils(object): copying files between the host and Android device, as well as the 'step' function, so that commands may be run through ADB. """ - def __init__(self, m): - self.m = m + def __init__(self, module): + self.module = module + self.m = module.m self._chrome_path = None self._win_toolchain_dir = self.m.vars.slave_dir.join(WIN_TOOLCHAIN_DIR) win_toolchain_asset_path = self.m.vars.infrabots_dir.join( diff --git a/infra/bots/recipe_modules/flavor/gn_flavor.py b/infra/bots/recipe_modules/flavor/gn_flavor.py index 4ee2f8efc1..bf23375642 100644 --- a/infra/bots/recipe_modules/flavor/gn_flavor.py +++ b/infra/bots/recipe_modules/flavor/gn_flavor.py @@ -170,8 +170,7 @@ class GNFlavorUtils(default_flavor.DefaultFlavorUtils): args = [self.m.vars.slave_dir] + [str(x) for x in cmd] with self.m.step.context({'cwd': self.m.vars.skia_dir, 'env': env}): self._py('symbolized %s' % name, - self.m.vars.infrabots_dir.join('recipe_modules', 'core', - 'resources', 'symbolize_stack_trace.py'), + self.module.resource('symbolize_stack_trace.py'), args=args, infra_step=False) diff --git a/infra/bots/recipe_modules/flavor/resources/symbolize_stack_trace.py b/infra/bots/recipe_modules/flavor/resources/symbolize_stack_trace.py new file mode 100755 index 0000000000..59e1e39e08 --- /dev/null +++ b/infra/bots/recipe_modules/flavor/resources/symbolize_stack_trace.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python +# Copyright 2017 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. +# pylint: disable=line-too-long + +import collections +import os +import re +import subprocess +import sys + +# Run a command and symbolize anything that looks like a stacktrace in the +# stdout/stderr. This will return with the same error code as the command. + +# First parameter is the current working directory, which will be stripped +# out of stacktraces. The rest of the parameters will be fed to +# subprocess.check_output() and should be the command and arguments that +# will be fed in. If any environment variables are set when running this +# script, they will be automatically used by the call to +# subprocess.check_output(). + +# This wrapper function is needed to make sure stdout and stderr stay properly +# interleaved, to assist in debugging. There are no clean ways to achieve +# this with recipes. For example, running the dm step with parameters like +# stdout=api.raw_io.output(), stderr=api.raw_io.output() ended up with +# stderr and stdout being separate files, which eliminated the interwoven logs. +# Aside from specifying stdout/stderr, there are no ways to capture or reason +# about the logs of previous steps without using a wrapper like this. + +def main(basedir, cmd): + logs = collections.deque(maxlen=200) + + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + for line in iter(proc.stdout.readline, ''): + sys.stdout.write(line) + logs.append(line) + proc.wait() + print 'Command exited with code %s' % proc.returncode + # Stacktraces generally look like: + # /lib/x86_64-linux-gnu/libc.so.6(abort+0x16a) [0x7fa90e8d0c62] + # /b/s/w/irISUIyA/linux_vulkan_intel_driver_debug/./libvulkan_intel.so(+0x1f4d0a) [0x7fa909eead0a] + # /b/s/w/irISUIyA/out/Debug/dm() [0x17c3c5f] + # The stack_line regex splits those into three parts. Experimentation has + # shown that the address in () works best for external libraries, but our code + # doesn't have that. So, we capture both addresses and prefer using the first + # over the second, unless the first is blank or invalid. Relative offsets + # like abort+0x16a are ignored. + stack_line = r'^(?P<path>.+)\(\+?(?P<addr>.*)\) \[(?P<addr2>.+)\]' + # After performing addr2line, the result can be something obnoxious like: + # foo(bar) at /b/s/w/a39kd/Skia/out/Clang/../../src/gpu/Frobulator.cpp:13 + # The extra_path strips off the not-useful prefix and leaves just the + # important src/gpu/Frobulator.cpp:13 bit. + extra_path = r'/.*\.\./' + is_first = True + for line in logs: + line = line.strip() + + m = re.search(stack_line, line) + if m: + if is_first: + print '#######################################' + print 'symbolized stacktrace follows' + print '#######################################' + is_first = False + + path = m.group('path') + addr = m.group('addr') + addr2 = m.group('addr2') + if os.path.exists(path): + if not addr or not addr.startswith('0x'): + addr = addr2 + sym = subprocess.check_output(['addr2line', '-Cfpe', path, addr]) + sym = sym.strip() + # If addr2line doesn't return anything useful, we don't replace the + # original address, so the human can see it. + if sym and not sym.startswith('?'): + if path.startswith(basedir): + path = path[len(basedir)+1:] + sym = re.sub(extra_path, '', sym) + line = path + ' ' + sym + print line + + sys.exit(proc.returncode) + + +if __name__ == '__main__': + if len(sys.argv) < 3: + print >> sys.stderr, 'USAGE: %s working_dir cmd_and_args...' % sys.argv[0] + sys.exit(1) + main(sys.argv[1], sys.argv[2:]) |