Chromium Code Reviews| Index: scripts/slave/recipe_modules/auto_bisect/revision_state.py |
| diff --git a/scripts/slave/recipe_modules/auto_bisect/revision_state.py b/scripts/slave/recipe_modules/auto_bisect/revision_state.py |
| index e54f731e826e837b31140d235863d1e49ab70447..c449aa3f5e540b39e29ccc10f1c7d5e873c92db3 100644 |
| --- a/scripts/slave/recipe_modules/auto_bisect/revision_state.py |
| +++ b/scripts/slave/recipe_modules/auto_bisect/revision_state.py |
| @@ -9,37 +9,74 @@ class so that the bisect module and recipe can use it. |
| See perf_revision_state for an example. |
| """ |
| +import hashlib |
| +import os |
| +import re |
| + |
| +from . import depot_config |
| class RevisionState(object): |
|
qyearsley
2015/02/22 20:37:55
The other files have two blank lines between impor
RobertoCN
2015/02/24 20:01:14
Done.
|
| """Abstracts the state of a single revision on a bisect job.""" |
| - def __init__(self, revision_string, bisector): |
| + def __init__(self, revision_string, bisector, depot='chromium', |
| + base_revision=None, deps_revision=None): |
| """Create a new instance to track the state of a revision. |
| + There are two use cases for this constructor: |
| + - Creating a revision state for a chromium revision, OR |
| + - Creating a revision state for a chromium revision plus a deps change. |
|
qyearsley
2015/02/22 20:37:55
I'm not sure, but for other people without context
RobertoCN
2015/02/24 20:01:14
Done.
|
| + In the first case a revision_string and a bisector are needed. |
| + In the second case, revision_string must be None, and all of depot, |
| + base_revision and deps_revision must be provided. |
| + |
| Args: |
| - revision_string: should be in the following format: |
| - [(chromium|src)@](<commit_pos>|<commit_hash)(,<repo>@<commit>)* |
| - E.g.: |
| - 'a0b1c2ffff89009909090' (full or abbrev. commit hash) |
| - '123456' |
| - 'src@123456' |
| - 'chromium@123456' |
| - 'src@abc01234ffff,v8@00af5ceb888ff' |
| - bisector: an instance of Bisector, the object performing the bisection. |
| + revision_string (str): A git hash or a commit position in the chromium |
| + repository. If None, all kwargs must be given. |
| + bisector (Bisector): The object performing the bisection. |
| + depot (dict): One of the entries in depot_config.DEPOT_DEPS_NAME that |
| + specifies which dependency to do the DEPS change on. It is expected to |
| + contain the 'chromium' string instead of None when not bisecting any |
| + dependencies. |
| + base_revision (RevisionState): The revision state to patch with the deps |
| + change. |
| + depot_revision: The commit hash of the dependency repo to put in place of |
| + the one set for the base_revision. |
| """ |
| + # TODO(robertocn): Evaluate if the logic of this constructor should be |
| + # split into separate methods. |
| super(RevisionState, self).__init__() |
| self.bisector = bisector |
| self._good = None |
| + self.deps = None |
| self.build_status_url = None |
| self.in_progress = False |
| self.aborted = False |
| self.next_revision = None |
| self.previous_revision = None |
| self.revision_string = revision_string |
| - self.commit_hash, self.commit_pos = self._commit_from_rev_string() |
| self.build_job_name = None |
| self.test_job_name = None |
| self.built = False |
| + if not self.revision_string: |
| + assert base_revision |
| + assert base_revision.deps_file_contents |
| + assert depot != 'chromium' |
| + assert deps_revision |
| + self.needs_patch = True |
| + self.depot = depot['deps_var'] |
| + self.revision_string = base_revision.revision_string + ',' + self.depot |
| + self.revision_string += '@' + deps_revision |
| + self.deps_patch, self.deps_file_contents = self.bisector.make_deps_patch( |
| + base_revision.commit_hash, base_revision.deps_file_contents, |
| + self.depot, deps_revision) |
| + self.deps_sha = hashlib.sha1(self.deps_patch).hexdigest() |
| + self.deps_patch += self.bisector.make_deps_sha_file(self.deps_sha) |
| + self.deps = dict(base_revision.deps) |
| + self.deps[self.depot] = deps_revision |
| + else: |
| + self.needs_patch = False |
| + self.depot = depot |
| + self.commit_hash, self.commit_pos = self._commit_from_rev_string() |
| self.build_url = self.bisector.get_platform_gs_prefix() + self._gs_suffix() |
| @property |
| @@ -100,6 +137,57 @@ class RevisionState(object): |
| return True |
| return False |
| + |
| + def _gen_deps_local_scope(self): |
| + """Defines the Var and From functions in a dict for calling exec. |
| + |
| + This is needed for executing the DEPS file. |
| + """ |
| + deps_data = { |
| + 'Var': lambda _: deps_data["vars"][_], |
|
qyearsley
2015/02/22 20:37:55
Single quotes.
RobertoCN
2015/02/24 20:01:14
Done.
|
| + 'From': lambda *args: None, |
| + } |
| + return deps_data |
| + |
| + def read_deps(self): |
| + """Sets the dependencies for this revision from the contents of DEPS.""" |
| + if self.deps: |
| + return |
| + deps_contents = self.m.git.cat_file_at_revision(depot_config.FILE_DEPS) |
| + try: |
| + deps_data = self._gen_deps_local_scope() |
| + exec(deps_contents, {}, deps_data) |
| + deps_data = deps_data['deps'] |
| + except ImportError: |
| + # TODO(robertocn): Implement manual parsing of DEPS when exec fails. |
| + raise NotImplementedError('Path not implemented to manually parse DEPS') |
| + |
| + rxp = re.compile(".git@(?P<revision>[a-fA-F0-9]+)") |
|
qyearsley
2015/02/22 20:37:55
1. Variable name could probably be improved.
2. No
RobertoCN
2015/02/24 20:01:14
Done.
|
| + results = {} |
| + for depot_name, depot_data in depot_config.DEPOT_DEPS_NAME.iteritems(): |
| + if (depot_data.get('platform') and |
| + depot_data.get('platform') != os.name): |
| + # TODO(robertocn) we shouldn't be checking the os of the bot running the |
| + # bisector, but the os the tester would be running on. |
| + continue |
| + |
| + if depot_data.get('recurse') and self.depot in depot_data.get('from'): |
| + depot_data_src = depot_data.get('src') or depot_data.get('src_old') |
| + src_dir = deps_data.get(depot_data_src) |
| + if src_dir: |
| + re_results = rxp.search(src_dir) |
| + if re_results: |
| + results[depot_name] = re_results.group('revision') |
| + else: |
| + warning_text = ('Could not parse revision for %s while bisecting ' |
| + '%s' % (depot_name, self.depot)) |
| + if not warning_text in self.bisector.warnings: |
| + self.bisector.warnings.append(warning_text) |
| + else: |
| + results[depot_name] = None |
| + self.deps = results |
| + return |
| + |
| def update_status(self): |
| """Checks on the pending jobs and updates status accordingly. |
| @@ -137,8 +225,10 @@ class RevisionState(object): |
| This takes into account whether the build has a deps patch. |
| """ |
| - # TODO: Implement the logic for deps patch changes. |
| - return self.commit_hash + '.zip' |
| + name_parts = [self.commit_hash] |
| + if self.needs_patch: |
| + name_parts.append(self.deps_sha) |
| + return '%s.zip' % '_'.join(name_parts) |
| def _commit_from_rev_string(self): |
| """Gets the chromium repo commit hash and position for this revision. |