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
11from . import android
12from . import chromebook
13from . import default
14from . import docker
15from . import ios
16from . import valgrind
17from . import win_ssh
18
19
20"""Abstractions for running code on various platforms.
21
22The methods in this module define how certain high-level functions should work.
23Each flavor should correspond to a subclass of DefaultFlavor which may override
24any of these functions as appropriate for that flavor.
25
26For example, the AndroidFlavor will override the functions for copying files
27between the host and Android device, as well as the 'step' function, so that
28commands may be run through ADB.
29"""
30
31
32VERSION_FILE_LOTTIE = 'LOTTIE_VERSION'
33VERSION_FILE_SK_IMAGE = 'SK_IMAGE_VERSION'
34VERSION_FILE_SKP = 'SKP_VERSION'
35VERSION_FILE_SVG = 'SVG_VERSION'
36VERSION_FILE_MSKP = 'MSKP_VERSION'
37VERSION_FILE_TEXTTRACES = 'TEXTTRACES_VERSION'
38
39VERSION_NONE = -1
40
41def is_android(vars_api):
42  return ('Android' in vars_api.extra_tokens or
43          'Android' in vars_api.builder_cfg.get('os', ''))
44
45def is_chromebook(vars_api):
46  return ('Chromebook' in vars_api.extra_tokens or
47          'ChromeOS' in vars_api.builder_cfg.get('os', ''))
48
49def is_docker(vars_api):
50  return 'Docker' in vars_api.extra_tokens
51
52def is_ios(vars_api):
53  return ('iOS' in vars_api.extra_tokens or
54          'iOS' == vars_api.builder_cfg.get('os', ''))
55
56def is_test_skqp(vars_api):
57  return ('SKQP' in vars_api.extra_tokens and
58          vars_api.builder_name.startswith('Test'))
59
60def is_valgrind(vars_api):
61  return 'Valgrind' in vars_api.extra_tokens
62
63def is_win_ssh(vars_api):
64  return 'LenovoYogaC630' in vars_api.builder_cfg.get('model', '')
65
66
67class SkiaFlavorApi(recipe_api.RecipeApi):
68  def get_flavor(self, vars_api, app_name):
69    """Return a flavor utils object specific to the given builder."""
70    if is_chromebook(vars_api):
71      return chromebook.ChromebookFlavor(self, app_name)
72    if is_android(vars_api) and not is_test_skqp(vars_api):
73      return android.AndroidFlavor(self, app_name)
74    elif is_docker(vars_api):
75      return docker.DockerFlavor(self, app_name)
76    elif is_ios(vars_api):
77      return ios.iOSFlavor(self, app_name)
78    elif is_valgrind(vars_api):
79      return valgrind.ValgrindFlavor(self, app_name)
80    elif is_win_ssh(vars_api):
81      return win_ssh.WinSSHFlavor(self, app_name)
82    else:
83      return default.DefaultFlavor(self, app_name)
84
85  def setup(self, app_name):
86    self._f = self.get_flavor(self.m.vars, app_name)
87    self.device_dirs = self._f.device_dirs
88    self.host_dirs = self._f.host_dirs
89    self._skia_dir = self.m.path['start_dir'].join('skia')
90
91  def step(self, name, cmd, **kwargs):
92    return self._f.step(name, cmd, **kwargs)
93
94  def device_path_join(self, *args):
95    return self._f.device_path_join(*args)
96
97  def copy_directory_contents_to_device(self, host_dir, device_dir):
98    return self._f.copy_directory_contents_to_device(host_dir, device_dir)
99
100  def copy_directory_contents_to_host(self, device_dir, host_dir):
101    return self._f.copy_directory_contents_to_host(device_dir, host_dir)
102
103  def copy_file_to_device(self, host_path, device_path):
104    return self._f.copy_file_to_device(host_path, device_path)
105
106  def create_clean_host_dir(self, path):
107    return self._f.create_clean_host_dir(path)
108
109  def create_clean_device_dir(self, path):
110    return self._f.create_clean_device_dir(path)
111
112  def read_file_on_device(self, path, **kwargs):
113    return self._f.read_file_on_device(path, **kwargs)
114
115  def remove_file_on_device(self, path):
116    return self._f.remove_file_on_device(path)
117
118  def install(self, skps=False, images=False, lotties=False, svgs=False,
119              resources=False, mskps=False, texttraces=False):
120    self._f.install()
121
122    if texttraces:
123      self._copy_texttraces()
124    # TODO(borenet): Only copy files which have changed.
125    if resources:
126      self.copy_directory_contents_to_device(
127          self.m.path['start_dir'].join('skia', 'resources'),
128          self.device_dirs.resource_dir)
129
130    if skps:
131      self._copy_skps()
132    if images:
133      self._copy_images()
134    if lotties:
135      self._copy_lotties()
136    if svgs:
137      self._copy_svgs()
138    if mskps:
139      self._copy_mskps()
140
141  def cleanup_steps(self):
142    return self._f.cleanup_steps()
143
144  def _copy_dir(self, host_version, version_file, tmp_dir,
145                host_path, device_path):
146    actual_version_file = self.m.path.join(tmp_dir, version_file)
147    # Copy to device.
148    device_version_file = self.device_path_join(
149        self.device_dirs.tmp_dir, version_file)
150    if str(actual_version_file) != str(device_version_file):
151      device_version = self.read_file_on_device(device_version_file,
152                                                abort_on_failure=False,
153                                                fail_build_on_failure=False)
154      if not device_version:
155        device_version = VERSION_NONE
156      if device_version != host_version:
157        self.remove_file_on_device(device_version_file)
158        self.create_clean_device_dir(device_path)
159        self.copy_directory_contents_to_device(
160            host_path, device_path)
161
162        # Copy the new version file.
163        self.copy_file_to_device(actual_version_file, device_version_file)
164
165  def _copy_images(self):
166    """Copy test images if needed."""
167    version = self.m.run.asset_version('skimage', self._skia_dir)
168    self.m.run.writefile(
169        self.m.path.join(self.m.vars.tmp_dir, VERSION_FILE_SK_IMAGE),
170        version)
171    self._copy_dir(
172        version,
173        VERSION_FILE_SK_IMAGE,
174        self.m.vars.tmp_dir,
175        self.host_dirs.images_dir,
176        self.device_dirs.images_dir)
177    return version
178
179  def _copy_lotties(self):
180    """Copy test lotties if needed."""
181    version = self.m.run.asset_version('lottie-samples', self._skia_dir)
182    self.m.run.writefile(
183        self.m.path.join(self.m.vars.tmp_dir, VERSION_FILE_LOTTIE),
184        version)
185    self._copy_dir(
186        version,
187        VERSION_FILE_LOTTIE,
188        self.m.vars.tmp_dir,
189        self.host_dirs.lotties_dir,
190        self.device_dirs.lotties_dir)
191    return version
192
193  def _copy_skps(self):
194    """Copy the SKPs if needed."""
195    version = self.m.run.asset_version('skp', self._skia_dir)
196    self.m.run.writefile(
197        self.m.path.join(self.m.vars.tmp_dir, VERSION_FILE_SKP),
198        version)
199    self._copy_dir(
200        version,
201        VERSION_FILE_SKP,
202        self.m.vars.tmp_dir,
203        self.host_dirs.skp_dir,
204        self.device_dirs.skp_dir)
205    return version
206
207  def _copy_svgs(self):
208    """Copy the SVGs if needed."""
209    version = self.m.run.asset_version('svg', self._skia_dir)
210    self.m.run.writefile(
211        self.m.path.join(self.m.vars.tmp_dir, VERSION_FILE_SVG),
212        version)
213    self._copy_dir(
214        version,
215        VERSION_FILE_SVG,
216        self.m.vars.tmp_dir,
217        self.host_dirs.svg_dir,
218        self.device_dirs.svg_dir)
219    return version
220
221  def _copy_mskps(self):
222    """Copy the MSKPs if needed."""
223    version = self.m.run.asset_version('mskp', self._skia_dir)
224    self.m.run.writefile(
225        self.m.path.join(self.m.vars.tmp_dir, VERSION_FILE_MSKP),
226        version)
227    self._copy_dir(
228        version,
229        VERSION_FILE_MSKP,
230        self.m.vars.tmp_dir,
231        self.host_dirs.mskp_dir,
232        self.device_dirs.mskp_dir)
233    return version
234
235  def _copy_texttraces(self):
236    """Copy the text traces if needed."""
237    version = self.m.run.asset_version('text_blob_traces', self._skia_dir)
238    self.m.run.writefile(
239        self.m.path.join(self.m.vars.tmp_dir, VERSION_FILE_TEXTTRACES),
240        version)
241    self._copy_dir(
242        version,
243        VERSION_FILE_TEXTTRACES,
244        self.m.vars.tmp_dir,
245        self.host_dirs.texttraces_dir,
246        self.device_dirs.texttraces_dir)
247    return version
248