blob: 796e566d8fcde6af1f9c954c3b1e694a703a0a1a [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
11class ControlFileNotFound(Exception):
12 """Raised when a control file cannot be found and/or read."""
13 pass
14
15
16class NoControlFileList(Exception):
17 """Raised when to indicate that a listing can't be done."""
18 pass
Chris Masone6fed6462011-10-20 16:36:43 -070019
20
21class ControlFileGetter(object):
22 """
23 Interface for classes that can list and fetch known control files.
Chris Masone6fed6462011-10-20 16:36:43 -070024 """
25
Chris Masone6fed6462011-10-20 16:36:43 -070026 def __init__(self):
27 pass
28
29
30 def get_control_file_list(self):
31 """
Chris Masonefef21382012-01-17 11:16:32 -080032 Gather a list of paths to control files.
Chris Masone6fed6462011-10-20 16:36:43 -070033
Chris Masonefef21382012-01-17 11:16:32 -080034 @return A list of file paths.
35 @throws NoControlFileList if there is an error while listing.
Chris Masone6fed6462011-10-20 16:36:43 -070036 """
37 pass
38
39
40 def get_control_file_contents(self, test_path):
41 """
42 Given a path to a control file, return its contents.
43
Chris Masonefef21382012-01-17 11:16:32 -080044 @param test_path: the path to the control file.
Chris Masone6fed6462011-10-20 16:36:43 -070045 @return the contents of the control file specified by the path.
Chris Masonefef21382012-01-17 11:16:32 -080046 @throws ControlFileNotFound if the file cannot be retrieved.
Chris Masone6fed6462011-10-20 16:36:43 -070047 """
48 pass
49
50
51 def get_control_file_contents_by_name(self, test_name):
52 """
53 Given the name of a control file, return its contents.
54
Chris Masonefef21382012-01-17 11:16:32 -080055 @param test_name: the name of the test whose control file is desired.
56 @return the contents of the control file specified by the name.
57 @throws ControlFileNotFound if the file cannot be retrieved.
Chris Masone6fed6462011-10-20 16:36:43 -070058 """
59 pass
60
61
Chris Masonefef21382012-01-17 11:16:32 -080062class CacheingControlFileGetter(ControlFileGetter):
63 """Wraps ControlFileGetter to cache the retrieved control file list."""
64 def __init__(self):
65 super(CacheingControlFileGetter, self).__init__()
66 self._files = []
67
68
69 def get_control_file_list(self):
70 """
71 Gather a list of paths to control files.
72
73 Gets a list of control files; populates |self._files| with that list
74 and then returns the paths to all useful files in the list.
75
76 @return A list of file paths.
77 @throws NoControlFileList if there is an error while listing.
78 """
79 self._files = self._get_control_file_list()
80 return self._files
81
82
83 def get_control_file_contents_by_name(self, test_name):
84 """
85 Given the name of a control file, return its contents.
86
87 Searches through previously-compiled list in |self._files| for a
88 test named |test_name| and returns the contents of the control file
89 for that test if it is found.
90
91 @param test_name: the name of the test whose control file is desired.
92 @return the contents of the control file specified by the name.
93 @throws ControlFileNotFound if the file cannot be retrieved.
94 """
95 if not self._files and not self.get_control_file_list():
96 raise ControlFileNotFound('No control files found.')
Chris Masone859fdec2012-01-30 08:38:09 -080097
98 if 'control' not in test_name:
99 regexp = re.compile(os.path.join(test_name, 'control'))
100 else:
101 regexp = re.compile(test_name)
Chris Masonefef21382012-01-17 11:16:32 -0800102 candidates = filter(regexp.search, self._files)
103 if not candidates:
104 raise ControlFileNotFound('No control file for ' + test_name)
105 if len(candidates) > 1:
106 raise ControlFileNotFound(test_name + ' is not unique.')
107 return self.get_control_file_contents(candidates[0])
108
109
110class FileSystemGetter(CacheingControlFileGetter):
111 """
112 Class that can list and fetch known control files from disk.
113
114 @var _CONTROL_PATTERN: control file name format to match.
115 """
116
117 _CONTROL_PATTERN = '^control(?:\..+)?$'
118
119 def __init__(self, paths):
120 """
121 @param paths: base directories to start search.
122 """
123 super(FileSystemGetter, self).__init__()
124 self._paths = paths
125
126
Chris Masone6fed6462011-10-20 16:36:43 -0700127 def _is_useful_file(self, name):
128 return '__init__.py' not in name and '.svn' not in name
129
130
Chris Masonefef21382012-01-17 11:16:32 -0800131 def _get_control_file_list(self):
Chris Masone6fed6462011-10-20 16:36:43 -0700132 """
Chris Masonefef21382012-01-17 11:16:32 -0800133 Gather a list of paths to control files under |self._paths|.
Chris Masone6fed6462011-10-20 16:36:43 -0700134
Chris Masonefef21382012-01-17 11:16:32 -0800135 Searches under |self._paths| for files that match
136 |self._CONTROL_PATTERN|. Populates |self._files| with that list
137 and then returns the paths to all useful files in the list.
Chris Masone6fed6462011-10-20 16:36:43 -0700138
Chris Masonefef21382012-01-17 11:16:32 -0800139 @return A list of files that match |self._CONTROL_PATTERN|.
140 @throws NoControlFileList if we find no files.
Chris Masone6fed6462011-10-20 16:36:43 -0700141 """
142 regexp = re.compile(self._CONTROL_PATTERN)
143 directories = self._paths
144 while len(directories) > 0:
145 directory = directories.pop()
146 if not os.path.exists(directory):
147 continue
148 for name in os.listdir(directory):
149 fullpath = os.path.join(directory, name)
150 if os.path.isfile(fullpath):
151 if regexp.search(name):
152 # if we are a control file
153 self._files.append(fullpath)
154 elif os.path.isdir(fullpath):
155 directories.append(fullpath)
Chris Masonefef21382012-01-17 11:16:32 -0800156 if not self._files:
157 msg = 'No control files under ' + ','.join(self._paths)
158 raise NoControlFileList(msg)
Chris Masone6fed6462011-10-20 16:36:43 -0700159 return [f for f in self._files if self._is_useful_file(f)]
160
161
162 def get_control_file_contents(self, test_path):
Chris Masonefef21382012-01-17 11:16:32 -0800163 """
164 Get the contents of the control file at |test_path|.
165
166 @return The contents of the aforementioned file.
167 @throws ControlFileNotFound if the file cannot be retrieved.
168 """
169 try:
170 return utils.read_file(test_path)
171 except EnvironmentError as (errno, strerror):
172 msg = "Can't retrieve {0}: {1} ({2})".format(test_path,
173 strerror,
174 errno)
175 raise ControlFileNotFound(msg)
Chris Masone6fed6462011-10-20 16:36:43 -0700176
177
Chris Masonefef21382012-01-17 11:16:32 -0800178class DevServerGetter(CacheingControlFileGetter):
179 def __init__(self, build, ds=None):
180 """
181 @param build: The build from which to get control files.
182 @param ds: An existing dev_server.DevServer object to use.
183 """
184 super(DevServerGetter, self).__init__()
185 self._dev_server = ds if ds else dev_server.DevServer()
186 self._build = build
187
188
Chris Masone859fdec2012-01-30 08:38:09 -0800189 @staticmethod
190 def create(build, ds=None):
191 """Wraps constructor. Can be mocked for testing purposes."""
192 return DevServerGetter(build, ds)
193
194
Chris Masonefef21382012-01-17 11:16:32 -0800195 def _get_control_file_list(self):
196 """
197 Gather a list of paths to control files from |self._dev_server|.
198
199 Get a listing of all the control files for |self._build| on
200 |self._dev_server|. Populates |self._files| with that list
201 and then returns paths (under the autotest dir) to them.
202
203 @return A list of control file paths. None on failure.
204 @throws NoControlFileList if there is an error while listing.
205 """
206 try:
207 return self._dev_server.list_control_files(self._build)
208 except urllib2.HTTPError as e:
209 raise NoControlFileList(e)
210
211
212 def get_control_file_contents(self, test_path):
213 """
214 Return the contents of |test_path| from |self._dev_server|.
215
216 Get the contents of the control file at |test_path| for |self._build| on
217 |self._dev_server|.
218
219 @return The contents of |test_path|. None on failure.
220 @throws ControlFileNotFound if the file cannot be retrieved.
221 """
222 try:
223 return self._dev_server.get_control_file(self._build, test_path)
224 except urllib2.HTTPError as e:
225 raise ControlFileNotFound(e)