blob: 932853f890fac69f6c722567825f4cd79076a111 [file] [edit]
# Copyright 2026 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.
"""API for loading workflow configurations."""
from __future__ import annotations
import json
import tomllib
from typing import Any
from google.protobuf import json_format
from recipe_engine import config_types, recipe_api
from PB.pigweed.pw_build.proto import build_driver as build_driver_pb
from PB.pigweed.pw_build.proto import (
pigweed_build_driver as pigweed_build_driver_pb,
)
from PB.pigweed.pw_build.proto import workflows as workflows_pb
_PROTO_MODULES = (
build_driver_pb,
pigweed_build_driver_pb,
workflows_pb,
)
_CANDIDATES = (
'workflows.textproto',
'workflows.json',
'workflows.yaml',
'workflows.toml',
)
class NoWorkflowFileFound(recipe_api.StepFailure):
pass
class TooManyWorkflowFilesFound(recipe_api.StepFailure):
pass
class WorkflowsApi(recipe_api.RecipeApi):
"""API for loading workflow configurations."""
NoWorkflowFileFound = NoWorkflowFileFound
TooManyWorkflowFilesFound = TooManyWorkflowFilesFound
def load(
self, directory: config_types.Path | None = None
) -> workflows_pb.WorkflowSuite:
"""Loads a WorkflowSuite message from a workflow file in directory."""
_ = _PROTO_MODULES
if directory is None:
directory = self.m.context.cwd or (self.m.path.start_dir / 'co')
found_files: list[config_types.Path] = []
for filename in _CANDIDATES:
path = directory / filename
if self.m.path.exists(path):
found_files.append(path)
if not found_files:
raise NoWorkflowFileFound(f'no workflow file in {directory}')
if len(found_files) > 1:
raise TooManyWorkflowFilesFound(
f'expected exactly one workflow file in {directory}, '
f'found {", ".join(str(f) for f in found_files)}'
)
target_file = found_files[0]
filename = target_file.name
if filename == 'workflows.textproto':
content: str = self.m.file.read_text(
f'read {filename}',
target_file,
test_data='',
)
return self.m.proto.decode(
content,
workflows_pb.WorkflowSuite,
self.m.proto.TEXTPB,
)
data: dict[str, Any] = {}
if filename == 'workflows.yaml':
data = self.m.yaml.read_file(
f'read {filename}',
target_file,
test_data={},
)
else:
content = self.m.file.read_text(
f'read {filename}',
target_file,
test_data='{}',
)
if filename == 'workflows.json':
data = json.loads(content)
elif filename == 'workflows.toml':
data = tomllib.loads(content)
else:
raise ValueError(
f'unsupported filename: {filename}'
) # pragma: no cover
return json_format.ParseDict(data, workflows_pb.WorkflowSuite())