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