OLD | NEW |
| (Empty) |
1 # Copyright (c) 2013 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 """ Utilities for generic build steps. """ | |
6 | |
7 import os | |
8 import shutil | |
9 import sys | |
10 | |
11 from utils import file_utils | |
12 from py.utils import shell_utils | |
13 | |
14 | |
15 class DeviceDirs(object): | |
16 def __init__(self, perf_data_dir, gm_actual_dir, gm_expected_dir, dm_dir, | |
17 resource_dir, skimage_in_dir, skimage_expected_dir, | |
18 skimage_out_dir, skp_dir, skp_perf_dir, | |
19 playback_actual_images_dir, playback_actual_summaries_dir, | |
20 playback_expected_summaries_dir, tmp_dir): | |
21 self._perf_data_dir = perf_data_dir | |
22 self._gm_actual_dir = gm_actual_dir | |
23 self._gm_expected_dir = gm_expected_dir | |
24 self._dm_dir = dm_dir | |
25 self._resource_dir = resource_dir | |
26 self._skimage_in_dir = skimage_in_dir | |
27 self._skimage_expected_dir = skimage_expected_dir | |
28 self._skimage_out_dir = skimage_out_dir | |
29 self._skp_dir = skp_dir | |
30 self._skp_perf_dir = skp_perf_dir | |
31 self._playback_actual_images_dir = playback_actual_images_dir | |
32 self._playback_actual_summaries_dir = playback_actual_summaries_dir | |
33 self._playback_expected_summaries_dir = playback_expected_summaries_dir | |
34 self._tmp_dir = tmp_dir | |
35 | |
36 def GMActualDir(self): | |
37 """Holds images and JSON summary written out by the 'gm' tool.""" | |
38 return self._gm_actual_dir | |
39 | |
40 def GMExpectedDir(self): | |
41 """Holds expectations JSON summary read by the 'gm' tool.""" | |
42 return self._gm_expected_dir | |
43 | |
44 def DMDir(self): | |
45 """Where DM writes.""" | |
46 return self._dm_dir | |
47 | |
48 def PerfDir(self): | |
49 return self._perf_data_dir | |
50 | |
51 def PlaybackActualImagesDir(self): | |
52 """Holds image files written out by the 'render_pictures' tool.""" | |
53 return self._playback_actual_images_dir | |
54 | |
55 def PlaybackActualSummariesDir(self): | |
56 """Holds actual-result JSON summaries written by 'render_pictures' tool.""" | |
57 return self._playback_actual_summaries_dir | |
58 | |
59 def PlaybackExpectedSummariesDir(self): | |
60 """Holds expected-result JSON summaries read by 'render_pictures' tool.""" | |
61 return self._playback_expected_summaries_dir | |
62 | |
63 def ResourceDir(self): | |
64 return self._resource_dir | |
65 | |
66 def SKImageInDir(self): | |
67 return self._skimage_in_dir | |
68 | |
69 def SKImageExpectedDir(self): | |
70 return self._skimage_expected_dir | |
71 | |
72 def SKImageOutDir(self): | |
73 return self._skimage_out_dir | |
74 | |
75 def SKPDir(self): | |
76 """Holds SKP files that are consumed by RenderSKPs and BenchPictures.""" | |
77 return self._skp_dir | |
78 | |
79 def SKPPerfDir(self): | |
80 return self._skp_perf_dir | |
81 | |
82 def TmpDir(self): | |
83 return self._tmp_dir | |
84 | |
85 | |
86 class DefaultBuildStepUtils: | |
87 """ Utilities to be used by subclasses of BuildStep. | |
88 | |
89 The methods in this class define how certain high-level functions should work. | |
90 Each build step flavor should correspond to a subclass of BuildStepUtils which | |
91 may override any of these functions as appropriate for that flavor. | |
92 | |
93 For example, the AndroidBuildStepUtils will override the functions for copying | |
94 files between the host and Android device, as well as the RunFlavoredCmd | |
95 function, so that commands may be run through ADB. """ | |
96 | |
97 def __init__(self, build_step_instance): | |
98 self._step = build_step_instance | |
99 | |
100 def ListBuildStepExecutables(self): | |
101 """ Called by subclasses that may need to install the executables. """ | |
102 return ['dm', 'gm', 'render_pictures', 'render_pdfs', | |
103 'skimage', 'nanobench'] | |
104 | |
105 def _PathToBinary(self, binary): | |
106 """ Returns the path to the given built executable. """ | |
107 return os.path.join('out', self._step.configuration, binary) | |
108 | |
109 def RunFlavoredCmd(self, app, args): | |
110 """ Override this in new BuildStepUtils flavors. """ | |
111 if (sys.platform == 'linux2' and 'x86_64' in self._step.builder_name | |
112 and not 'TSAN' in self._step.builder_name): | |
113 cmd = ['catchsegv', self._PathToBinary(app)] | |
114 else: | |
115 cmd = [self._PathToBinary(app)] | |
116 shell_utils.run(cmd + args) | |
117 | |
118 def ReadFileOnDevice(self, filepath): | |
119 """ Read the contents of a file on the associated device. Subclasses should | |
120 override this method with one appropriate for reading the contents of a file | |
121 on the device side. """ | |
122 with open(filepath) as f: | |
123 return f.read() | |
124 | |
125 def CopyDirectoryContentsToDevice(self, host_dir, device_dir): | |
126 """ Copy the contents of a host-side directory to a clean directory on the | |
127 device side. Subclasses should override this method with one appropriate for | |
128 copying the contents of a host-side directory to a clean device-side | |
129 directory. | |
130 | |
131 TODO(epoger): Clarify the description a bit: this method does not expect | |
132 device_dir to be an empty directory before it is called. Implementations | |
133 of this method for other device types create an empty directory at | |
134 device_dir as the first step. | |
135 """ | |
136 # For "normal" builders who don't have an attached device, we expect | |
137 # host_dir and device_dir to be the same. | |
138 if host_dir != device_dir: | |
139 raise ValueError('For builders who do not have attached devices, copying ' | |
140 'from host to device is undefined and only allowed if ' | |
141 'host_dir and device_dir are the same.') | |
142 | |
143 def CopyDirectoryContentsToHost(self, device_dir, host_dir): | |
144 """ Copy the contents of a device-side directory to a clean directory on the | |
145 host side. Subclasses should override this method with one appropriate for | |
146 copying the contents of a device-side directory to a clean host-side | |
147 directory.""" | |
148 # For "normal" builders who don't have an attached device, we expect | |
149 # host_dir and device_dir to be the same. | |
150 if host_dir != device_dir: | |
151 raise ValueError('For builders who do not have attached devices, copying ' | |
152 'from host to device is undefined and only allowed if ' | |
153 'host_dir and device_dir are the same.') | |
154 | |
155 def PushFileToDevice(self, src, dst): | |
156 """ Copy the a single file from path "src" on the host to path "dst" on | |
157 the device. If the host IS the device we are testing, it's just a filecopy. | |
158 Subclasses should override this method with one appropriate for | |
159 pushing the file to the device. """ | |
160 shutil.copy(src, dst) | |
161 | |
162 def DeviceListDir(self, directory): | |
163 """ List the contents of a directory on the connected device. """ | |
164 return os.listdir(directory) | |
165 | |
166 def DevicePathExists(self, path): | |
167 """ Like os.path.exists(), but for a path on the connected device. """ | |
168 return os.path.exists(path) | |
169 | |
170 def DevicePathJoin(self, *args): | |
171 """ Like os.path.join(), but for paths that will target the connected | |
172 device. """ | |
173 return os.sep.join(args) | |
174 | |
175 def CreateCleanDeviceDirectory(self, directory): | |
176 """ Creates an empty directory on an attached device. Subclasses with | |
177 attached devices should override. """ | |
178 file_utils.create_clean_local_dir(directory) | |
179 | |
180 def CreateCleanHostDirectory(self, directory): | |
181 """ Creates an empty directory on the host. Can be overridden by subclasses, | |
182 but that should not be necessary. """ | |
183 file_utils.create_clean_local_dir(directory) | |
184 | |
185 def Install(self): | |
186 """ Install the Skia executables. """ | |
187 pass | |
188 | |
189 def RunGYP(self): | |
190 self.Compile('gyp') | |
191 | |
192 def Compile(self, target): | |
193 """ Compile the Skia executables. """ | |
194 # TODO(borenet): It would be nice to increase code sharing here. | |
195 if 'Win8' in self._step.builder_name: | |
196 os.environ['GYP_MSVS_VERSION'] = '2012' | |
197 print 'GYP_MSVS_VERSION="%s"' % os.environ['GYP_MSVS_VERSION'] | |
198 | |
199 os.environ['CHROME_PATH'] = os.path.join(os.path.expanduser('~'), 'src') | |
200 print 'CHROME_PATH="%s"' % os.environ['CHROME_PATH'] | |
201 | |
202 os.environ['GYP_DEFINES'] = self._step.args['gyp_defines'] | |
203 print 'GYP_DEFINES="%s"' % os.environ['GYP_DEFINES'] | |
204 make_cmd = 'make' | |
205 if os.name == 'nt': | |
206 make_cmd = 'make.bat' | |
207 cmd = [make_cmd, | |
208 target, | |
209 'BUILDTYPE=%s' % self._step.configuration, | |
210 ] | |
211 cmd.extend(self._step.default_make_flags) | |
212 cmd.extend(self._step.make_flags) | |
213 | |
214 # TODO(epoger): Maybe remove this once we fix the underlying problem in | |
215 # https://code.google.com/p/skia/issues/detail?id=2393 ('recurring RunGYP | |
216 # failures on multiple Test-Win7-ShuttleA-HD2000-* bots') | |
217 print 'about to run cmd %s' % cmd | |
218 cwd = os.getcwd() | |
219 print 'cwd is %s' % cwd | |
220 print 'contents of cwd are %s' % os.listdir(cwd) | |
221 | |
222 shell_utils.run(cmd) | |
223 | |
224 def MakeClean(self): | |
225 make_cmd = 'make' | |
226 if os.name == 'nt': | |
227 make_cmd = 'make.bat' | |
228 shell_utils.run([make_cmd, 'clean']) | |
229 | |
230 def PreRun(self): | |
231 """ Preprocessing step to run before the BuildStep itself. """ | |
232 pass | |
233 | |
234 def GetDeviceDirs(self): | |
235 """ Set the directories which will be used by the BuildStep. | |
236 | |
237 In the case of DefaultBuildStepUtils, host_dirs and device_dirs are the | |
238 same, which is why CopyDirectoryContentsToDevice() is a no-op. | |
239 """ | |
240 return DeviceDirs( | |
241 perf_data_dir=self._step.perf_data_dir, | |
242 # TODO(epoger): Instead, set gm_actual_dir to self._step._gm_actual_dir | |
243 # and remove os.path.join() with self._builder_name in postrender.py ? | |
244 # (CopyDirectoryContentsToHost fails if the paths are different when | |
245 # host==device, so why not just make them inherently equal?) | |
246 gm_actual_dir=os.path.join(os.pardir, os.pardir, 'gm', 'actual'), | |
247 gm_expected_dir=os.path.join(os.pardir, os.pardir, 'gm', 'expected'), | |
248 dm_dir=os.path.join(os.pardir, os.pardir, 'dm'), | |
249 resource_dir=self._step.resource_dir, | |
250 skimage_in_dir=self._step.skimage_in_dir, | |
251 skimage_expected_dir=os.path.join(os.pardir, os.pardir, 'skimage', | |
252 'expected'), | |
253 skimage_out_dir=self._step.skimage_out_dir, | |
254 skp_dir=self._step.skp_dir, | |
255 skp_perf_dir=self._step.perf_data_dir, | |
256 playback_actual_images_dir=self._step.playback_actual_images_dir, | |
257 playback_actual_summaries_dir=self._step.playback_actual_summaries_dir, | |
258 playback_expected_summaries_dir=( | |
259 self._step.playback_expected_summaries_dir), | |
260 tmp_dir=os.path.join(os.pardir, 'tmp')) | |
OLD | NEW |