Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # Copyright 2014 The Chromium Authors. All rights reserved. | 1 # Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 | 5 |
| 6 """Recipe module to ensure a checkout is consistant on a bot.""" | 6 """Recipe module to ensure a checkout is consistant on a bot.""" |
| 7 | 7 |
| 8 from recipe_engine import recipe_api | 8 from recipe_engine import recipe_api |
| 9 | 9 |
| 10 | 10 |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 41 ret += ']' | 41 ret += ']' |
| 42 elif isinstance(spec, basestring): | 42 elif isinstance(spec, basestring): |
| 43 ret = repr(str(spec)) | 43 ret = repr(str(spec)) |
| 44 else: | 44 else: |
| 45 ret = repr(spec) | 45 ret = repr(spec) |
| 46 return ret | 46 return ret |
| 47 | 47 |
| 48 | 48 |
| 49 class BotUpdateApi(recipe_api.RecipeApi): | 49 class BotUpdateApi(recipe_api.RecipeApi): |
| 50 | 50 |
| 51 def __init__(self, *args, **kwargs): | 51 def __init__(self, mastername, buildername, slavename, issue, patchset, |
| 52 self._properties = {} | 52 patch_url, repository, gerrit_ref, rietveld, revision, |
| 53 super(BotUpdateApi, self).__init__(*args, **kwargs) | 53 parent_got_revision, deps_revision_overrides, fail_patch, |
| 54 *args, **kwargs): | |
| 55 self._mastername = mastername | |
| 56 self._buildername = buildername | |
| 57 self._slavename = slavename | |
| 58 self._issue = issue | |
| 59 self._patchset = patchset | |
| 60 self._patch_url = patch_url | |
| 61 self._repository = repository | |
| 62 self._gerrit_ref = gerrit_ref | |
| 63 self._rietveld = rietveld | |
| 64 self._revision = revision | |
| 65 self._parent_got_revision = parent_got_revision | |
| 66 self._deps_revision_overrides = deps_revision_overrides | |
| 67 self._fail_patch = fail_patch | |
| 68 | |
| 69 self._last_returned_properties = {} | |
| 70 super(BotUpdateApi, self).__init__(*args, **kwargs) | |
| 54 | 71 |
| 55 def __call__(self, name, cmd, **kwargs): | 72 def __call__(self, name, cmd, **kwargs): |
| 56 """Wrapper for easy calling of bot_update.""" | 73 """Wrapper for easy calling of bot_update.""" |
| 57 assert isinstance(cmd, (list, tuple)) | 74 assert isinstance(cmd, (list, tuple)) |
| 58 bot_update_path = self.resource('bot_update.py') | 75 bot_update_path = self.resource('bot_update.py') |
| 59 kwargs.setdefault('infra_step', True) | 76 kwargs.setdefault('infra_step', True) |
| 60 kwargs.setdefault('env', {}) | 77 kwargs.setdefault('env', {}) |
| 61 kwargs['env'].setdefault('PATH', '%(PATH)s') | 78 kwargs['env'].setdefault('PATH', '%(PATH)s') |
| 62 kwargs['env']['PATH'] = self.m.path.pathsep.join([ | 79 kwargs['env']['PATH'] = self.m.path.pathsep.join([ |
| 63 kwargs['env']['PATH'], str(self._module.PACKAGE_DIRECTORY)]) | 80 kwargs['env']['PATH'], str(self._module.PACKAGE_DIRECTORY)]) |
| 64 return self.m.python(name, bot_update_path, cmd, **kwargs) | 81 return self.m.python(name, bot_update_path, cmd, **kwargs) |
| 65 | 82 |
| 66 @property | 83 @property |
| 67 def properties(self): | 84 def last_returned_properties(self): |
| 68 return self._properties | 85 return self._last_returned_properties |
| 69 | 86 |
| 70 def ensure_checkout(self, gclient_config=None, suffix=None, | 87 def ensure_checkout(self, gclient_config=None, suffix=None, |
| 71 patch=True, update_presentation=True, | 88 patch=True, update_presentation=True, |
| 72 force=False, patch_root=None, no_shallow=False, | 89 force=False, patch_root=None, no_shallow=False, |
| 73 with_branch_heads=False, refs=None, | 90 with_branch_heads=False, refs=None, |
| 74 patch_project_roots=None, patch_oauth2=False, | 91 patch_project_roots=None, patch_oauth2=False, |
| 75 output_manifest=True, clobber=False, | 92 output_manifest=True, clobber=False, run_hooks=True, |
| 76 root_solution_revision=None, **kwargs): | 93 root_solution_revision=None, rietveld=None, issue=None, |
| 94 patchset=None, git_cache_dir=None, **kwargs): | |
| 95 """ | |
| 96 Args: | |
| 97 run_hooks: Whether or not to run `gclient runhooks` after we checkout the | |
|
Ryan Tseng
2016/03/02 02:09:34
Is this used anywhere?
| |
| 98 code. Defaults to true. | |
| 99 gclient_config: The gclient configuration to use when running bot_update. | |
| 100 If omitted, the current gclient configuration is used. | |
| 101 rietveld: The rietveld server to use. If omitted, will infer from | |
| 102 the 'rietveld' property. | |
| 103 issue: The rietveld issue number to use. If omitted, will infer from | |
| 104 the 'issue' property. | |
| 105 patchset: The rietveld issue patchset to use. If omitted, will infer from | |
| 106 the 'patchset' property. | |
| 107 git_cache_dir: The directory to use as the git cache. If omitted, will use | |
| 108 the 'cache_dir' path in the path api module. | |
| 109 """ | |
| 77 refs = refs or [] | 110 refs = refs or [] |
| 78 # We can re-use the gclient spec from the gclient module, since all the | 111 # We can re-use the gclient spec from the gclient module, since all the |
| 79 # data bot_update needs is already configured into the gclient spec. | 112 # data bot_update needs is already configured into the gclient spec. |
| 80 cfg = gclient_config or self.m.gclient.c | 113 cfg = gclient_config or self.m.gclient.c |
| 81 spec_string = jsonish_to_python(cfg.as_jsonish(), True) | 114 spec_string = jsonish_to_python(cfg.as_jsonish(), True) |
| 82 | 115 |
| 83 # Used by bot_update to determine if we want to run or not. | 116 # Used by bot_update to determine if we want to run or not. |
| 84 master = self.m.properties['mastername'] | 117 master = self._mastername |
| 85 builder = self.m.properties['buildername'] | 118 builder = self._buildername |
| 86 slave = self.m.properties['slavename'] | 119 slave = self._slavename |
| 87 | 120 |
| 88 # Construct our bot_update command. This basically be inclusive of | 121 # Construct our bot_update command. This basically be inclusive of |
| 89 # everything required for bot_update to know: | 122 # everything required for bot_update to know: |
| 90 root = patch_root | 123 root = patch_root |
| 91 if root is None: | 124 if root is None: |
| 92 root = cfg.solutions[0].name | 125 root = cfg.solutions[0].name |
| 93 additional = self.m.rietveld.calculate_issue_root(patch_project_roots) | 126 additional = self.m.rietveld.calculate_issue_root(patch_project_roots) |
| 94 if additional: | 127 if additional: |
| 95 root = self.m.path.join(root, additional) | 128 root = self.m.path.join(root, additional) |
| 96 | 129 |
| 97 if patch: | 130 if patch: |
| 98 issue = self.m.properties.get('issue') | 131 issue = issue or self._issue |
| 99 patchset = self.m.properties.get('patchset') | 132 patchset = patchset or self._patchset |
| 100 patch_url = self.m.properties.get('patch_url') | 133 patch_url = self._patch_url |
| 101 gerrit_repo = self.m.properties.get('repository') | 134 gerrit_repo = self._repository |
| 102 gerrit_ref = self.m.properties.get('event.patchSet.ref') | 135 gerrit_ref = self._gerrit_ref |
| 103 else: | 136 else: |
| 104 # The trybot recipe sometimes wants to de-apply the patch. In which case | 137 # The trybot recipe sometimes wants to de-apply the patch. In which case |
| 105 # we pretend the issue/patchset/patch_url never existed. | 138 # we pretend the issue/patchset/patch_url never existed. |
| 106 issue = patchset = patch_url = email_file = key_file = None | 139 issue = patchset = patch_url = email_file = key_file = None |
| 107 gerrit_repo = gerrit_ref = None | 140 gerrit_repo = gerrit_ref = None |
| 108 | 141 |
| 109 # Issue and patchset must come together. | 142 # Issue and patchset must come together. |
| 110 if issue: | 143 if issue: |
| 111 assert patchset | 144 assert patchset |
| 112 if patchset: | 145 if patchset: |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 136 flags = [ | 169 flags = [ |
| 137 # 1. Do we want to run? (master/builder/slave). | 170 # 1. Do we want to run? (master/builder/slave). |
| 138 ['--master', master], | 171 ['--master', master], |
| 139 ['--builder', builder], | 172 ['--builder', builder], |
| 140 ['--slave', slave], | 173 ['--slave', slave], |
| 141 | 174 |
| 142 # 2. What do we want to check out (spec/root/rev/rev_map). | 175 # 2. What do we want to check out (spec/root/rev/rev_map). |
| 143 ['--spec', spec_string], | 176 ['--spec', spec_string], |
| 144 ['--root', root], | 177 ['--root', root], |
| 145 ['--revision_mapping_file', self.m.json.input(rev_map)], | 178 ['--revision_mapping_file', self.m.json.input(rev_map)], |
| 146 ['--git-cache-dir', self.m.path['git_cache']], | 179 ['--git-cache-dir', git_cache_dir or self.m.path['git_cache']], |
| 147 | 180 |
| 148 # 3. How to find the patch, if any (issue/patchset/patch_url). | 181 # 3. How to find the patch, if any (issue/patchset/patch_url). |
| 149 ['--issue', issue], | 182 ['--issue', issue], |
| 150 ['--patchset', patchset], | 183 ['--patchset', patchset], |
| 151 ['--patch_url', patch_url], | 184 ['--patch_url', patch_url], |
| 152 ['--rietveld_server', self.m.properties.get('rietveld')], | 185 ['--rietveld_server', rietveld or self._rietveld], |
| 153 ['--gerrit_repo', gerrit_repo], | 186 ['--gerrit_repo', gerrit_repo], |
| 154 ['--gerrit_ref', gerrit_ref], | 187 ['--gerrit_ref', gerrit_ref], |
| 155 ['--apply_issue_email_file', email_file], | 188 ['--apply_issue_email_file', email_file], |
| 156 ['--apply_issue_key_file', key_file], | 189 ['--apply_issue_key_file', key_file], |
| 157 | 190 |
| 158 # 4. Hookups to JSON output back into recipes. | 191 # 4. Hookups to JSON output back into recipes. |
| 159 ['--output_json', self.m.json.output()],] | 192 ['--output_json', self.m.json.output()],] |
| 160 | 193 |
| 161 | 194 |
| 162 # Collect all fixed revisions to simulate them in the json output. | 195 # Collect all fixed revisions to simulate them in the json output. |
| 163 # Fixed revision are the explicit input revisions of bot_update.py, i.e. | 196 # Fixed revision are the explicit input revisions of bot_update.py, i.e. |
| 164 # every command line parameter "--revision name@value". | 197 # every command line parameter "--revision name@value". |
| 165 fixed_revisions = {} | 198 fixed_revisions = {} |
| 166 | 199 |
| 167 revisions = {} | 200 revisions = {} |
| 168 for solution in cfg.solutions: | 201 for solution in cfg.solutions: |
| 169 if solution.revision: | 202 if solution.revision: |
| 170 revisions[solution.name] = solution.revision | 203 revisions[solution.name] = solution.revision |
| 171 elif solution == cfg.solutions[0]: | 204 elif solution == cfg.solutions[0]: |
| 172 revisions[solution.name] = ( | 205 revisions[solution.name] = ( |
| 173 self.m.properties.get('parent_got_revision') or | 206 self._parent_got_revision or |
| 174 self.m.properties.get('revision') or | 207 self._revision or |
| 175 'HEAD') | 208 'HEAD') |
| 176 if self.m.gclient.c and self.m.gclient.c.revisions: | 209 if self.m.gclient.c and self.m.gclient.c.revisions: |
| 177 revisions.update(self.m.gclient.c.revisions) | 210 revisions.update(self.m.gclient.c.revisions) |
| 178 if cfg.solutions and root_solution_revision: | 211 if cfg.solutions and root_solution_revision: |
| 179 revisions[cfg.solutions[0].name] = root_solution_revision | 212 revisions[cfg.solutions[0].name] = root_solution_revision |
| 180 # Allow for overrides required to bisect into rolls. | 213 # Allow for overrides required to bisect into rolls. |
| 181 revisions.update(self.m.properties.get('deps_revision_overrides', {})) | 214 revisions.update(self._deps_revision_overrides) |
| 182 for name, revision in sorted(revisions.items()): | 215 for name, revision in sorted(revisions.items()): |
| 183 fixed_revision = self.m.gclient.resolve_revision(revision) | 216 fixed_revision = self.m.gclient.resolve_revision(revision) |
| 184 if fixed_revision: | 217 if fixed_revision: |
| 185 fixed_revisions[name] = fixed_revision | 218 fixed_revisions[name] = fixed_revision |
| 186 flags.append(['--revision', '%s@%s' % (name, fixed_revision)]) | 219 flags.append(['--revision', '%s@%s' % (name, fixed_revision)]) |
| 187 | 220 |
| 188 # Add extra fetch refspecs. | 221 # Add extra fetch refspecs. |
| 189 for ref in refs: | 222 for ref in refs: |
| 190 flags.append(['--refs', ref]) | 223 flags.append(['--refs', ref]) |
| 191 | 224 |
| 192 # Filter out flags that are None. | 225 # Filter out flags that are None. |
| 193 cmd = [item for flag_set in flags | 226 cmd = [item for flag_set in flags |
| 194 for item in flag_set if flag_set[1] is not None] | 227 for item in flag_set if flag_set[1] is not None] |
| 195 | 228 |
| 196 if clobber: | 229 if clobber: |
| 197 cmd.append('--clobber') | 230 cmd.append('--clobber') |
| 198 if force: | 231 if force: |
| 199 cmd.append('--force') | 232 cmd.append('--force') |
| 200 if no_shallow: | 233 if no_shallow: |
| 201 cmd.append('--no_shallow') | 234 cmd.append('--no_shallow') |
| 202 if output_manifest: | 235 if output_manifest: |
| 203 cmd.append('--output_manifest') | 236 cmd.append('--output_manifest') |
| 204 if with_branch_heads or cfg.with_branch_heads: | 237 if with_branch_heads or cfg.with_branch_heads: |
| 205 cmd.append('--with_branch_heads') | 238 cmd.append('--with_branch_heads') |
| 206 | 239 |
| 207 # Inject Json output for testing. | 240 # Inject Json output for testing. |
| 208 git_mode = self.m.properties.get('mastername') not in SVN_MASTERS | 241 git_mode = self._mastername not in SVN_MASTERS |
| 209 first_sln = cfg.solutions[0].name | 242 first_sln = cfg.solutions[0].name |
| 210 step_test_data = lambda: self.test_api.output_json( | 243 step_test_data = lambda: self.test_api.output_json( |
| 211 master, builder, slave, root, first_sln, rev_map, git_mode, force, | 244 master, builder, slave, root, first_sln, rev_map, git_mode, force, |
| 212 self.m.properties.get('fail_patch', False), | 245 self._fail_patch, |
| 213 output_manifest=output_manifest, fixed_revisions=fixed_revisions) | 246 output_manifest=output_manifest, fixed_revisions=fixed_revisions) |
| 214 | 247 |
| 215 # Add suffixes to the step name, if specified. | 248 # Add suffixes to the step name, if specified. |
| 216 name = 'bot_update' | 249 name = 'bot_update' |
| 217 if not patch: | 250 if not patch: |
| 218 name += ' (without patch)' | 251 name += ' (without patch)' |
| 219 if suffix: | 252 if suffix: |
| 220 name += ' - %s' % suffix | 253 name += ' - %s' % suffix |
| 221 | 254 |
| 222 # Ah hah! Now that everything is in place, lets run bot_update! | 255 # Ah hah! Now that everything is in place, lets run bot_update! |
| 223 try: | 256 try: |
| 224 # 87 and 88 are the 'patch failure' codes for patch download and patch | 257 # 87 and 88 are the 'patch failure' codes for patch download and patch |
| 225 # apply, respectively. We don't actually use the error codes, and instead | 258 # apply, respectively. We don't actually use the error codes, and instead |
| 226 # rely on emitted json to determine cause of failure. | 259 # rely on emitted json to determine cause of failure. |
| 227 self(name, cmd, step_test_data=step_test_data, | 260 self(name, cmd, step_test_data=step_test_data, |
| 228 ok_ret=(0, 87, 88), **kwargs) | 261 ok_ret=(0, 87, 88), **kwargs) |
| 229 finally: | 262 finally: |
| 230 step_result = self.m.step.active_result | 263 step_result = self.m.step.active_result |
| 231 self._properties = step_result.json.output.get('properties', {}) | 264 self._last_returned__properties = step_result.json.output.get('properties' , {}) |
| 232 | 265 |
| 233 if update_presentation: | 266 if update_presentation: |
| 234 # Set properties such as got_revision. | 267 # Set properties such as got_revision. |
| 235 for prop_name, prop_value in self.properties.iteritems(): | 268 for prop_name, prop_value in self.properties.iteritems(): |
| 236 step_result.presentation.properties[prop_name] = prop_value | 269 step_result.presentation.properties[prop_name] = prop_value |
| 237 # Add helpful step description in the step UI. | 270 # Add helpful step description in the step UI. |
| 238 if 'step_text' in step_result.json.output: | 271 if 'step_text' in step_result.json.output: |
| 239 step_text = step_result.json.output['step_text'] | 272 step_text = step_result.json.output['step_text'] |
| 240 step_result.presentation.step_text = step_text | 273 step_result.presentation.step_text = step_text |
| 241 # Add log line output. | 274 # Add log line output. |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 270 | 303 |
| 271 # bot_update actually just sets root to be the folder name of the | 304 # bot_update actually just sets root to be the folder name of the |
| 272 # first solution. | 305 # first solution. |
| 273 if step_result.json.output['did_run']: | 306 if step_result.json.output['did_run']: |
| 274 co_root = step_result.json.output['root'] | 307 co_root = step_result.json.output['root'] |
| 275 cwd = kwargs.get('cwd', self.m.path['slave_build']) | 308 cwd = kwargs.get('cwd', self.m.path['slave_build']) |
| 276 if 'checkout' not in self.m.path: | 309 if 'checkout' not in self.m.path: |
| 277 self.m.path['checkout'] = cwd.join(*co_root.split(self.m.path.sep)) | 310 self.m.path['checkout'] = cwd.join(*co_root.split(self.m.path.sep)) |
| 278 | 311 |
| 279 return step_result | 312 return step_result |
| OLD | NEW |