| OLD | NEW |
| 1 # Copyright 2013 The LUCI Authors. All rights reserved. | 1 # Copyright 2013 The LUCI Authors. All rights reserved. |
| 2 # Use of this source code is governed under the Apache License, Version 2.0 | 2 # Use of this source code is governed under the Apache License, Version 2.0 |
| 3 # that can be found in the LICENSE file. | 3 # that can be found in the LICENSE file. |
| 4 | 4 |
| 5 import functools | 5 import functools |
| 6 import itertools | 6 import itertools |
| 7 import os | 7 import os |
| 8 import re |
| 8 import tempfile | 9 import tempfile |
| 9 | 10 |
| 10 from recipe_engine import recipe_api | 11 from recipe_engine import recipe_api |
| 11 from recipe_engine import config_types | 12 from recipe_engine import config_types |
| 12 | 13 |
| 13 | 14 |
| 14 class Error(Exception): | 15 class Error(Exception): |
| 15 """Error specific to path recipe module.""" | 16 """Error specific to path recipe module.""" |
| 16 | 17 |
| 17 | 18 |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 65 current platform according to the `platform` module. This allows us to | 66 current platform according to the `platform` module. This allows us to |
| 66 simulate path functions according to the platform being tested, rather than | 67 simulate path functions according to the platform being tested, rather than |
| 67 the platform which is currently running. | 68 the platform which is currently running. |
| 68 """ | 69 """ |
| 69 | 70 |
| 70 def __init__(self, api, _mock_path_exists): | 71 def __init__(self, api, _mock_path_exists): |
| 71 self._api = api | 72 self._api = api |
| 72 self._mock_path_exists = path_set(self, _mock_path_exists) | 73 self._mock_path_exists = path_set(self, _mock_path_exists) |
| 73 self._pth = None | 74 self._pth = None |
| 74 | 75 |
| 75 def __getattr__(self, name): | 76 def _init_pth(self): |
| 76 if not self._pth: | 77 if not self._pth: |
| 77 if self._api.m.platform.is_win: | 78 if self._api.m.platform.is_win: |
| 78 import ntpath as pth | 79 import ntpath as pth |
| 79 elif self._api.m.platform.is_mac or self._api.m.platform.is_linux: | 80 elif self._api.m.platform.is_mac or self._api.m.platform.is_linux: |
| 80 import posixpath as pth | 81 import posixpath as pth |
| 81 self._pth = pth | 82 self._pth = pth |
| 83 |
| 84 def __getattr__(self, name): |
| 85 self._init_pth() |
| 82 return getattr(self._pth, name) | 86 return getattr(self._pth, name) |
| 83 | 87 |
| 84 def mock_add_paths(self, path): | 88 def mock_add_paths(self, path): |
| 85 """ | 89 """ |
| 86 Adds a path and all of its parents to the set of existing paths. | 90 Adds a path and all of its parents to the set of existing paths. |
| 87 """ | 91 """ |
| 88 self._mock_path_exists.add(path) | 92 self._mock_path_exists.add(path) |
| 89 | 93 |
| 90 def exists(self, path): # pylint: disable=E0202 | 94 def exists(self, path): # pylint: disable=E0202 |
| 91 """Return True if path refers to an existing path.""" | 95 """Return True if path refers to an existing path.""" |
| 92 return self._mock_path_exists.contains(path) | 96 return self._mock_path_exists.contains(path) |
| 93 | 97 |
| 98 # This matches: |
| 99 # [START_DIR] |
| 100 # RECIPE[some_pkg::some_module:recipe_name] |
| 101 # |
| 102 # and friends at the beginning of a string. |
| 103 ROOT_MATCHER = re.compile('^[A-Z_]*\[[^]]*\]') |
| 104 |
| 105 def normpath(self, path): |
| 106 """Normalizese the path. |
| 107 |
| 108 This splits off a recipe base (i.e. RECIPE[...]) so that normpath is |
| 109 only called on the user-supplied portion of the path. |
| 110 """ |
| 111 self._init_pth() |
| 112 real_normpath = self._pth.normpath |
| 113 m = self.ROOT_MATCHER.match(path) |
| 114 if m: |
| 115 prefix = m.group(0) |
| 116 rest = path[len(prefix):] |
| 117 if rest == '': |
| 118 # normpath turns '' into '.' |
| 119 return prefix |
| 120 return prefix + real_normpath(rest) |
| 121 return real_normpath(path) |
| 122 |
| 94 def abspath(self, path): | 123 def abspath(self, path): |
| 95 """Returns the absolute version of path.""" | 124 """Returns the absolute version of path.""" |
| 96 return self.normpath(path) | 125 return self.normpath(path) |
| 97 | 126 |
| 98 def realpath(self, path): | 127 def realpath(self, path): |
| 99 """Returns the canonical version of the path.""" | 128 """Returns the canonical version of the path.""" |
| 100 return self.normpath(path) | 129 return self.normpath(path) |
| 101 | 130 |
| 102 def expanduser(self, path): | 131 def expanduser(self, path): |
| 103 return path.replace('~', '[HOME]') | 132 return path.replace('~', '[HOME]') |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 249 Example: | 278 Example: |
| 250 ``` | 279 ``` |
| 251 # assume [START_DIR] == "/basis/dir/for/recipe" | 280 # assume [START_DIR] == "/basis/dir/for/recipe" |
| 252 api.path.abs_to_path("/basis/dir/for/recipe/some/other/dir") -> | 281 api.path.abs_to_path("/basis/dir/for/recipe/some/other/dir") -> |
| 253 Path("[START_DIR]/some/other/dir") | 282 Path("[START_DIR]/some/other/dir") |
| 254 ``` | 283 ``` |
| 255 | 284 |
| 256 Raises an ValueError if the preconditions are not met, otherwise returns the | 285 Raises an ValueError if the preconditions are not met, otherwise returns the |
| 257 Path object. | 286 Path object. |
| 258 """ | 287 """ |
| 259 if self.abspath(abs_string_path) != abs_string_path: | 288 ap = self.abspath(abs_string_path) |
| 260 raise ValueError("path is not absolute: %r" % abs_string_path) | 289 if ap != abs_string_path: |
| 290 raise ValueError("path is not absolute: %r v %r" % (abs_string_path, ap)) |
| 261 | 291 |
| 262 # try module/recipe/package resource paths first | 292 # try module/recipe/package resource paths first |
| 263 sPath, path = self._paths_client.find_longest_prefix( | 293 sPath, path = self._paths_client.find_longest_prefix( |
| 264 abs_string_path, self.sep) | 294 abs_string_path, self.sep) |
| 265 if path is None: | 295 if path is None: |
| 266 # try base paths now | 296 # try base paths now |
| 267 for path_name in itertools.chain(self.c.dynamic_paths, self.c.base_paths): | 297 for path_name in itertools.chain(self.c.dynamic_paths, self.c.base_paths): |
| 268 path = self[path_name] | 298 path = self[path_name] |
| 269 sPath = str(path) | 299 sPath = str(path) |
| 270 if abs_string_path.startswith(sPath): | 300 if abs_string_path.startswith(sPath): |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 302 if name in self.OK_ATTRS: | 332 if name in self.OK_ATTRS: |
| 303 return getattr(self._path_mod, name) | 333 return getattr(self._path_mod, name) |
| 304 if name in self.FILTER_METHODS: | 334 if name in self.FILTER_METHODS: |
| 305 return string_filter(getattr(self._path_mod, name)) | 335 return string_filter(getattr(self._path_mod, name)) |
| 306 raise AttributeError("'%s' object has no attribute '%s'" % | 336 raise AttributeError("'%s' object has no attribute '%s'" % |
| 307 (self._path_mod, name)) # pragma: no cover | 337 (self._path_mod, name)) # pragma: no cover |
| 308 | 338 |
| 309 def __dir__(self): # pragma: no cover | 339 def __dir__(self): # pragma: no cover |
| 310 # Used for helping out show_me_the_modules.py | 340 # Used for helping out show_me_the_modules.py |
| 311 return self.__dict__.keys() + list(self.OK_ATTRS + self.FILTER_METHODS) | 341 return self.__dict__.keys() + list(self.OK_ATTRS + self.FILTER_METHODS) |
| OLD | NEW |