blob: 2f83538e5352f583141241d9ee6b5d28eda2dcac [file] [log] [blame]
Chris Masone859fdec2012-01-30 08:38:09 -08001# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Chris Masone6fed6462011-10-20 16:36:43 -07002# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import common
Chris Masonefef21382012-01-17 11:16:32 -08006import compiler, logging, os, random, re, time, urllib2
Chris Masone6fed6462011-10-20 16:36:43 -07007from autotest_lib.client.common_lib import control_data, error, utils
Chris Masonefef21382012-01-17 11:16:32 -08008from autotest_lib.client.common_lib.cros import dev_server
9
10
Chris Masonef8b53062012-05-08 22:14:18 -070011# Relevant CrosDynamicSuiteExceptions are defined in client/common_lib/error.py.
Chris Masone6fed6462011-10-20 16:36:43 -070012
13
14class ControlFileGetter(object):
15 """
16 Interface for classes that can list and fetch known control files.
Chris Masone6fed6462011-10-20 16:36:43 -070017 """
18
Chris Masone6fed6462011-10-20 16:36:43 -070019 def __init__(self):
20 pass
21
22
23 def get_control_file_list(self):
24 """
Chris Masonefef21382012-01-17 11:16:32 -080025 Gather a list of paths to control files.
Chris Masone6fed6462011-10-20 16:36:43 -070026
Chris Masonefef21382012-01-17 11:16:32 -080027 @return A list of file paths.
28 @throws NoControlFileList if there is an error while listing.
Chris Masone6fed6462011-10-20 16:36:43 -070029 """
30 pass
31
32
33 def get_control_file_contents(self, test_path):
34 """
35 Given a path to a control file, return its contents.
36
Chris Masonefef21382012-01-17 11:16:32 -080037 @param test_path: the path to the control file.
Chris Masone6fed6462011-10-20 16:36:43 -070038 @return the contents of the control file specified by the path.
Chris Masonefef21382012-01-17 11:16:32 -080039 @throws ControlFileNotFound if the file cannot be retrieved.
Chris Masone6fed6462011-10-20 16:36:43 -070040 """
41 pass
42
43
44 def get_control_file_contents_by_name(self, test_name):
45 """
46 Given the name of a control file, return its contents.
47
Chris Masonefef21382012-01-17 11:16:32 -080048 @param test_name: the name of the test whose control file is desired.
49 @return the contents of the control file specified by the name.
50 @throws ControlFileNotFound if the file cannot be retrieved.
Chris Masone6fed6462011-10-20 16:36:43 -070051 """
52 pass
53
54
Chris Masonefef21382012-01-17 11:16:32 -080055class CacheingControlFileGetter(ControlFileGetter):
56 """Wraps ControlFileGetter to cache the retrieved control file list."""
57 def __init__(self):
58 super(CacheingControlFileGetter, self).__init__()
59 self._files = []
60
61
62 def get_control_file_list(self):
63 """
64 Gather a list of paths to control files.
65
66 Gets a list of control files; populates |self._files| with that list
67 and then returns the paths to all useful files in the list.
68
69 @return A list of file paths.
70 @throws NoControlFileList if there is an error while listing.
71 """
72 self._files = self._get_control_file_list()
73 return self._files
74
75
76 def get_control_file_contents_by_name(self, test_name):
77 """
78 Given the name of a control file, return its contents.
79
80 Searches through previously-compiled list in |self._files| for a
81 test named |test_name| and returns the contents of the control file
82 for that test if it is found.
83
84 @param test_name: the name of the test whose control file is desired.
85 @return the contents of the control file specified by the name.
86 @throws ControlFileNotFound if the file cannot be retrieved.
87 """
88 if not self._files and not self.get_control_file_list():
Chris Masonef8b53062012-05-08 22:14:18 -070089 raise error.ControlFileNotFound('No control files found.')
Chris Masone859fdec2012-01-30 08:38:09 -080090
91 if 'control' not in test_name:
92 regexp = re.compile(os.path.join(test_name, 'control'))
93 else:
94 regexp = re.compile(test_name)
Chris Masonefef21382012-01-17 11:16:32 -080095 candidates = filter(regexp.search, self._files)
96 if not candidates:
Chris Masonef8b53062012-05-08 22:14:18 -070097 raise error.ControlFileNotFound('No control file for ' + test_name)
Chris Masonefef21382012-01-17 11:16:32 -080098 if len(candidates) > 1:
Chris Masonef8b53062012-05-08 22:14:18 -070099 raise error.ControlFileNotFound(test_name + ' is not unique.')
Chris Masonefef21382012-01-17 11:16:32 -0800100 return self.get_control_file_contents(candidates[0])
101
102
103class FileSystemGetter(CacheingControlFileGetter):
104 """
105 Class that can list and fetch known control files from disk.
106
107 @var _CONTROL_PATTERN: control file name format to match.
108 """
109
110 _CONTROL_PATTERN = '^control(?:\..+)?$'
111
112 def __init__(self, paths):
113 """
114 @param paths: base directories to start search.
115 """
116 super(FileSystemGetter, self).__init__()
117 self._paths = paths
118
119
Chris Masone6fed6462011-10-20 16:36:43 -0700120 def _is_useful_file(self, name):
121 return '__init__.py' not in name and '.svn' not in name
122
123
Chris Masonefef21382012-01-17 11:16:32 -0800124 def _get_control_file_list(self):
Chris Masone6fed6462011-10-20 16:36:43 -0700125 """
Chris Masonefef21382012-01-17 11:16:32 -0800126 Gather a list of paths to control files under |self._paths|.
Chris Masone6fed6462011-10-20 16:36:43 -0700127
Chris Masonefef21382012-01-17 11:16:32 -0800128 Searches under |self._paths| for files that match
129 |self._CONTROL_PATTERN|. Populates |self._files| with that list
130 and then returns the paths to all useful files in the list.
Chris Masone6fed6462011-10-20 16:36:43 -0700131
Chris Masonefef21382012-01-17 11:16:32 -0800132 @return A list of files that match |self._CONTROL_PATTERN|.
133 @throws NoControlFileList if we find no files.
Chris Masone6fed6462011-10-20 16:36:43 -0700134 """
135 regexp = re.compile(self._CONTROL_PATTERN)
136 directories = self._paths
137 while len(directories) > 0:
138 directory = directories.pop()
139 if not os.path.exists(directory):
140 continue
141 for name in os.listdir(directory):
142 fullpath = os.path.join(directory, name)
143 if os.path.isfile(fullpath):
144 if regexp.search(name):
145 # if we are a control file
146 self._files.append(fullpath)
147 elif os.path.isdir(fullpath):
148 directories.append(fullpath)
Chris Masonefef21382012-01-17 11:16:32 -0800149 if not self._files:
150 msg = 'No control files under ' + ','.join(self._paths)
Chris Masonef8b53062012-05-08 22:14:18 -0700151 raise error.NoControlFileList(msg)
Chris Masone6fed6462011-10-20 16:36:43 -0700152 return [f for f in self._files if self._is_useful_file(f)]
153
154
155 def get_control_file_contents(self, test_path):
Chris Masonefef21382012-01-17 11:16:32 -0800156 """
157 Get the contents of the control file at |test_path|.
158
159 @return The contents of the aforementioned file.
160 @throws ControlFileNotFound if the file cannot be retrieved.
161 """
162 try:
163 return utils.read_file(test_path)
164 except EnvironmentError as (errno, strerror):
165 msg = "Can't retrieve {0}: {1} ({2})".format(test_path,
166 strerror,
167 errno)
Chris Masonef8b53062012-05-08 22:14:18 -0700168 raise error.ControlFileNotFound(msg)
Chris Masone6fed6462011-10-20 16:36:43 -0700169
170
Chris Masonefef21382012-01-17 11:16:32 -0800171class DevServerGetter(CacheingControlFileGetter):
172 def __init__(self, build, ds=None):
173 """
174 @param build: The build from which to get control files.
175 @param ds: An existing dev_server.DevServer object to use.
176 """
177 super(DevServerGetter, self).__init__()
178 self._dev_server = ds if ds else dev_server.DevServer()
179 self._build = build
180
181
Chris Masone859fdec2012-01-30 08:38:09 -0800182 @staticmethod
183 def create(build, ds=None):
184 """Wraps constructor. Can be mocked for testing purposes."""
185 return DevServerGetter(build, ds)
186
187
Chris Masonefef21382012-01-17 11:16:32 -0800188 def _get_control_file_list(self):
189 """
190 Gather a list of paths to control files from |self._dev_server|.
191
192 Get a listing of all the control files for |self._build| on
193 |self._dev_server|. Populates |self._files| with that list
194 and then returns paths (under the autotest dir) to them.
195
196 @return A list of control file paths. None on failure.
197 @throws NoControlFileList if there is an error while listing.
198 """
199 try:
200 return self._dev_server.list_control_files(self._build)
201 except urllib2.HTTPError as e:
Chris Masonef8b53062012-05-08 22:14:18 -0700202 raise error.NoControlFileList(e)
Chris Masonefef21382012-01-17 11:16:32 -0800203
204
205 def get_control_file_contents(self, test_path):
206 """
207 Return the contents of |test_path| from |self._dev_server|.
208
209 Get the contents of the control file at |test_path| for |self._build| on
210 |self._dev_server|.
211
212 @return The contents of |test_path|. None on failure.
213 @throws ControlFileNotFound if the file cannot be retrieved.
214 """
215 try:
216 return self._dev_server.get_control_file(self._build, test_path)
217 except urllib2.HTTPError as e:
Chris Masonef8b53062012-05-08 22:14:18 -0700218 raise error.ControlFileNotFound(e)