← Back to team overview

launchpad-reviewers team mailing list archive

Re: [Merge] ~ruinedyourlife/launchpad:add-sourcecraft-yaml-parser into launchpad:master

 

I am not really happy about manually maintaining a list of distroseries - let's have a chat before merging.

Diff comments:

> diff --git a/lib/lp/crafts/adapters/buildarch.py b/lib/lp/crafts/adapters/buildarch.py
> new file mode 100644
> index 0000000..3f1ffde
> --- /dev/null
> +++ b/lib/lp/crafts/adapters/buildarch.py
> @@ -0,0 +1,127 @@
> +# Copyright 2024 Canonical Ltd.  This software is licensed under the
> +# GNU Affero General Public License version 3 (see the file LICENSE).
> +
> +__all__ = [
> +    "determine_instances_to_build",
> +]
> +
> +from collections import OrderedDict

OrderedDicts are not longer necessary since Python 3.6/3.7, as insertion order is stable since then - and yes, you adapted that from my code :-)

> +
> +
> +class CraftBasesParserError(Exception):
> +    """Base class for all exceptions in this module."""
> +
> +
> +class MissingPropertyError(CraftBasesParserError):
> +    """Error for when an expected property is not present in the YAML."""
> +
> +    def __init__(self, prop, msg=None):
> +        if msg is None:
> +            msg = f"Craft specification is missing the {prop!r} property"
> +        super().__init__(msg)
> +        self.property = prop
> +
> +
> +class BadPropertyError(CraftBasesParserError):
> +    """Error for when a YAML property is malformed in some way."""
> +
> +
> +class CraftBase:
> +    """A single base in sourcecraft.yaml."""
> +
> +    VALID_BASES = {"ubuntu@20.04", "ubuntu@22.04", "ubuntu@24.04", "bare"}

This means, every time a new LTS gets released, we need to think to update that code here. I am not entirely sure, but I think if you tried to schedule a build for ubuntu@30.04 right now, this would error out automatically.

For rocks we use something like this..

```
        results = store.using(*origin).find(
            (DistroArchSeries, DistroSeries, Distribution),
            DistroSeries.status.is_in(ACTIVE_STATUSES),
        )
        all_buildable_dases = DecoratedResultSet(results, itemgetter(0))
```

> +    VALID_BUILD_BASES = VALID_BASES | {"devel"}
> +
> +    def __init__(self, base_string, is_build_base=False):
> +        if is_build_base:
> +            if base_string not in self.VALID_BUILD_BASES:
> +                raise BadPropertyError(
> +                    f"Invalid build-base: {base_string!r}. "
> +                    f"Must be one of "
> +                    f"{', '.join(sorted(self.VALID_BUILD_BASES))}"
> +                )
> +        else:
> +            if base_string not in self.VALID_BASES:
> +                raise BadPropertyError(
> +                    f"Invalid base: {base_string!r}. "
> +                    f"Must be one of {', '.join(sorted(self.VALID_BASES))}"
> +                )
> +
> +        self.base_string = base_string
> +        if base_string == "bare":
> +            self.name = "bare"
> +            self.channel = None
> +        elif base_string == "devel":
> +            raise BadPropertyError("The 'devel' base is not supported for now")
> +        else:
> +            self.name, self.channel = base_string.split("@")
> +
> +    def __eq__(self, other):
> +        if not isinstance(other, CraftBase):
> +            return NotImplemented
> +        return self.name == other.name and self.channel == other.channel
> +
> +    def __hash__(self):
> +        return hash((self.name, self.channel))
> +
> +    def __str__(self):
> +        return f"{self.name}@{self.channel}"
> +
> +
> +def determine_instances_to_build(
> +    sourcecraft_data, supported_arches, default_distro_series
> +):
> +    """Return a list of instances to build based on sourcecraft.yaml.
> +
> +    :param sourcecraft_data: A parsed sourcecraft.yaml.
> +    :param supported_arches: An ordered list of all `DistroArchSeries` that
> +        we can create builds for. Note that these may span multiple
> +        `DistroSeries`.
> +    :param default_distro_series: The default `DistroSeries` to use if
> +        sourcecraft.yaml does not explicitly declare a base.
> +    :return: A list of `DistroArchSeries`.
> +    """
> +    base = sourcecraft_data.get("base")
> +    if not base:
> +        raise MissingPropertyError("base")
> +
> +    craft_base = CraftBase(base)
> +
> +    if craft_base.base_string == "bare":
> +        build_base = sourcecraft_data.get("build-base")
> +        if not build_base:
> +            raise MissingPropertyError(
> +                "build-base",
> +                "When 'base' is 'bare', 'build-base' must be specified",
> +            )
> +        craft_base = CraftBase(build_base, is_build_base=True)
> +    elif "build-base" in sourcecraft_data:
> +        craft_base = CraftBase(
> +            sourcecraft_data["build-base"], is_build_base=True
> +        )
> +
> +    platforms = sourcecraft_data.get("platforms")
> +    if not platforms:
> +        raise MissingPropertyError("platforms")
> +
> +    instances = OrderedDict()
> +    for platform, config in platforms.items():
> +        build_on = config.get("build-on", [platform])
> +        build_for = config.get("build-for", [platform])
> +
> +        if isinstance(build_on, str):
> +            build_on = [build_on]
> +        if isinstance(build_for, str):
> +            build_for = [build_for]
> +
> +        for arch in build_on:
> +            for das in supported_arches:
> +                if (
> +                    das.distroseries.distribution.name == craft_base.name
> +                    and das.distroseries.version == craft_base.channel
> +                    and das.architecturetag == arch
> +                ):
> +                    instances[das] = None
> +                    break
> +
> +    return list(instances)


-- 
https://code.launchpad.net/~ruinedyourlife/launchpad/+git/launchpad/+merge/474016
Your team Launchpad code reviewers is requested to review the proposed merge of ~ruinedyourlife/launchpad:add-sourcecraft-yaml-parser into launchpad:master.



References