Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(243)

Side by Side Diff: recipe_engine/package.py

Issue 2728303004: [package.proto] add canonical_base_url field. (Closed)
Patch Set: spaces Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « recipe_engine/package.proto ('k') | recipe_engine/package_pb2.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 copy 5 import copy
6 import difflib 6 import difflib
7 import logging 7 import logging
8 import operator 8 import operator
9 import os 9 import os
10 import subprocess 10 import subprocess
(...skipping 18 matching lines...) Expand all
29 29
30 class CyclicDependencyError(Exception): 30 class CyclicDependencyError(Exception):
31 pass 31 pass
32 32
33 33
34 def cleanup_pyc(path): 34 def cleanup_pyc(path):
35 """Removes any .pyc files from |path|'s directory tree. 35 """Removes any .pyc files from |path|'s directory tree.
36 36
37 This ensures we always use the fresh code. 37 This ensures we always use the fresh code.
38 """ 38 """
39 for root, dirs, files in os.walk(path): 39 for root, _dirs, files in os.walk(path):
40 for f in files: 40 for f in files:
41 if f.endswith('.pyc'): 41 if f.endswith('.pyc'):
42 os.unlink(os.path.join(root, f)) 42 os.unlink(os.path.join(root, f))
43 43
44 44
45 class InfraRepoConfig(object): 45 class InfraRepoConfig(object):
46 def to_recipes_cfg(self, repo_root): 46 def to_recipes_cfg(self, repo_root):
47 # TODO(luqui): This is not always correct. It can be configured in 47 # TODO(luqui): This is not always correct. It can be configured in
48 # infra/config:refs.cfg. 48 # infra/config:refs.cfg.
49 return os.path.join(repo_root, 'infra', 'config', 'recipes.cfg') 49 return os.path.join(repo_root, 'infra', 'config', 'recipes.cfg')
(...skipping 304 matching lines...) Expand 10 before | Expand all | Expand 10 after
354 return False 354 return False
355 return self._proto_file == other._proto_file 355 return self._proto_file == other._proto_file
356 356
357 357
358 class Package(object): 358 class Package(object):
359 """Package represents a loaded package, and contains path and dependency 359 """Package represents a loaded package, and contains path and dependency
360 information. 360 information.
361 361
362 This is accessed by loader.py through RecipeDeps.get_package. 362 This is accessed by loader.py through RecipeDeps.get_package.
363 """ 363 """
364 def __init__(self, name, repo_spec, deps, repo_root, relative_recipes_dir): 364 def __init__(self, name, repo_spec, deps, repo_root, relative_recipes_dir,
365 canonical_base_url):
365 self.name = name 366 self.name = name
366 self.repo_spec = repo_spec 367 self.repo_spec = repo_spec
367 self.deps = deps 368 self.deps = deps
368 self.repo_root = repo_root 369 self.repo_root = repo_root
369 self.relative_recipes_dir = relative_recipes_dir 370 self.relative_recipes_dir = relative_recipes_dir
371 self.canonical_base_url = canonical_base_url
370 372
371 @property 373 @property
372 def recipes_dir(self): 374 def recipes_dir(self):
373 return os.path.join(self.repo_root, self.relative_recipes_dir) 375 return os.path.join(self.repo_root, self.relative_recipes_dir)
374 376
375 @property 377 @property
376 def recipe_dir(self): 378 def recipe_dir(self):
377 return os.path.join(self.recipes_dir, 'recipes') 379 return os.path.join(self.recipes_dir, 'recipes')
378 380
379 @property 381 @property
380 def module_dir(self): 382 def module_dir(self):
381 return os.path.join(self.recipes_dir, 'recipe_modules') 383 return os.path.join(self.recipes_dir, 'recipe_modules')
382 384
383 def find_dep(self, dep_name): 385 def find_dep(self, dep_name):
384 if dep_name == self.name: 386 if dep_name == self.name:
385 return self 387 return self
386 388
387 assert dep_name in self.deps, ( 389 assert dep_name in self.deps, (
388 '%s does not exist or is not declared as a dependency of %s' % ( 390 '%s does not exist or is not declared as a dependency of %s' % (
389 dep_name, self.name)) 391 dep_name, self.name))
390 return self.deps[dep_name] 392 return self.deps[dep_name]
391 393
392 def module_path(self, module_name): 394 def module_path(self, module_name):
393 return os.path.join(self.recipes_dir, 'recipe_modules', module_name) 395 return os.path.join(self.recipes_dir, 'recipe_modules', module_name)
394 396
395 def __repr__(self): 397 def __repr__(self):
396 return 'Package(%r, %r, %r, %r)' % ( 398 return 'Package(%r, %r, %r, %r, %r)' % (
397 self.name, self.repo_spec, self.deps, self.recipe_dir) 399 self.name, self.repo_spec, self.deps, self.recipe_dir,
400 self.canonical_base_url)
398 401
399 def __str__(self): 402 def __str__(self):
400 return 'Package %s, with dependencies %s' % (self.name, self.deps.keys()) 403 return 'Package %s, with dependencies %s' % (self.name, self.deps.keys())
401 404
402 405
403 class RollCandidate(object): 406 class RollCandidate(object):
404 """RollCandidate represents a recipe roll candidate, i.e. updates 407 """RollCandidate represents a recipe roll candidate, i.e. updates
405 to pinned revisions of recipe dependencies. 408 to pinned revisions of recipe dependencies.
406 409
407 This is mostly used by recipes.py autoroll command. 410 This is mostly used by recipes.py autoroll command.
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
459 def get_rolled_spec(self): 462 def get_rolled_spec(self):
460 """Returns a PackageSpec with all the deps updates from this roll.""" 463 """Returns a PackageSpec with all the deps updates from this roll."""
461 # TODO(phajdan.jr): does this preserve comments? should it? 464 # TODO(phajdan.jr): does this preserve comments? should it?
462 new_deps = _updated( 465 new_deps = _updated(
463 self._package_spec.deps, 466 self._package_spec.deps,
464 { project_id: spec for project_id, spec in 467 { project_id: spec for project_id, spec in
465 self._updates.iteritems() }) 468 self._updates.iteritems() })
466 return PackageSpec( 469 return PackageSpec(
467 self._package_spec.project_id, 470 self._package_spec.project_id,
468 self._package_spec.recipes_path, 471 self._package_spec.recipes_path,
469 new_deps) 472 new_deps,
473 self._package_spec.canonical_base_url)
470 474
471 def get_commit_infos(self): 475 def get_commit_infos(self):
472 """Returns a mapping project_id -> list of commits from that repo 476 """Returns a mapping project_id -> list of commits from that repo
473 that are getting pulled by this roll. 477 that are getting pulled by this roll.
474 """ 478 """
475 commit_infos = {} 479 commit_infos = {}
476 480
477 for project_id, update in self._updates.iteritems(): 481 for project_id, update in self._updates.iteritems():
478 commit_infos[project_id] = self._package_spec.deps[ 482 commit_infos[project_id] = self._package_spec.deps[
479 project_id].commit_infos(self._context, update.revision) 483 project_id].commit_infos(self._context, update.revision)
(...skipping 10 matching lines...) Expand all
490 """Returns a unified diff between original package spec and one after roll. 494 """Returns a unified diff between original package spec and one after roll.
491 """ 495 """
492 orig = str(self._package_spec.dump()).splitlines() 496 orig = str(self._package_spec.dump()).splitlines()
493 new = str(self.get_rolled_spec().dump()).splitlines() 497 new = str(self.get_rolled_spec().dump()).splitlines()
494 return '\n'.join(difflib.unified_diff(orig, new, lineterm='')) 498 return '\n'.join(difflib.unified_diff(orig, new, lineterm=''))
495 499
496 500
497 class PackageSpec(object): 501 class PackageSpec(object):
498 API_VERSION = 1 502 API_VERSION = 1
499 503
500 def __init__(self, project_id, recipes_path, deps): 504 def __init__(self, project_id, recipes_path, deps, canonical_base_url):
501 self._project_id = project_id 505 self._project_id = project_id
502 self._recipes_path = recipes_path 506 self._recipes_path = recipes_path
503 self._deps = deps 507 self._deps = deps
508 self._canonical_base_url = canonical_base_url
504 509
505 @classmethod 510 @classmethod
506 def load_proto(cls, proto_file): 511 def load_proto(cls, proto_file):
507 buf = proto_file.read() 512 buf = proto_file.read()
508 assert buf.api_version == cls.API_VERSION 513 assert buf.api_version == cls.API_VERSION
509 514
510 deps = { str(dep.project_id): cls.spec_for_dep(dep) 515 deps = { str(dep.project_id): cls.spec_for_dep(dep)
511 for dep in buf.deps } 516 for dep in buf.deps }
512 return cls(str(buf.project_id), str(buf.recipes_path), deps) 517 return cls(str(buf.project_id), str(buf.recipes_path), deps,
518 buf.canonical_base_url)
513 519
514 @classmethod 520 @classmethod
515 def spec_for_dep(cls, dep): 521 def spec_for_dep(cls, dep):
516 """Returns a RepoSpec for the given dependency protobuf.""" 522 """Returns a RepoSpec for the given dependency protobuf."""
517 url = str(dep.url) 523 url = str(dep.url)
518 if url.startswith("file://"): 524 if url.startswith("file://"):
519 return PathRepoSpec(str(dep.project_id), url[len("file://"):]) 525 return PathRepoSpec(str(dep.project_id), url[len("file://"):])
520 526
521 if dep.repo_type in (package_pb2.DepSpec.GIT, package_pb2.DepSpec.GITILES): 527 if dep.repo_type in (package_pb2.DepSpec.GIT, package_pb2.DepSpec.GITILES):
522 if dep.repo_type == package_pb2.DepSpec.GIT: 528 if dep.repo_type == package_pb2.DepSpec.GIT:
(...skipping 14 matching lines...) Expand all
537 return self._project_id 543 return self._project_id
538 544
539 @property 545 @property
540 def recipes_path(self): 546 def recipes_path(self):
541 return self._recipes_path 547 return self._recipes_path
542 548
543 @property 549 @property
544 def deps(self): 550 def deps(self):
545 return self._deps 551 return self._deps
546 552
553 @property
554 def canonical_base_url(self):
555 return self._canonical_base_url
556
547 def dump(self): 557 def dump(self):
548 return package_pb2.Package( 558 return package_pb2.Package(
549 api_version=self.API_VERSION, 559 api_version=self.API_VERSION,
550 project_id=self._project_id, 560 project_id=self._project_id,
551 recipes_path=self._recipes_path, 561 recipes_path=self._recipes_path,
552 deps=[ self._deps[dep].dump() for dep in sorted(self._deps.keys()) ]) 562 deps=[ self._deps[dep].dump() for dep in sorted(self._deps.keys()) ],
563 canonical_base_url=self._canonical_base_url)
553 564
554 def roll_candidates(self, root_spec, context): 565 def roll_candidates(self, root_spec, context):
555 """Returns list of consistent roll candidates, and rejected roll candidates. 566 """Returns list of consistent roll candidates, and rejected roll candidates.
556 567
557 The first one is sorted by score, descending. The more commits are pulled by 568 The first one is sorted by score, descending. The more commits are pulled by
558 the roll, the higher score. 569 the roll, the higher score.
559 570
560 Second list is included to distinguish between a situation where there are 571 Second list is included to distinguish between a situation where there are
561 no roll candidates from one where there are updates but they're not 572 no roll candidates from one where there are updates but they're not
562 consistent. 573 consistent.
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
617 are the override path. 628 are the override path.
618 """ 629 """
619 context = PackageContext.from_proto_file(repo_root, proto_file, allow_fetch, 630 context = PackageContext.from_proto_file(repo_root, proto_file, allow_fetch,
620 deps_path=deps_path) 631 deps_path=deps_path)
621 632
622 if overrides: 633 if overrides:
623 overrides = {project_id: PathRepoSpec(project_id, path) 634 overrides = {project_id: PathRepoSpec(project_id, path)
624 for project_id, path in overrides.iteritems()} 635 for project_id, path in overrides.iteritems()}
625 package_deps = cls(context, overrides=overrides) 636 package_deps = cls(context, overrides=overrides)
626 637
627 package_deps._root_package = package_deps._create_package(RootRepoSpec(proto _file)) 638 package_deps._root_package = package_deps._create_package(
639 RootRepoSpec(proto_file))
628 640
629 return package_deps 641 return package_deps
630 642
631 def _create_package(self, repo_spec): 643 def _create_package(self, repo_spec):
632 repo_spec.checkout(self._context) 644 repo_spec.checkout(self._context)
633 package_spec = PackageSpec.load_proto(repo_spec.proto_file(self._context)) 645 package_spec = PackageSpec.load_proto(repo_spec.proto_file(self._context))
634 return self._create_from_spec(repo_spec, package_spec) 646 return self._create_from_spec(repo_spec, package_spec)
635 647
636 def _create_from_spec(self, repo_spec, package_spec): 648 def _create_from_spec(self, repo_spec, package_spec):
637 project_id = package_spec.project_id 649 project_id = package_spec.project_id
(...skipping 12 matching lines...) Expand all
650 self._packages[project_id] = None 662 self._packages[project_id] = None
651 663
652 deps = {} 664 deps = {}
653 for dep, dep_repo in sorted(package_spec.deps.items()): 665 for dep, dep_repo in sorted(package_spec.deps.items()):
654 dep_repo = self._overrides.get(dep, dep_repo) 666 dep_repo = self._overrides.get(dep, dep_repo)
655 deps[dep] = self._create_package(dep_repo) 667 deps[dep] = self._create_package(dep_repo)
656 668
657 package = Package( 669 package = Package(
658 project_id, repo_spec, deps, 670 project_id, repo_spec, deps,
659 repo_spec.repo_root(self._context), 671 repo_spec.repo_root(self._context),
660 package_spec.recipes_path) 672 package_spec.recipes_path,
673 package_spec.canonical_base_url)
661 674
662 self._packages[project_id] = package 675 self._packages[project_id] = package
663 return package 676 return package
664 677
665 # TODO(luqui): Remove this, so all accesses to packages are done 678 # TODO(luqui): Remove this, so all accesses to packages are done
666 # via other packages with properly scoped deps. 679 # via other packages with properly scoped deps.
667 def get_package(self, package_id): 680 def get_package(self, package_id):
668 return self._packages[package_id] 681 return self._packages[package_id]
669 682
670 @property 683 @property
(...skipping 12 matching lines...) Expand all
683 >>> d = { 'x': 1, 'y': 2 } 696 >>> d = { 'x': 1, 'y': 2 }
684 >>> sorted(_updated(d, { 'y': 3, 'z': 4 }).items()) 697 >>> sorted(_updated(d, { 'y': 3, 'z': 4 }).items())
685 [('x', 1), ('y', 3), ('z', 4)] 698 [('x', 1), ('y', 3), ('z', 4)]
686 >>> sorted(d.items()) 699 >>> sorted(d.items())
687 [('x', 1), ('y', 2)] 700 [('x', 1), ('y', 2)]
688 """ 701 """
689 702
690 d = copy.copy(d) 703 d = copy.copy(d)
691 d.update(updates) 704 d.update(updates)
692 return d 705 return d
OLDNEW
« no previous file with comments | « recipe_engine/package.proto ('k') | recipe_engine/package_pb2.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698