OLD | NEW |
---|---|
1 # Copyright 2015 The LUCI Authors. All rights reserved. | 1 # Copyright 2015 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 ast | 5 import ast |
6 import collections | 6 import collections |
7 import contextlib | 7 import contextlib |
8 import copy | 8 import copy |
9 import difflib | 9 import difflib |
10 import functools | 10 import functools |
(...skipping 12 matching lines...) Expand all Loading... | |
23 from . import fetch | 23 from . import fetch |
24 | 24 |
25 | 25 |
26 class InconsistentDependencyGraphError(Exception): | 26 class InconsistentDependencyGraphError(Exception): |
27 def __init__(self, project_id, specs): | 27 def __init__(self, project_id, specs): |
28 self.project_id = project_id | 28 self.project_id = project_id |
29 self.specs = specs | 29 self.specs = specs |
30 | 30 |
31 def __str__(self): | 31 def __str__(self): |
32 return 'Package specs for %s do not match: %s vs %s' % ( | 32 return 'Package specs for %s do not match: %s vs %s' % ( |
33 project_id, self.specs[0], self.specs[1]) | 33 self.project_id, self.specs[0], self.specs[1]) |
34 | 34 |
35 | 35 |
36 class CyclicDependencyError(Exception): | 36 class CyclicDependencyError(Exception): |
37 pass | 37 pass |
38 | 38 |
39 | 39 |
40 def cleanup_pyc(path): | 40 def cleanup_pyc(path): |
41 """Removes any .pyc files from |path|'s directory tree. | 41 """Removes any .pyc files from |path|'s directory tree. |
42 | 42 |
43 This ensures we always use the fresh code. | 43 This ensures we always use the fresh code. |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
159 """Returns the root of this repository.""" | 159 """Returns the root of this repository.""" |
160 raise NotImplementedError() | 160 raise NotImplementedError() |
161 | 161 |
162 def __eq__(self, other): | 162 def __eq__(self, other): |
163 raise NotImplementedError() | 163 raise NotImplementedError() |
164 | 164 |
165 def __ne__(self, other): | 165 def __ne__(self, other): |
166 return not (self == other) | 166 return not (self == other) |
167 | 167 |
168 def proto_file(self, context): | 168 def proto_file(self, context): |
169 """Returns the ProtoFile of the recipes config file in this repository. | 169 """Returns the ProtoFile of the recipes config file in this repository. |
170 Requires a good checkout.""" | 170 Requires a good checkout.""" |
171 return ProtoFile(InfraRepoConfig().to_recipes_cfg(self.repo_root(context))) | 171 return ProtoFile(InfraRepoConfig().to_recipes_cfg(self.repo_root(context))) |
172 | 172 |
173 | 173 |
174 class GitRepoSpec(RepoSpec): | 174 class GitRepoSpec(RepoSpec): |
175 def __init__(self, project_id, repo, branch, revision, path, backend): | 175 def __init__(self, project_id, repo, branch, revision, path, backend): |
176 self.project_id = project_id | 176 self.project_id = project_id |
177 self.repo = repo | 177 self.repo = repo |
178 self.branch = branch | 178 self.branch = branch |
179 self.revision = revision | 179 self.revision = revision |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
296 | 296 |
297 def __eq__(self, other): | 297 def __eq__(self, other): |
298 if not isinstance(other, type(self)): | 298 if not isinstance(other, type(self)): |
299 return False | 299 return False |
300 return self._components() == other._components() | 300 return self._components() == other._components() |
301 | 301 |
302 | 302 |
303 class PathRepoSpec(RepoSpec): | 303 class PathRepoSpec(RepoSpec): |
304 """A RepoSpec implementation that uses a local filesystem path.""" | 304 """A RepoSpec implementation that uses a local filesystem path.""" |
305 | 305 |
306 def __init__(self, path): | 306 def __init__(self, project_id, path): |
307 self.project_id = project_id | |
307 self.path = path | 308 self.path = path |
308 | 309 |
309 def __str__(self): | 310 def __str__(self): |
310 return 'PathRepoSpec{path="%(path)s"}' % self.__dict__ | 311 return ( |
312 'PathRepoSpec{project_id="%(project_id)s", path="%(path)s"}' | |
313 % self.__dict__ | |
314 ) | |
311 | 315 |
312 def checkout(self, context): | 316 def checkout(self, context): |
313 pass | 317 pass |
314 | 318 |
315 def repo_root(self, _context): | 319 def repo_root(self, _context): |
316 return self.path | 320 return self.path |
317 | 321 |
318 def proto_file(self, context): | 322 def proto_file(self, context): |
319 """Returns the ProtoFile of the recipes config file in this repository. | 323 """Returns the ProtoFile of the recipes config file in this repository. |
320 Requires a good checkout.""" | 324 Requires a good checkout.""" |
321 return ProtoFile(InfraRepoConfig().to_recipes_cfg(self.path)) | 325 return ProtoFile(InfraRepoConfig().to_recipes_cfg(self.path)) |
322 | 326 |
327 def updates(self, _context, _other_revision=None): | |
328 """Returns (empty) list of potential updates for this spec.""" | |
329 return [] | |
330 | |
331 def dump(self): | |
332 """Returns the package.proto DepSpec form of this RepoSpec.""" | |
333 return package_pb2.DepSpec( | |
334 project_id=self.project_id, | |
335 url="file://"+self.path) | |
iannucci
2017/02/03 00:00:05
These are used by the autoroller tests.
| |
336 | |
323 def __eq__(self, other): | 337 def __eq__(self, other): |
324 if not isinstance(other, type(self)): | 338 if not isinstance(other, type(self)): |
325 return False | 339 return False |
326 return self.path == other.path | 340 return self.path == other.path |
327 | 341 |
328 | 342 |
329 class RootRepoSpec(RepoSpec): | 343 class RootRepoSpec(RepoSpec): |
330 def __init__(self, proto_file): | 344 def __init__(self, proto_file): |
331 self._proto_file = proto_file | 345 self._proto_file = proto_file |
332 | 346 |
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
502 buf = proto_file.read() | 516 buf = proto_file.read() |
503 assert buf.api_version == cls.API_VERSION | 517 assert buf.api_version == cls.API_VERSION |
504 | 518 |
505 deps = { str(dep.project_id): cls.spec_for_dep(dep) | 519 deps = { str(dep.project_id): cls.spec_for_dep(dep) |
506 for dep in buf.deps } | 520 for dep in buf.deps } |
507 return cls(str(buf.project_id), str(buf.recipes_path), deps) | 521 return cls(str(buf.project_id), str(buf.recipes_path), deps) |
508 | 522 |
509 @classmethod | 523 @classmethod |
510 def spec_for_dep(cls, dep): | 524 def spec_for_dep(cls, dep): |
511 """Returns a RepoSpec for the given dependency protobuf.""" | 525 """Returns a RepoSpec for the given dependency protobuf.""" |
526 url = str(dep.url) | |
527 if url.startswith("file://"): | |
528 return PathRepoSpec(str(dep.project_id), url[len("file://"):]) | |
512 | 529 |
513 if dep.repo_type in (package_pb2.DepSpec.GIT, package_pb2.DepSpec.GITILES): | 530 if dep.repo_type in (package_pb2.DepSpec.GIT, package_pb2.DepSpec.GITILES): |
514 if dep.repo_type == package_pb2.DepSpec.GIT: | 531 if dep.repo_type == package_pb2.DepSpec.GIT: |
515 backend = fetch.GitBackend() | 532 backend = fetch.GitBackend() |
516 elif dep.repo_type == package_pb2.DepSpec.GITILES: | 533 elif dep.repo_type == package_pb2.DepSpec.GITILES: |
517 backend = fetch.GitilesBackend() | 534 backend = fetch.GitilesBackend() |
518 return GitRepoSpec(str(dep.project_id), | 535 return GitRepoSpec(str(dep.project_id), |
519 str(dep.url), | 536 url, |
520 str(dep.branch), | 537 str(dep.branch), |
521 str(dep.revision), | 538 str(dep.revision), |
522 str(dep.path_override), | 539 str(dep.path_override), |
523 backend) | 540 backend) |
524 | 541 |
525 assert False, 'Unexpected repo type: %s' % dep | 542 assert False, 'Unexpected repo type: %s' % dep |
526 | 543 |
527 @property | 544 @property |
528 def project_id(self): | 545 def project_id(self): |
529 return self._project_id | 546 return self._project_id |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
605 allow_fetch: whether to fetch dependencies rather than just checking for | 622 allow_fetch: whether to fetch dependencies rather than just checking for |
606 them. | 623 them. |
607 overrides: if not None, a dictionary of project overrides. Dictionary keys | 624 overrides: if not None, a dictionary of project overrides. Dictionary keys |
608 are the `project_id` field to override, and dictionary values | 625 are the `project_id` field to override, and dictionary values |
609 are the override path. | 626 are the override path. |
610 """ | 627 """ |
611 context = PackageContext.from_proto_file(repo_root, proto_file, allow_fetch, | 628 context = PackageContext.from_proto_file(repo_root, proto_file, allow_fetch, |
612 deps_path=deps_path) | 629 deps_path=deps_path) |
613 | 630 |
614 if overrides: | 631 if overrides: |
615 overrides = {project_id: PathRepoSpec(path) | 632 overrides = {project_id: PathRepoSpec(project_id, path) |
616 for project_id, path in overrides.iteritems()} | 633 for project_id, path in overrides.iteritems()} |
617 package_deps = cls(context, overrides=overrides) | 634 package_deps = cls(context, overrides=overrides) |
618 | 635 |
619 package_deps._root_package = package_deps._create_package(RootRepoSpec(proto _file)) | 636 package_deps._root_package = package_deps._create_package(RootRepoSpec(proto _file)) |
620 | 637 |
621 return package_deps | 638 return package_deps |
622 | 639 |
623 def _create_package(self, repo_spec): | 640 def _create_package(self, repo_spec): |
624 repo_spec.checkout(self._context) | 641 repo_spec.checkout(self._context) |
625 package_spec = PackageSpec.load_proto(repo_spec.proto_file(self._context)) | 642 package_spec = PackageSpec.load_proto(repo_spec.proto_file(self._context)) |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
675 >>> d = { 'x': 1, 'y': 2 } | 692 >>> d = { 'x': 1, 'y': 2 } |
676 >>> sorted(_updated(d, { 'y': 3, 'z': 4 }).items()) | 693 >>> sorted(_updated(d, { 'y': 3, 'z': 4 }).items()) |
677 [('x', 1), ('y', 3), ('z', 4)] | 694 [('x', 1), ('y', 3), ('z', 4)] |
678 >>> sorted(d.items()) | 695 >>> sorted(d.items()) |
679 [('x', 1), ('y', 2)] | 696 [('x', 1), ('y', 2)] |
680 """ | 697 """ |
681 | 698 |
682 d = copy.copy(d) | 699 d = copy.copy(d) |
683 d.update(updates) | 700 d.update(updates) |
684 return d | 701 return d |
OLD | NEW |