| # Copyright 2024 The Pigweed Authors |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| # use this file except in compliance with the License. You may obtain a copy of |
| # the License at |
| # |
| # https://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| # License for the specific language governing permissions and limitations under |
| # the License. |
| |
| from __future__ import annotations |
| |
| import configparser |
| import dataclasses |
| import io |
| import re |
| from typing import TYPE_CHECKING |
| |
| from PB.recipe_modules.pigweed.checkout.options import ( |
| Options as CheckoutOptions, |
| ) |
| from recipe_engine import recipe_api |
| |
| if TYPE_CHECKING: # pragma: no cover |
| from typing import Generator |
| from PB.recipe_modules.pigweed.txt_roll.txt_entry import TxtEntry |
| from RECIPE_MODULES.pigweed.checkout import api as checkout_api |
| from RECIPE_MODULES.pigweed.roll_util import api as roll_util_api |
| |
| |
| class TxtRollApi(recipe_api.RecipeApi): |
| |
| def update( |
| self, |
| checkout: checkout_api.CheckoutContext, |
| txt_entry: TxtEntry, |
| ) -> dict[str, roll_util_api.Roll] | None: |
| branch = txt_entry.branch or 'main' |
| |
| new_revision: Optional[str] = None |
| |
| # First, try to get new_revision from the trigger. |
| bb_remote: Optional[str] = None |
| commit = self.m.buildbucket.build.input.gitiles_commit |
| if commit and commit.project: |
| new_revision = commit.id |
| host = commit.host |
| bb_remote = f'https://{host}/{commit.project}' |
| |
| # If we still don't have a revision then it wasn't in the trigger. |
| # (Perhaps this was manually triggered.) In this case we update to the |
| # property-specified branch HEAD. |
| if new_revision is None: |
| new_revision = branch |
| |
| # If this was triggered by a gitiles poller, check that the triggering |
| # repository matches project_remote. |
| |
| if bb_remote: |
| if not checkout.remotes_equivalent(txt_entry.remote, bb_remote): |
| raise self.m.step.StepFailure( |
| 'triggering repository ({}) does not match project remote ' |
| '({})'.format(bb_remote, txt_entry.remote) |
| ) |
| |
| project_dir = self.m.path.start_dir / 'project' |
| |
| project_checkout = self.m.checkout( |
| CheckoutOptions( |
| remote=txt_entry.remote, |
| branch=branch, |
| use_trigger=True, |
| ), |
| root=project_dir, |
| ) |
| |
| # In case new_revision is a branch name we need to retrieve the hash it |
| # resolves to. |
| if not re.search(r'^[0-9a-f]{40}$', new_revision): |
| new_revision = self.m.checkout.get_revision( |
| project_dir, 'get new revision', test_data='2' * 40 |
| ) |
| |
| full_txt_path = checkout.root / txt_entry.path |
| |
| old_revision = self.m.file.read_text( |
| 'read old revision', |
| full_txt_path, |
| test_data='1' * 40, |
| ).strip() |
| |
| self.m.file.write_text( |
| 'write new revision', full_txt_path, f'{new_revision}\n' |
| ) |
| |
| direction = self.m.roll_util.get_roll_direction( |
| project_dir, old_revision, new_revision |
| ) |
| |
| # If the primary roll is not necessary or is backwards we can exit |
| # immediately. |
| if not self.m.roll_util.can_roll(direction): |
| self.m.roll_util.skip_roll_step( |
| txt_entry.remote, |
| old_revision, |
| new_revision, |
| ) |
| return |
| |
| with self.m.step.nest('txt_path') as pres: |
| pres.step_summary_text = repr(txt_entry.path) |
| |
| return { |
| txt_entry.path: self.m.roll_util.create_roll( |
| project_name=txt_entry.path, |
| old_revision=old_revision, |
| new_revision=new_revision, |
| proj_dir=project_dir, |
| direction=direction, |
| ), |
| } |