| OLD | NEW |
| 1 # Copyright 2014 The Chromium Authors. All rights reserved. | 1 # Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 """Implementation of package repository service. | 5 """Implementation of package repository service. |
| 6 | 6 |
| 7 Package and PackageInstance | 7 Package and PackageInstance |
| 8 --------------------------- | 8 --------------------------- |
| 9 | 9 |
| 10 Definitions: | 10 Definitions: |
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 172 """Returns Package entity if it exists. | 172 """Returns Package entity if it exists. |
| 173 | 173 |
| 174 Args: | 174 Args: |
| 175 package_name: name of the package, e.g. 'infra/tools/cipd'. | 175 package_name: name of the package, e.g. 'infra/tools/cipd'. |
| 176 | 176 |
| 177 Returns: | 177 Returns: |
| 178 Package or None. | 178 Package or None. |
| 179 """ | 179 """ |
| 180 return package_key(package_name).get() | 180 return package_key(package_name).get() |
| 181 | 181 |
| 182 @staticmethod |
| 183 def _is_in_directory(directory, path, recursive): |
| 184 """Tests if the path is under the given directory. |
| 185 |
| 186 This assumes directory is a prefix of path. |
| 187 |
| 188 Args: |
| 189 directory: string, directory the path should fall under. |
| 190 path: string, full path to test. |
| 191 recursive: whether the path can be in a subdirectory. |
| 192 |
| 193 Returns: |
| 194 True if the path is under the directory. |
| 195 """ |
| 196 start = len(directory) |
| 197 |
| 198 # The directory itself or anything shorter is not a match. |
| 199 if len(path) <= start: |
| 200 return False |
| 201 |
| 202 # The root doesn't begin with slash so only check non-root searches. |
| 203 if start: |
| 204 if path[start] != '/': |
| 205 return False |
| 206 start += 1 |
| 207 |
| 208 # A subdirectory was found and we're not looking for recursive matches. |
| 209 if not recursive and '/' in path[start:]: |
| 210 return False |
| 211 return True |
| 212 |
| 213 def list_packages(self, dir_path, recursive): |
| 214 """Returns lists of package names and directory names with the given prefix. |
| 215 |
| 216 Args: |
| 217 dir_path: string directory from which to list packages. |
| 218 recursive: boolean whether to list contents of subdirectories. |
| 219 |
| 220 Returns: |
| 221 [package name, ...], [directory name, ...] |
| 222 """ |
| 223 query = Package.query() |
| 224 |
| 225 # Normalize directory to simplify matching logic later. |
| 226 dir_path = dir_path.rstrip('/') |
| 227 |
| 228 # Only apply the filtering if a prefix was given. The empty string isn't a |
| 229 # valid key and will result in an exception. |
| 230 if dir_path: |
| 231 query = query.filter( |
| 232 # Prefix match using the operators available to us. Packages can only |
| 233 # contain lowercase ascii, numbers, and '/' so '\uffff' will always |
| 234 # be larger. |
| 235 ndb.AND(Package.key >= ndb.Key(Package, dir_path), |
| 236 Package.key <= ndb.Key(Package, dir_path + u'\uffff'))) |
| 237 pkgs = [] |
| 238 dirs = set() |
| 239 for key in query.iter(keys_only=True): |
| 240 pkg = key.string_id() |
| 241 |
| 242 # In case the index is stale since this is an eventual consistent query. |
| 243 if not pkg.startswith(dir_path): # pragma: no cover |
| 244 continue |
| 245 pkgs.append(pkg) |
| 246 |
| 247 # Add in directories derived from full package path. |
| 248 if '/' in pkg: |
| 249 parts = pkg.split('/') |
| 250 dirs.update('/'.join(parts[:n]) for n in xrange(1, len(parts))) |
| 251 |
| 252 dirs = [d for d in dirs if self._is_in_directory(dir_path, d, recursive)] |
| 253 pkgs = [p for p in pkgs if self._is_in_directory(dir_path, p, recursive) |
| 254 or len(dir_path) == len(p)] |
| 255 return pkgs, dirs |
| 256 |
| 182 def get_processing_result(self, package_name, instance_id, processor_name): | 257 def get_processing_result(self, package_name, instance_id, processor_name): |
| 183 """Returns results of some asynchronous processor or None if not ready. | 258 """Returns results of some asynchronous processor or None if not ready. |
| 184 | 259 |
| 185 Args: | 260 Args: |
| 186 package_name: name of the package, e.g. 'infra/tools/cipd'. | 261 package_name: name of the package, e.g. 'infra/tools/cipd'. |
| 187 instance_id: identifier of the package instance (SHA1 of package file). | 262 instance_id: identifier of the package instance (SHA1 of package file). |
| 188 processor_name: name of the processor to retrieve results of. | 263 processor_name: name of the processor to retrieve results of. |
| 189 | 264 |
| 190 Returns: | 265 Returns: |
| 191 ProcessingResult entity or None. | 266 ProcessingResult entity or None. |
| (...skipping 692 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 884 processors=payload['processors']) | 959 processors=payload['processors']) |
| 885 | 960 |
| 886 | 961 |
| 887 def get_backend_routes(): # pragma: no cover | 962 def get_backend_routes(): # pragma: no cover |
| 888 """Returns a list of webapp2.Route to add to backend WSGI app.""" | 963 """Returns a list of webapp2.Route to add to backend WSGI app.""" |
| 889 return [ | 964 return [ |
| 890 webapp2.Route( | 965 webapp2.Route( |
| 891 r'/internal/taskqueue/cipd-process/<instance_id:.+>', | 966 r'/internal/taskqueue/cipd-process/<instance_id:.+>', |
| 892 ProcessTaskQueueHandler), | 967 ProcessTaskQueueHandler), |
| 893 ] | 968 ] |
| OLD | NEW |