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 9from recipe_engine import recipe_api 10 11 12TEST_DEFAULT_ASSET_VERSION = '42' 13 14class SkiaStepApi(recipe_api.RecipeApi): 15 16 def __init__(self, *args, **kwargs): 17 """Initialize the recipe module.""" 18 super(SkiaStepApi, self).__init__(*args, **kwargs) 19 20 self._already_ran = {} 21 self._ccache = None 22 self._checked_for_ccache = False 23 self._failed = [] 24 25 def check_failure(self): 26 """Raise an exception if any step failed.""" 27 if self._failed: 28 raise self.m.step.StepFailure('Failed build steps: %s' % 29 ', '.join([f.name for f in self._failed])) 30 31 @property 32 def failed_steps(self): 33 return self._failed[:] 34 35 def run_once(self, fn, *args, **kwargs): 36 if not fn.__name__ in self._already_ran: 37 self._already_ran[fn.__name__] = fn(*args, **kwargs) 38 return self._already_ran[fn.__name__] 39 40 def readfile(self, filename, *args, **kwargs): 41 """Convenience function for reading files.""" 42 name = kwargs.pop('name', 'read %s' % self.m.path.basename(filename)) 43 return self.m.file.read_text(name, filename, *args, **kwargs) 44 45 def writefile(self, filename, contents): 46 """Convenience function for writing files.""" 47 return self.m.file.write_text('write %s' % self.m.path.basename(filename), 48 filename, contents) 49 50 def rmtree(self, path): 51 """Wrapper around api.file.rmtree.""" 52 self.m.file.rmtree('rmtree %s' % self.m.path.basename(path), path) 53 54 def asset_version(self, asset_name, skia_dir, test_data=None): 55 """Return the contents of VERSION for the given asset as a string. 56 57 If test_data is not specified, reads the property 58 'test_<asset_name>_version' or if not present, uses 59 TEST_DEFAULT_ASSET_VERSION.""" 60 version_file = skia_dir.join( 61 'infra', 'bots', 'assets', asset_name, 'VERSION') 62 if not test_data: 63 test_data = self.m.properties.get( 64 'test_%s_version' % asset_name, TEST_DEFAULT_ASSET_VERSION) 65 return self.m.file.read_text('Get %s VERSION' % asset_name, 66 version_file, 67 test_data=test_data).rstrip() 68 69 def __call__(self, steptype, name, abort_on_failure=True, 70 fail_build_on_failure=True, **kwargs): 71 """Run a step. If it fails, keep going but mark the build status failed.""" 72 try: 73 with self.m.env(self.m.vars.default_env): 74 return steptype(name=name, **kwargs) 75 except self.m.step.StepFailure as e: 76 if fail_build_on_failure: 77 self._failed.append(e) 78 if abort_on_failure: 79 raise 80 81 def with_retry(self, steptype, name, attempts, between_attempts_fn=None, 82 abort_on_failure=True, fail_build_on_failure=True, **kwargs): 83 for attempt in range(attempts): 84 step_name = name 85 if attempt > 0: 86 step_name += ' (attempt %d)' % (attempt + 1) 87 try: 88 res = self(steptype, name=step_name, abort_on_failure=True, 89 fail_build_on_failure=fail_build_on_failure, **kwargs) 90 if attempt > 0 and fail_build_on_failure: 91 del self._failed[-attempt:] 92 return res 93 except self.m.step.StepFailure: 94 if attempt == attempts - 1: 95 if abort_on_failure: 96 raise 97 elif between_attempts_fn: 98 between_attempts_fn(attempt+1) 99