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 |