1#!/usr/bin/env python
2#
3# Copyright 2016 Google Inc.
4#
5# Use of this source code is governed by a BSD-style license that can be
6# found in the LICENSE file.
7
8
9"""Default flavor utils class, used for desktop bots."""
10
11
12import os
13import shutil
14import sys
15
16
17class DeviceDirs(object):
18  def __init__(self,
19               dm_dir,
20               perf_data_dir,
21               resource_dir,
22               images_dir,
23               skp_dir,
24               tmp_dir):
25    self._dm_dir = dm_dir
26    self._perf_data_dir = perf_data_dir
27    self._resource_dir = resource_dir
28    self._images_dir = images_dir
29    self._skp_dir = skp_dir
30    self._tmp_dir = tmp_dir
31
32  @property
33  def dm_dir(self):
34    """Where DM writes."""
35    return self._dm_dir
36
37  @property
38  def perf_data_dir(self):
39    return self._perf_data_dir
40
41  @property
42  def resource_dir(self):
43    return self._resource_dir
44
45  @property
46  def images_dir(self):
47    return self._images_dir
48
49  @property
50  def skp_dir(self):
51    return self._skp_dir
52
53  @property
54  def tmp_dir(self):
55    return self._tmp_dir
56
57
58class DefaultFlavorUtils(object):
59  """Utilities to be used by build steps.
60
61  The methods in this class define how certain high-level functions should
62  work. Each build step flavor should correspond to a subclass of
63  DefaultFlavorUtils which may override any of these functions as appropriate
64  for that flavor.
65
66  For example, the AndroidFlavorUtils will override the functions for
67  copying files between the host and Android device, as well as the
68  'step' function, so that commands may be run through ADB.
69  """
70  def __init__(self, bot_info, *args, **kwargs):
71    self._bot_info = bot_info
72    self.chrome_path = os.path.join(os.path.expanduser('~'), 'src')
73
74  def step(self, cmd, **kwargs):
75    """Runs a step as appropriate for this flavor."""
76    path_to_app = self._bot_info.out_dir.join(
77        self._bot_info.configuration, cmd[0])
78    if (sys.platform == 'linux' and
79        'x86_64' in self._bot_info.bot_name and
80        not 'TSAN' in self._bot_info.bot_name):
81      new_cmd = ['catchsegv', path_to_app]
82    else:
83      new_cmd = [path_to_app]
84    new_cmd.extend(cmd[1:])
85    return self._bot_info.run(new_cmd, **kwargs)
86
87
88  def compile(self, target):
89    """Build the given target."""
90    # The CHROME_PATH environment variable is needed for bots that use
91    # toolchains downloaded by Chrome.
92    env = {'CHROME_PATH': self.chrome_path}
93    if sys.platform == 'win32':
94      make_cmd = ['python', 'make.py']
95    else:
96      make_cmd = ['make']
97    cmd = make_cmd + [target]
98    self._bot_info.run(cmd, env=env)
99
100  def device_path_join(self, *args):
101    """Like os.path.join(), but for paths on a connected device."""
102    return os.path.join(*args)
103
104  def device_path_exists(self, path):
105    """Like os.path.exists(), but for paths on a connected device."""
106    return os.path.exists(path, infra_step=True)  # pragma: no cover
107
108  def copy_directory_contents_to_device(self, host_dir, device_dir):
109    """Like shutil.copytree(), but for copying to a connected device."""
110    # For "normal" bots who don't have an attached device, we expect
111    # host_dir and device_dir to be the same.
112    if str(host_dir) != str(device_dir):
113      raise ValueError('For bots who do not have attached devices, copying '
114                       'from host to device is undefined and only allowed if '
115                       'host_path and device_path are the same (%s vs %s).' % (
116                       str(host_dir), str(device_dir)))  # pragma: no cover
117
118  def copy_directory_contents_to_host(self, device_dir, host_dir):
119    """Like shutil.copytree(), but for copying from a connected device."""
120    # For "normal" bots who don't have an attached device, we expect
121    # host_dir and device_dir to be the same.
122    if str(host_dir) != str(device_dir):
123      raise ValueError('For bots who do not have attached devices, copying '
124                       'from device to host is undefined and only allowed if '
125                       'host_path and device_path are the same (%s vs %s).' % (
126                       str(host_dir), str(device_dir)))  # pragma: no cover
127
128  def copy_file_to_device(self, host_path, device_path):
129    """Like shutil.copyfile, but for copying to a connected device."""
130    # For "normal" bots who don't have an attached device, we expect
131    # host_dir and device_dir to be the same.
132    if str(host_path) != str(device_path):  # pragma: no cover
133      raise ValueError('For bots who do not have attached devices, copying '
134                       'from host to device is undefined and only allowed if '
135                       'host_path and device_path are the same (%s vs %s).' % (
136                       str(host_path), str(device_path)))
137
138  def create_clean_device_dir(self, path):
139    """Like shutil.rmtree() + os.makedirs(), but on a connected device."""
140    self.create_clean_host_dir(path)
141
142  def create_clean_host_dir(self, path):
143    """Convenience function for creating a clean directory."""
144    shutil.rmtree(path)
145    os.makedirs(path)
146
147  def install(self):
148    """Run device-specific installation steps."""
149    pass
150
151  def cleanup_steps(self):
152    """Run any device-specific cleanup steps."""
153    pass
154
155  def get_device_dirs(self):
156    """ Set the directories which will be used by the build steps.
157
158    These refer to paths on the same device where the test executables will
159    run, for example, for Android bots these are paths on the Android device
160    itself. For desktop bots, these are just local paths.
161    """
162    join = lambda p: os.path.join(self._bot_info.build_dir, p)
163    return DeviceDirs(
164        dm_dir=join('dm'),
165        perf_data_dir=self._bot_info.perf_data_dir,
166        resource_dir=self._bot_info.resource_dir,
167        images_dir=join('images'),
168        skp_dir=self._bot_info.local_skp_dir,
169        tmp_dir=join('tmp'))
170
171  def __repr__(self):
172    return '<%s object>' % self.__class__.__name__  # pragma: no cover
173