| OLD | NEW |
| 1 # Copyright 2017 The LUCI Authors. All rights reserved. | 1 # Copyright 2017 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 sys | 5 import sys |
| 6 import time | 6 import time |
| 7 | 7 |
| 8 from recipe_engine import package | 8 from recipe_engine import package |
| 9 | 9 |
| 10 from .commit_list import CommitList | 10 from .commit_list import CommitList |
| (...skipping 13 matching lines...) Expand all Loading... |
| 24 """ | 24 """ |
| 25 return { | 25 return { |
| 26 project_id: CommitList.from_repo_spec(repo_spec) | 26 project_id: CommitList.from_repo_spec(repo_spec) |
| 27 for project_id, repo_spec in deps.iteritems() | 27 for project_id, repo_spec in deps.iteritems() |
| 28 } | 28 } |
| 29 | 29 |
| 30 | 30 |
| 31 def find_best_rev(repos): | 31 def find_best_rev(repos): |
| 32 """Returns the project_id of the best repo to roll. | 32 """Returns the project_id of the best repo to roll. |
| 33 | 33 |
| 34 "Best" is determined by "is an interesting commit and moves the least amount | 34 "Best" is determined by "moves the least amount of commits, globally". There |
| 35 of commits, globally". | 35 are two ways that rolling a repo can move commits: |
| 36 | |
| 37 "Interesting" means "the commit modifies one or more recipe related files", | |
| 38 and is defined by CommitMetadata.roll_candidate. | |
| 39 | |
| 40 There are two ways that rolling a repo can move commits: | |
| 41 | 36 |
| 42 1) As dependencies. Rolling repo A that depends on (B, C) will take | 37 1) As dependencies. Rolling repo A that depends on (B, C) will take |
| 43 a penalty for each commit that B and C need to move in order to be | 38 a penalty for each commit that B and C need to move in order to be |
| 44 compatible with the new A revision. | 39 compatible with the new A revision. |
| 45 | 40 |
| 46 2) As dependees. Rolling repo A which is depended on by (B, C) will take | 41 2) As dependees. Rolling repo A which is depended on by (B, C) will take |
| 47 a penalty for each commit that B and C need to move in order to be | 42 a penalty for each commit that B and C need to move in order to be |
| 48 compatible with the new A revision. | 43 compatible with the new A revision. |
| 49 | 44 |
| 50 Each repo is analyzed with these two rules and a score is computed. The score | 45 Each repo is analyzed with these two rules and a score is computed. The score |
| (...skipping 24 matching lines...) Expand all Loading... |
| 75 Returns (str) - The project_id of the repo to advance next. | 70 Returns (str) - The project_id of the repo to advance next. |
| 76 """ | 71 """ |
| 77 # The project_ids of all the repos that can move | 72 # The project_ids of all the repos that can move |
| 78 repo_set = set(repos) | 73 repo_set = set(repos) |
| 79 | 74 |
| 80 best_project_id = None | 75 best_project_id = None |
| 81 best_score = () # (# commits moved, timestamp) | 76 best_score = () # (# commits moved, timestamp) |
| 82 | 77 |
| 83 for project_id, clist in repos.iteritems(): | 78 for project_id, clist in repos.iteritems(): |
| 84 assert isinstance(clist, CommitList) | 79 assert isinstance(clist, CommitList) |
| 85 candidate, movement_score = clist.next_roll_candidate | 80 candidate = clist.next |
| 86 if not candidate: | 81 if not candidate: |
| 87 continue | 82 continue |
| 88 | 83 |
| 89 unaccounted_repos = set(repo_set) | 84 unaccounted_repos = set(repo_set) |
| 90 | 85 |
| 86 movement_score = 0 |
| 91 # first, determine if rolling this repo will force other repos to move. | 87 # first, determine if rolling this repo will force other repos to move. |
| 92 for d_pid, dep in candidate.spec.deps.iteritems(): | 88 for d_pid, dep in candidate.spec.deps.iteritems(): |
| 93 unaccounted_repos.discard(d_pid) | 89 unaccounted_repos.discard(d_pid) |
| 94 movement_score += repos[d_pid].dist_to(dep.revision) | 90 movement_score += repos[d_pid].dist_to(dep.revision) |
| 95 | 91 |
| 96 # Next, see if any unaccounted_repos depend on this repo. | 92 # Next, see if any unaccounted_repos depend on this repo. |
| 97 for pid in unaccounted_repos: | 93 for pid in unaccounted_repos: |
| 98 movement_score += repos[pid].dist_compatible_with(pid, candidate.revision) | 94 movement_score += repos[pid].dist_compatible_with(pid, candidate.revision) |
| 99 | 95 |
| 100 score = (movement_score, candidate.commit_timestamp) | 96 score = (movement_score, candidate.commit_timestamp) |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 201 | 197 |
| 202 # not on py3 so we can't use print(..., flush=True) :( | 198 # not on py3 so we can't use print(..., flush=True) :( |
| 203 sys.stdout.write('finding roll candidates... ') | 199 sys.stdout.write('finding roll candidates... ') |
| 204 sys.stdout.flush() | 200 sys.stdout.flush() |
| 205 | 201 |
| 206 repos = get_commitlists(package_spec.deps) | 202 repos = get_commitlists(package_spec.deps) |
| 207 ret_good, ret_bad = _get_roll_candidates_impl(context, package_spec, repos) | 203 ret_good, ret_bad = _get_roll_candidates_impl(context, package_spec, repos) |
| 208 | 204 |
| 209 print('found %d/%d good/bad candidates in %0.2f seconds' % ( | 205 print('found %d/%d good/bad candidates in %0.2f seconds' % ( |
| 210 len(ret_good), len(ret_bad), time.time()-start)) | 206 len(ret_good), len(ret_bad), time.time()-start)) |
| 211 sys.stdout.flush() | |
| 212 return ret_good, ret_bad, repos | 207 return ret_good, ret_bad, repos |
| OLD | NEW |