| OLD | NEW |
| 1 # Copyright 2016 The Chromium Authors. All rights reserved. | 1 # Copyright 2016 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 collections | 5 import collections |
| 6 import hashlib | 6 import hashlib |
| 7 import json | 7 import json |
| 8 import re | 8 import re |
| 9 | 9 |
| 10 from recipe_engine import recipe_api | 10 from recipe_engine import recipe_api |
| 11 | 11 |
| 12 RECIPE_TRYJOB_BYPASS_REASON_TAG = "Recipe-Tryjob-Bypass-Reason" | 12 RECIPE_TRYJOB_BYPASS_REASON_TAG = "Recipe-Tryjob-Bypass-Reason" |
| 13 | 13 |
| 14 #TODO(martiniss): make the recipe engine be able to dump the package as JSON so | |
| 15 # we don't have to do this weird parsing. | |
| 16 def parse_protobuf(lines): | |
| 17 """Parse the protobuf text format just well enough to understand recipes.cfg. | |
| 18 | |
| 19 We don't use the protobuf library because we want to be as self-contained | |
| 20 as possible in this bootstrap, so it can be simply vendored into a client | |
| 21 repo. | |
| 22 | |
| 23 We assume all fields are repeated since we don't have a proto spec to work | |
| 24 with. | |
| 25 | |
| 26 Args: | |
| 27 lines: a list of the lines to parse | |
| 28 Returns: | |
| 29 A recursive dictionary of lists. | |
| 30 """ | |
| 31 def parse_atom(text): | |
| 32 # NOTE: Assuming we only have numbers and strings to avoid using | |
| 33 # ast.literal_eval | |
| 34 try: | |
| 35 return int(text) | |
| 36 except ValueError: | |
| 37 return text.strip("'").strip('"') | |
| 38 | |
| 39 ret = {} | |
| 40 while lines: | |
| 41 line = lines.pop(0).strip() | |
| 42 | |
| 43 m = re.match(r'(\w+)\s*:\s*(.*)', line) | |
| 44 if m: | |
| 45 ret.setdefault(m.group(1), []).append(parse_atom(m.group(2))) | |
| 46 continue | |
| 47 | |
| 48 m = re.match(r'(\w+)\s*{', line) | |
| 49 if m: | |
| 50 subparse = parse_protobuf(lines) | |
| 51 ret.setdefault(m.group(1), []).append(subparse) | |
| 52 continue | |
| 53 | |
| 54 if line == '}': | |
| 55 return ret | |
| 56 if line == '': | |
| 57 continue | |
| 58 | |
| 59 raise ValueError('Could not understand line: <%s>' % line)# pragma: no cover | |
| 60 return ret | |
| 61 | |
| 62 def get_recipes_path(project_config): | 14 def get_recipes_path(project_config): |
| 63 # Returns a tuple of the path components to traverse from the root of the repo | 15 # Returns a tuple of the path components to traverse from the root of the repo |
| 64 # to get to the directory containing recipes. | 16 # to get to the directory containing recipes. |
| 65 return project_config['recipes_path'][0].split('/') | 17 return project_config['recipes_path'][0].split('/') |
| 66 | 18 |
| 67 | 19 |
| 68 def get_deps(project_config): | 20 def get_deps(project_config): |
| 69 """ Get the recipe engine deps of a project from its recipes.cfg file. """ | 21 """ Get the recipe engine deps of a project from its recipes.cfg file. """ |
| 70 # "[0]" Since parsing makes every field a list | 22 # "[0]" Since parsing makes every field a list |
| 71 return [dep['project_id'][0] for dep in project_config.get('deps', [])] | 23 return [dep['project_id'][0] for dep in project_config.get('deps', [])] |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 144 """ | 96 """ |
| 145 This is intended as a utility module for recipe tryjobs. Currently it's just a | 97 This is intended as a utility module for recipe tryjobs. Currently it's just a |
| 146 refactored version of a recipe; eventually some of this, especially the | 98 refactored version of a recipe; eventually some of this, especially the |
| 147 dependency information, will probably get moved into the recipe engine. | 99 dependency information, will probably get moved into the recipe engine. |
| 148 """ | 100 """ |
| 149 def _get_project_config(self, project): | 101 def _get_project_config(self, project): |
| 150 """Fetch the project config from luci-config. | 102 """Fetch the project config from luci-config. |
| 151 | 103 |
| 152 Args: | 104 Args: |
| 153 project: The name of the project in luci-config. | 105 project: The name of the project in luci-config. |
| 154 auth_token: Authentication token to use when talking to luci-config. | |
| 155 | 106 |
| 156 Returns: | 107 Returns: |
| 157 The recipes.cfg file for that project, as a parsed dictionary. See | 108 The recipes.cfg file for that project, as a parsed dictionary. See |
| 158 parse_protobuf for details on the format to expect. | 109 parse_protobuf for details on the format to expect. |
| 159 """ | 110 """ |
| 160 result = self.m.luci_config.get_project_config(project, 'recipes.cfg') | 111 result = self.m.luci_config.get_project_config(project, 'recipes.cfg') |
| 161 | 112 |
| 162 parsed = parse_protobuf(result['content'].split('\n')) | 113 parsed = self.m.luci_config.parse_textproto(result['content'].split('\n')) |
| 163 return parsed | 114 return parsed |
| 164 | 115 |
| 165 def _checkout_projects(self, root_dir, url_mapping, deps, | 116 def _checkout_projects(self, root_dir, url_mapping, deps, |
| 166 downstream_projects, patches): | 117 downstream_projects, patches): |
| 167 """Checks out projects listed in projects into root_dir. | 118 """Checks out projects listed in projects into root_dir. |
| 168 | 119 |
| 169 Args: | 120 Args: |
| 170 root_dir: Root directory to check this project out in. | 121 root_dir: Root directory to check this project out in. |
| 171 url_mapping: Project id to url of git repository. | 122 url_mapping: Project id to url of git repository. |
| 172 downstream_projects: The mapping from project to dependent projects. | 123 downstream_projects: The mapping from project to dependent projects. |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 339 except recipe_api.StepFailure: | 290 except recipe_api.StepFailure: |
| 340 if should_fail_build_mapping.get(proj, True): | 291 if should_fail_build_mapping.get(proj, True): |
| 341 bad_projects.append(proj) | 292 bad_projects.append(proj) |
| 342 | 293 |
| 343 if bad_projects: | 294 if bad_projects: |
| 344 raise recipe_api.StepFailure( | 295 raise recipe_api.StepFailure( |
| 345 "One or more projects failed tests: %s" % ( | 296 "One or more projects failed tests: %s" % ( |
| 346 ','.join(bad_projects))) | 297 ','.join(bad_projects))) |
| 347 | 298 |
| 348 | 299 |
| OLD | NEW |