Skip to content

Commit

Permalink
feat!(plugins): make PluginProperties more complete
Browse files Browse the repository at this point in the history
This does several things:

- Merges PluginProperties and PluginPropertiesModel
- Makes PluginProperties.unmarshal() work for most plugins be default
- Makes PluginProperties.marshal() fully dump json-able objects
- Adds a `plugin` field to all plugins, providing their names.
  • Loading branch information
lengau committed Jul 10, 2024
1 parent 257af9f commit ff77dd9
Show file tree
Hide file tree
Showing 23 changed files with 111 additions and 320 deletions.
2 changes: 1 addition & 1 deletion craft_parts/plugins/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@

from .base import Plugin, extract_plugin_properties
from .plugins import (
PluginProperties,
extract_part_properties,
get_plugin,
get_plugin_class,
Expand All @@ -27,6 +26,7 @@
unregister,
unregister_all,
)
from .properties import PluginProperties
from .validator import PluginEnvironmentValidator

__all__ = [
Expand Down
23 changes: 4 additions & 19 deletions craft_parts/plugins/ant_plugin.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
#
# Copyright 2022 Canonical Ltd.
# Copyright 2022,2024 Canonical Ltd.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
Expand All @@ -20,7 +20,7 @@
import os
import shlex
from collections.abc import Iterator
from typing import Any, cast
from typing import Any, Literal, cast
from urllib.parse import urlsplit

from overrides import override
Expand All @@ -34,31 +34,16 @@
logger = logging.getLogger(__name__)


class AntPluginProperties(PluginProperties):
class AntPluginProperties(PluginProperties, frozen=True):
"""The part properties used by the Ant plugin."""
plugin: Literal["ant"] = "ant"

ant_build_targets: list[str] = []
ant_build_file: str | None = None
ant_properties: dict[str, str] = {}

source: str

@classmethod
@override
def unmarshal(cls, data: dict[str, Any]) -> "AntPluginProperties":
"""Populate make properties from the part specification.
:param data: A dictionary containing part properties.
:return: The populated plugin properties data object.
:raise pydantic.ValidationError: If validation fails.
"""
plugin_data = extract_plugin_properties(
data, plugin_name="ant", required=["source"]
)
return cls(**plugin_data)


class AntPluginEnvironmentValidator(validator.PluginEnvironmentValidator):
"""Check the execution environment for the Ant plugin.
Expand Down
23 changes: 4 additions & 19 deletions craft_parts/plugins/autotools_plugin.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
#
# Copyright 2020 Canonical Ltd.
# Copyright 2020,2024 Canonical Ltd.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
Expand All @@ -16,39 +16,24 @@

"""The autotools plugin implementation."""

from typing import Any, cast
from typing import Any, Literal, cast

from overrides import override

from .base import Plugin, extract_plugin_properties
from .properties import PluginProperties


class AutotoolsPluginProperties(PluginProperties):
class AutotoolsPluginProperties(PluginProperties, frozen=True):
"""The part properties used by the autotools plugin."""
plugin: Literal["autotools"] = "autotools"

autotools_configure_parameters: list[str] = []
autotools_bootstrap_parameters: list[str] = []

# part properties required by the plugin
source: str

@classmethod
@override
def unmarshal(cls, data: dict[str, Any]) -> "AutotoolsPluginProperties":
"""Populate autotools properties from the part specification.
:param data: A dictionary containing part properties.
:return: The populated plugin properties data object.
:raise pydantic.ValidationError: If validation fails.
"""
plugin_data = extract_plugin_properties(
data, plugin_name="autotools", required=["source"]
)
return cls(**plugin_data)


class AutotoolsPlugin(Plugin):
"""The autotools plugin is used for autotools-based parts.
Expand Down
11 changes: 8 additions & 3 deletions craft_parts/plugins/base.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
#
# Copyright 2020-2023 Canonical Ltd.
# Copyright 2020-2024 Canonical Ltd.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
Expand All @@ -16,9 +16,14 @@

"""Plugin base class and definitions."""

from __future__ import annotations

import abc
from copy import deepcopy
from typing import TYPE_CHECKING, Any
from typing import TYPE_CHECKING, Any, ClassVar, Collection
from typing_extensions import Self

import pydantic

from craft_parts.actions import ActionProperties

Expand Down Expand Up @@ -123,7 +128,7 @@ def _get_java_post_build_commands(self) -> list[str]:


def extract_plugin_properties(
data: dict[str, Any], *, plugin_name: str, required: list[str] | None = None
data: dict[str, Any], *, plugin_name: str, required: Collection[str] | None = None
) -> dict[str, Any]:
"""Obtain plugin-specific entries from part properties.
Expand Down
23 changes: 4 additions & 19 deletions craft_parts/plugins/cmake_plugin.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
#
# Copyright 2020-2022 Canonical Ltd.
# Copyright 2020-2022,2024 Canonical Ltd.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
Expand All @@ -16,39 +16,24 @@

"""The cmake plugin."""

from typing import Any, cast
from typing import Any, Literal, cast

from overrides import override

from .base import Plugin, extract_plugin_properties
from .properties import PluginProperties


class CMakePluginProperties(PluginProperties):
class CMakePluginProperties(PluginProperties, frozen=True):
"""The part properties used by the cmake plugin."""
plugin: Literal["cmake"] = "cmake"

cmake_parameters: list[str] = []
cmake_generator: str = "Unix Makefiles"

# part properties required by the plugin
source: str

@classmethod
@override
def unmarshal(cls, data: dict[str, Any]) -> "CMakePluginProperties":
"""Populate class attributes from the part specification.
:param data: A dictionary containing part properties.
:return: The populated plugin properties data object.
:raise pydantic.ValidationError: If validation fails.
"""
plugin_data = extract_plugin_properties(
data, plugin_name="cmake", required=["source"]
)
return cls(**plugin_data)


class CMakePlugin(Plugin):
"""The cmake plugin is useful for building cmake based parts.
Expand Down
23 changes: 4 additions & 19 deletions craft_parts/plugins/dotnet_plugin.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
#
# Copyright 2021 Canonical Ltd.
# Copyright 2021,2024 Canonical Ltd.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
Expand All @@ -17,7 +17,7 @@
"""The Dotnet plugin."""

import logging
from typing import Any, cast
from typing import Any, Literal, cast

from overrides import override

Expand All @@ -28,31 +28,16 @@
logger = logging.getLogger(__name__)


class DotnetPluginProperties(PluginProperties):
class DotnetPluginProperties(PluginProperties, frozen=True):
"""The part properties used by the Dotnet plugin."""
plugin: Literal["dotnet"] = "dotnet"

dotnet_build_configuration: str = "Release"
dotnet_self_contained_runtime_identifier: str | None = None

# part properties required by the plugin
source: str

@classmethod
@override
def unmarshal(cls, data: dict[str, Any]) -> "DotnetPluginProperties":
"""Populate make properties from the part specification.
:param data: A dictionary containing part properties.
:return: The populated plugin properties data object.
:raise pydantic.ValidationError: If validation fails.
"""
plugin_data = extract_plugin_properties(
data, plugin_name="dotnet", required=["source"]
)
return cls(**plugin_data)


class DotPluginEnvironmentValidator(validator.PluginEnvironmentValidator):
"""Check the execution environment for the Dotnet plugin.
Expand Down
25 changes: 5 additions & 20 deletions craft_parts/plugins/dump_plugin.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
#
# Copyright 2020 Canonical Ltd.
# Copyright 2020,2024 Canonical Ltd.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
Expand All @@ -19,33 +19,18 @@
This plugin just dumps the content from a specified part source.
"""

from typing import Any
from typing import Any, Literal

from overrides import override

from .base import Plugin
from .properties import PluginProperties


class DumpPluginProperties(PluginProperties):
class DumpPluginProperties(PluginProperties, frozen=True):
"""The part properties used by the dump plugin."""

@classmethod
@override
def unmarshal(cls, data: dict[str, Any]) -> "DumpPluginProperties":
"""Populate dump properties from the part specification.
'source' is a required part property.
:param data: A dictionary containing part properties.
:return: The populated plugin properties data object.
:raise ValueError: If a required property is not found.
"""
if "source" not in data:
raise ValueError("'source' is required by the dump plugin")
return cls()
plugin: Literal["dump"] = "dump"
source: str


class DumpPlugin(Plugin):
Expand Down
23 changes: 4 additions & 19 deletions craft_parts/plugins/go_plugin.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
#
# Copyright 2020-2021 Canonical Ltd.
# Copyright 2020-2021,2024 Canonical Ltd.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
Expand All @@ -17,7 +17,7 @@
"""The Go plugin."""

import logging
from typing import Any, cast
from typing import Any, Literal, cast

from overrides import override

Expand All @@ -30,31 +30,16 @@
logger = logging.getLogger(__name__)


class GoPluginProperties(PluginProperties):
class GoPluginProperties(PluginProperties, frozen=True):
"""The part properties used by the Go plugin."""
plugin: Literal["go"] = "go"

go_buildtags: list[str] = []
go_generate: list[str] = []

# part properties required by the plugin
source: str

@classmethod
@override
def unmarshal(cls, data: dict[str, Any]) -> "GoPluginProperties":
"""Populate make properties from the part specification.
:param data: A dictionary containing part properties.
:return: The populated plugin properties data object.
:raise pydantic.ValidationError: If validation fails.
"""
plugin_data = extract_plugin_properties(
data, plugin_name="go", required=["source"]
)
return cls(**plugin_data)


class GoPluginEnvironmentValidator(validator.PluginEnvironmentValidator):
"""Check the execution environment for the Go plugin.
Expand Down
23 changes: 4 additions & 19 deletions craft_parts/plugins/make_plugin.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
#
# Copyright 2020-2021 Canonical Ltd.
# Copyright 2020-2021,2024 Canonical Ltd.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
Expand All @@ -16,38 +16,23 @@

"""The make plugin implementation."""

from typing import Any, cast
from typing import Any, Literal, cast

from overrides import override

from .base import Plugin, extract_plugin_properties
from .properties import PluginProperties


class MakePluginProperties(PluginProperties):
class MakePluginProperties(PluginProperties, frozen=True):
"""The part properties used by the make plugin."""
plugin: Literal["make"] = "make"

make_parameters: list[str] = []

# part properties required by the plugin
source: str

@classmethod
@override
def unmarshal(cls, data: dict[str, Any]) -> "MakePluginProperties":
"""Populate make properties from the part specification.
:param data: A dictionary containing part properties.
:return: The populated plugin properties data object.
:raise pydantic.ValidationError: If validation fails.
"""
plugin_data = extract_plugin_properties(
data, plugin_name="make", required=["source"]
)
return cls(**plugin_data)


class MakePlugin(Plugin):
"""A plugin useful for building make-based parts.
Expand Down
Loading

0 comments on commit ff77dd9

Please sign in to comment.