Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # Copyright 2013 The Chromium Authors. All rights reserved. | 1 # Copyright 2013 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 import cgi | 5 import cgi |
| 6 import re | 6 import re |
| 7 | 7 |
| 8 from recipe_engine import recipe_api | 8 from recipe_engine import recipe_api |
| 9 | 9 |
| 10 | 10 |
| 11 class ChromiteApi(recipe_api.RecipeApi): | 11 class ChromiteApi(recipe_api.RecipeApi): |
| 12 chromite_url = 'https://chromium.googlesource.com/chromiumos/chromite.git' | 12 chromite_url = 'https://chromium.googlesource.com/chromiumos/chromite.git' |
| 13 manifest_url = 'https://chromium.googlesource.com/chromiumos/manifest.git' | 13 manifest_url = 'https://chromium.googlesource.com/chromiumos/manifest.git' |
| 14 repo_url = 'https://chromium.googlesource.com/external/repo.git' | 14 repo_url = 'https://chromium.googlesource.com/external/repo.git' |
| 15 chromite_subpath = 'chromite' | 15 chromite_subpath = 'chromite' |
| 16 | 16 |
| 17 # The number of Gitiles attempts to make before giving up. | 17 # The number of Gitiles attempts to make before giving up. |
| 18 _GITILES_ATTEMPTS = 10 | 18 _GITILES_ATTEMPTS = 10 |
| 19 | 19 |
| 20 _MANIFEST_CMD_RE = re.compile(r'Automatic:\s+Start\s+([^\s]+)\s+([^\s]+)') | 20 _MANIFEST_CMD_RE = re.compile(r'Automatic:\s+Start\s+([^\s]+)\s+([^\s]+)') |
| 21 _BUILD_ID_RE = re.compile(r'CrOS-Build-Id: (.+)') | 21 _BUILD_ID_RE = re.compile(r'CrOS-Build-Id: (.+)') |
| 22 | 22 |
| 23 def get_config_defaults(self): | |
| 24 build_number = self.m.properties.get('buildnumber') | |
| 25 if build_number is not None: | |
| 26 # On a developer system, it's been noted that when the build number is | |
| 27 # zero, it's passed as an empty string in the properties JSON blob. | |
|
luqui
2015/07/31 19:58:15
The purpose of this comment is unclear. So this l
dnj (Google)
2015/08/01 01:31:34
Filed https://code.google.com/p/chromium/issues/de
| |
| 28 build_number = int(build_number or 0) | |
| 29 | |
| 30 return { | |
| 31 'CBB_CONFIG': self.m.properties.get('cbb_config'), | |
| 32 'CBB_BRANCH': self.m.properties.get('cbb_branch'), | |
| 33 'CBB_BUILD_NUMBER': build_number, | |
| 34 'CBB_DEBUG': self.m.properties.get('cbb_debug') is not None, | |
| 35 'CBB_CLOBBER': 'clobber' in self.m.properties, | |
| 36 } | |
| 37 | |
| 23 def check_repository(self, repo_type_key, value): | 38 def check_repository(self, repo_type_key, value): |
| 24 """Scans through registered repositories for a specified value. | 39 """Scans through registered repositories for a specified value. |
| 25 | 40 |
| 26 Args: | 41 Args: |
| 27 repo_type_key (str): The key in the 'repositories' config to scan through. | 42 repo_type_key (str): The key in the 'repositories' config to scan through. |
| 28 value (str): The value to scan for. | 43 value (str): The value to scan for. |
| 29 Returns (bool): True if the value was found. | 44 Returns (bool): True if the value was found. |
| 30 """ | 45 """ |
| 31 def remove_tail(v, tail): | 46 def remove_tail(v, tail): |
| 32 if v.endswith(tail): | 47 if v.endswith(tail): |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 114 # Build ID? | 129 # Build ID? |
| 115 match = self._BUILD_ID_RE.match(line) | 130 match = self._BUILD_ID_RE.match(line) |
| 116 if match: | 131 if match: |
| 117 self.c.cbb.build_id = match.group(1) | 132 self.c.cbb.build_id = match.group(1) |
| 118 loaded.append('Build ID: %s' % (self.c.cbb.build_id,)) | 133 loaded.append('Build ID: %s' % (self.c.cbb.build_id,)) |
| 119 continue | 134 continue |
| 120 if loaded: | 135 if loaded: |
| 121 loaded.insert(0, '') | 136 loaded.insert(0, '') |
| 122 result.presentation.step_text += '<br/>'.join(loaded) | 137 result.presentation.step_text += '<br/>'.join(loaded) |
| 123 | 138 |
| 139 @property | |
| 124 def default_chromite_path(self): | 140 def default_chromite_path(self): |
| 125 """Returns: (Path) The default Chromite checkout path.""" | 141 """Returns: (Path) The default Chromite checkout path.""" |
| 126 return self.m.path['slave_build'].join(self.chromite_subpath) | 142 return self.m.path['slave_build'].join(self.chromite_subpath) |
| 127 | 143 |
| 128 def gclient_config(self): | 144 def gclient_config(self): |
| 129 """Generate a 'gclient' configuration to check out Chromite. | 145 """Generate a 'gclient' configuration to check out Chromite. |
| 130 | 146 |
| 131 Return: (config) A 'gclient' recipe module configuration. | 147 Return: (config) A 'gclient' recipe module configuration. |
| 132 """ | 148 """ |
| 133 cfg = self.m.gclient.make_config() | 149 cfg = self.m.gclient.make_config() |
| 134 soln = cfg.solutions.add() | 150 soln = cfg.solutions.add() |
| 135 soln.name = 'chromite' | 151 soln.name = 'chromite' |
| 136 soln.url = self.chromite_url | 152 soln.url = self.chromite_url |
| 137 # Set the revision using 'bot_update' remote branch:revision notation. | 153 # Set the revision using 'bot_update' remote branch:revision notation. |
| 138 # Omitting the revision uses HEAD. | 154 # Omitting the revision uses HEAD. |
| 139 soln.revision = '%s:' % (self.c.chromite_branch,) | 155 soln.revision = '%s:' % (self.c.chromite_branch,) |
| 140 return cfg | 156 return cfg |
| 141 | 157 |
| 142 def checkout(self, manifest_url=None, repo_url=None): | 158 def checkout(self, manifest_url=None, repo_url=None): |
| 143 manifest_url = manifest_url or self.manifest_url | 159 manifest_url = manifest_url or self.manifest_url |
| 144 repo_url = repo_url or self.repo_url | 160 repo_url = repo_url or self.repo_url |
| 145 | 161 |
| 146 self.m.repo.init(manifest_url, '--repo-url', repo_url) | 162 self.m.repo.init(manifest_url, '--repo-url', repo_url) |
| 147 self.m.repo.sync() | 163 self.m.repo.sync() |
| 148 | 164 |
| 165 @property | |
| 166 def old_chromite_layout(self): | |
|
luqui
2015/07/31 19:58:15
How about using_old_chromite_layout. This naming
dnj (Google)
2015/08/01 01:31:34
Done.
| |
| 167 """Returns (bool): True if we're using old Chromite checkout layout. | |
| 168 """ | |
| 169 return self.c.chromite_branch in self.c.old_chromite_branches | |
| 170 | |
| 149 def cbuildbot(self, name, config, args=None, chromite_path=None, **kwargs): | 171 def cbuildbot(self, name, config, args=None, chromite_path=None, **kwargs): |
| 150 """Runs the cbuildbot command defined by the arguments. | 172 """Runs the cbuildbot command defined by the arguments. |
| 151 | 173 |
| 152 Args: | 174 Args: |
| 153 name: (str) The name of the command step. | 175 name: (str) The name of the command step. |
| 154 config: (str) The name of the 'cbuildbot' configuration to invoke. | 176 config: (str) The name of the 'cbuildbot' configuration to invoke. |
| 155 args: (list) If not None, addition arguments to pass to 'cbuildbot'. | 177 args: (list) If not None, addition arguments to pass to 'cbuildbot'. |
| 156 chromite_path: (str) The path to the Chromite checkout; if None, the | 178 chromite_path: (str) The path to the Chromite checkout; if None, the |
| 157 'default_chromite_path()' will be used. | 179 'default_chromite_path' will be used. |
| 158 | 180 |
| 159 Returns: (Step) The step that was run. | 181 Returns: (Step) The step that was run. |
| 160 """ | 182 """ |
| 161 chromite_path = chromite_path or self.default_chromite_path() | 183 chromite_path = chromite_path or self.default_chromite_path |
| 162 args = (args or [])[:] | 184 args = (args or [])[:] |
| 163 args.append(config) | 185 args.append(config) |
| 164 | 186 |
| 165 cmd = [self.m.path.join(chromite_path, 'bin', 'cbuildbot')] + args | 187 bindir = ('bin' if not self.old_chromite_layout else 'buildbot') |
|
luqui
2015/07/31 19:58:15
This is convoluted to read. I see what you're goi
dnj (Google)
2015/08/01 01:31:34
Agreed this is more readable. Stylistically I like
| |
| 166 | 188 cmd = [self.m.path.join(chromite_path, bindir, 'cbuildbot')] + args |
| 167 # TODO(petermayo): Wrap this nested annotation in a stabilizing wrapper. | |
| 168 return self.m.step(name, cmd, allow_subannotations=True, **kwargs) | 189 return self.m.step(name, cmd, allow_subannotations=True, **kwargs) |
| 169 | 190 |
| 170 def cros_sdk(self, name, cmd, args=None, environ=None, chromite_path=None, | 191 def cros_sdk(self, name, cmd, args=None, environ=None, chromite_path=None, |
| 171 **kwargs): | 192 **kwargs): |
| 172 """Return a step to run a command inside the cros_sdk.""" | 193 """Return a step to run a command inside the cros_sdk.""" |
| 173 chromite_path = chromite_path or self.default_chromite_path() | 194 chromite_path = chromite_path or self.default_chromite_path |
| 174 | 195 |
| 175 chroot_cmd = self.m.path.join(chromite_path, 'bin', 'cros_sdk') | 196 chroot_cmd = self.m.path.join(chromite_path, 'bin', 'cros_sdk') |
| 176 | 197 |
| 177 arg_list = (args or [])[:] | 198 arg_list = (args or [])[:] |
| 178 for t in sorted((environ or {}).items()): | 199 for t in sorted((environ or {}).items()): |
| 179 arg_list.append('%s=%s' % t) | 200 arg_list.append('%s=%s' % t) |
| 180 arg_list.append('--') | 201 arg_list.append('--') |
| 181 arg_list.extend(cmd) | 202 arg_list.extend(cmd) |
| 182 | 203 |
| 183 self.m.python(name, chroot_cmd, arg_list, **kwargs) | 204 self.m.python(name, chroot_cmd, arg_list, **kwargs) |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 209 master_config = config_map.get('master_config') | 230 master_config = config_map.get('master_config') |
| 210 assert master_config, ( | 231 assert master_config, ( |
| 211 "No 'master_config' configuration for '%s'" % (master,)) | 232 "No 'master_config' configuration for '%s'" % (master,)) |
| 212 self.set_config(master_config) | 233 self.set_config(master_config) |
| 213 | 234 |
| 214 # Apply any variant configurations. | 235 # Apply any variant configurations. |
| 215 if variant: | 236 if variant: |
| 216 for config_name in config_map.get('variants', {}).get(variant, ()): | 237 for config_name in config_map.get('variants', {}).get(variant, ()): |
| 217 self.apply_config(config_name) | 238 self.apply_config(config_name) |
| 218 | 239 |
| 219 # If a Chromite branch is supplied, use it to override the default Chromite | |
| 220 # checkout revision. | |
| 221 if properties.get('cbb_branch'): | |
| 222 self.c.chromite_branch = properties['cbb_branch'] | |
| 223 | |
| 224 # Set the build number if one is defined in the properties. | |
| 225 if self.m.properties.get('buildnumber') is not None: | |
| 226 # On a developer system, it's been noted that when the build number is | |
| 227 # zero, it's passed as an empty string in the properties JSON blob. | |
| 228 self.c.cbb.build_number = int(self.m.properties['buildnumber'] or 0) | |
| 229 | |
| 230 # Run a debug build if instructed. | |
| 231 if properties.get('cbb_debug'): | |
| 232 self.c.cbb.debug = True | |
| 233 | |
| 234 # If a clobber build was requested, set this builder to clobber. | |
| 235 if 'clobber' in properties: | |
| 236 self.c.cbb.clobber = True | |
| 237 | 240 |
| 238 # If a config repo was specified, use it. | 241 # If a config repo was specified, use it. |
| 239 if 'config_repo' in properties: | 242 if 'config_repo' in properties: |
| 240 self.c.cbb.config_repo = self.m.properties['config_repo'] | 243 self.c.cbb.config_repo = self.m.properties['config_repo'] |
| 241 | 244 |
| 242 def run_cbuildbot(self, config, tryjob=False): | 245 def run_cbuildbot(self, tryjob=False): |
| 243 """Runs a 'cbuildbot' checkout-and-build workflow. | 246 """Runs a 'cbuildbot' checkout-and-build workflow. |
| 244 | 247 |
| 245 This workflow uses the registered configuration dictionary to make master- | 248 This workflow uses the registered configuration dictionary to make master- |
| 246 and builder-specific changes to the standard workflow. | 249 and builder-specific changes to the standard workflow. |
| 247 | 250 |
| 248 The specific workflow paths that are taken are also influenced by several | 251 The specific workflow paths that are taken are also influenced by several |
| 249 build properties. | 252 build properties. |
| 250 | 253 |
| 251 TODO(dnj): When CrOS migrates away from BuildBot, replace property | 254 TODO(dnj): When CrOS migrates away from BuildBot, replace property |
| 252 inferences with command-line parameters. | 255 inferences with command-line parameters. |
| 253 | 256 |
| 254 This workflow: | 257 This workflow: |
| 255 - Checks out the specified 'cbuildbot' repository. | 258 - Checks out the specified 'cbuildbot' repository. |
| 256 - Pulls information based on the configured change's repository/revision | 259 - Pulls information based on the configured change's repository/revision |
| 257 to pass to 'cbuildbot'. | 260 to pass to 'cbuildbot'. |
| 258 - Executes the 'cbuildbot' command. | 261 - Executes the 'cbuildbot' command. |
| 259 | 262 |
| 260 Args: | 263 Args: |
| 261 config (str): The name of the 'cbuildbot' configuration target to build. | |
| 262 tryjob (bool): If True, load a tryjob description from the source | 264 tryjob (bool): If True, load a tryjob description from the source |
| 263 repository and augment the cbuildbot command-line with it. | 265 repository and augment the cbuildbot command-line with it. |
| 264 Returns: (Step) the 'cbuildbot' execution step. | 266 Returns: (Step) the 'cbuildbot' execution step. |
| 265 """ | 267 """ |
| 266 | 268 |
| 267 # Assert correct configuration. | 269 # Assert correct configuration. |
| 268 assert config, 'An empty configuration was specified.' | |
| 269 assert self.c.cbb.builddir, 'A build directory name must be specified.' | 270 assert self.c.cbb.builddir, 'A build directory name must be specified.' |
| 270 | 271 |
| 271 # Load properties from the commit being processed. This requires both a | 272 # Load properties from the commit being processed. This requires both a |
| 272 # repository and revision to proceed. | 273 # repository and revision to proceed. |
| 273 repository = self.m.properties.get('repository') | 274 repository = self.m.properties.get('repository') |
| 274 revision = self.m.properties.get('revision') | 275 revision = self.m.properties.get('revision') |
| 275 tryjob_args = [] | 276 tryjob_args = [] |
| 276 if repository and revision: | 277 if repository and revision: |
| 277 if tryjob: | 278 if tryjob: |
| 278 assert self.check_repository('tryjob', repository), ( | 279 assert self.check_repository('tryjob', repository), ( |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 321 # Add tryjob args, if there are any. | 322 # Add tryjob args, if there are any. |
| 322 cbb_args.extend(tryjob_args) | 323 cbb_args.extend(tryjob_args) |
| 323 | 324 |
| 324 # Checkout Chromite. | 325 # Checkout Chromite. |
| 325 self.m.bot_update.ensure_checkout( | 326 self.m.bot_update.ensure_checkout( |
| 326 gclient_config=self.gclient_config(), | 327 gclient_config=self.gclient_config(), |
| 327 update_presentation=False, | 328 update_presentation=False, |
| 328 force=True) | 329 force=True) |
| 329 | 330 |
| 330 # Run cbuildbot. | 331 # Run cbuildbot. |
| 331 return self.cbuildbot(str('cbuildbot [%s]' % (config,)), | 332 return self.cbuildbot(str('cbuildbot [%s]' % (self.c.cbb.config,)), |
| 332 config, | 333 self.c.cbb.config, |
| 333 args=cbb_args, | 334 args=cbb_args, |
| 334 chromite_path=self.m.path['checkout'], | 335 chromite_path=self.m.path['checkout'], |
| 335 cwd=self.m.path['slave_root']) | 336 cwd=self.m.path['slave_root']) |
| OLD | NEW |