Chromium Code Reviews| 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 |