1 # Copyright 2016 The Chromium Authors. All rights reserved. 2 # Use of this source code is governed by a BSD-style license that can be 3 # found in the LICENSE file. 4 5 6 # pylint: disable=W0201 7 8 9 from recipe_engine import recipe_api 10 11 12 BUILD_PRODUCTS_ISOLATE_WHITELIST = [ 13 'bookmaker', 14 'dm', 15 'dm.exe', 16 'dm.app', 17 'nanobench.app', 18 'get_images_from_skps', 19 'get_images_from_skps.exe', 20 'nanobench', 21 'nanobench.exe', 22 'skpbench', 23 '*.so', 24 '*.dll', 25 '*.dylib', 26 'skia_launcher', 27 'skiaserve', 28 'lib/*.so', 29 ] 30 31 32 class SkiaStepApi(recipe_api.RecipeApi): 33 34 def __init__(self, *args, **kwargs): 35 """Initialize the recipe module.""" 36 super(SkiaStepApi, self).__init__(*args, **kwargs) 37 38 self._already_ran = {} 39 self._ccache = None 40 self._checked_for_ccache = False 41 self._failed = [] 42 43 def check_failure(self): 44 """Raise an exception if any step failed.""" 45 if self._failed: 46 raise self.m.step.StepFailure('Failed build steps: %s' % 47 ', '.join([f.name for f in self._failed])) 48 49 @property 50 def failed_steps(self): 51 return self._failed[:] 52 53 def run_once(self, fn, *args, **kwargs): 54 if not fn.__name__ in self._already_ran: 55 self._already_ran[fn.__name__] = fn(*args, **kwargs) 56 return self._already_ran[fn.__name__] 57 58 def readfile(self, filename, *args, **kwargs): 59 """Convenience function for reading files.""" 60 name = kwargs.pop('name', 'read %s' % self.m.path.basename(filename)) 61 return self.m.file.read_text(name, filename, *args, **kwargs) 62 63 def writefile(self, filename, contents): 64 """Convenience function for writing files.""" 65 return self.m.file.write_text('write %s' % self.m.path.basename(filename), 66 filename, contents) 67 68 def rmtree(self, path): 69 """Wrapper around api.file.rmtree.""" 70 self.m.file.rmtree('rmtree %s' % self.m.path.basename(path), path) 71 72 def __call__(self, steptype, name, abort_on_failure=True, 73 fail_build_on_failure=True, **kwargs): 74 """Run a step. If it fails, keep going but mark the build status failed.""" 75 try: 76 with self.m.env(self.m.vars.default_env): 77 return steptype(name=name, **kwargs) 78 except self.m.step.StepFailure as e: 79 if fail_build_on_failure: 80 self._failed.append(e) 81 if abort_on_failure: 82 raise 83 84 def copy_build_products(self, src, dst): 85 """Copy whitelisted build products from src to dst.""" 86 self.m.python.inline( 87 name='copy build products', 88 program='''import errno 89 import glob 90 import os 91 import shutil 92 import sys 93 94 src = sys.argv[1] 95 dst = sys.argv[2] 96 build_products_whitelist = %s 97 98 try: 99 os.makedirs(dst) 100 except OSError as e: 101 if e.errno != errno.EEXIST: 102 raise 103 104 for pattern in build_products_whitelist: 105 path = os.path.join(src, pattern) 106 for f in glob.glob(path): 107 dst_path = os.path.join(dst, os.path.relpath(f, src)) 108 if not os.path.isdir(os.path.dirname(dst_path)): 109 os.makedirs(os.path.dirname(dst_path)) 110 print 'Copying build product %%s to %%s' %% (f, dst_path) 111 shutil.move(f, dst_path) 112 ''' % str(BUILD_PRODUCTS_ISOLATE_WHITELIST), 113 args=[src, dst], 114 infra_step=True) 115 116 def with_retry(self, steptype, name, attempts, between_attempts_fn=None, 117 abort_on_failure=True, fail_build_on_failure=True, **kwargs): 118 for attempt in xrange(attempts): 119 step_name = name 120 if attempt > 0: 121 step_name += ' (attempt %d)' % (attempt + 1) 122 try: 123 res = self(steptype, name=step_name, abort_on_failure=True, 124 fail_build_on_failure=fail_build_on_failure, **kwargs) 125 if attempt > 0 and fail_build_on_failure: 126 del self._failed[-attempt:] 127 return res 128 except self.m.step.StepFailure: 129 if attempt == attempts - 1: 130 if abort_on_failure: 131 raise 132 elif between_attempts_fn: 133 between_attempts_fn(attempt+1) 134