diff --git a/platformcraft.yaml b/platformcraft.yaml new file mode 100644 index 000000000..b269db16a --- /dev/null +++ b/platformcraft.yaml @@ -0,0 +1,23 @@ +name: my-platform-thingy +base: ubuntu@25.10 +version: "0" + +platforms: + mario: + build-on: [amd64, arm64] + build-for: [arm64] + extensions: + - player-1 + + luigi: + build-on: [amd64, riscv64] + build-for: [riscv64] + extensions: + - player-2 + + +parts: + thing: + plugin: nil + override-build: | + exit 0 diff --git a/platformcraft/__init__.py b/platformcraft/__init__.py new file mode 100644 index 000000000..a5d4f9dbc --- /dev/null +++ b/platformcraft/__init__.py @@ -0,0 +1,21 @@ +# This file is part of craft_application. +# +# Copyright 2025 Canonical Ltd. +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License version 3, as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, +# SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with this program. If not, see . +"""Platformcraft. + +Platformcraft is a fake craft-application app that enables partitions. + +This package contains things that differ between testcraft and platformcraft. +""" diff --git a/platformcraft/__main__.py b/platformcraft/__main__.py new file mode 100644 index 000000000..a16bb2ed9 --- /dev/null +++ b/platformcraft/__main__.py @@ -0,0 +1,22 @@ +# This file is part of craft_application. +# +# Copyright 2025 Canonical Ltd. +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License version 3, as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, +# SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with this program. If not, see . +"""The main entrypoint to testcraft.""" + +import sys + +from platformcraft import cli + +sys.exit(cli.create_app().run()) diff --git a/platformcraft/application.py b/platformcraft/application.py new file mode 100644 index 000000000..733ad5548 --- /dev/null +++ b/platformcraft/application.py @@ -0,0 +1,30 @@ +# This file is part of craft_application. +# +# Copyright 2025 Canonical Ltd. +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License version 3, as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, +# SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with this program. If not, see . +"""Application implementation for partitioncraft.""" + +import craft_application + +from platformcraft.models.project import FancyProject + +PLATFORMCRAFT = craft_application.AppMetadata( + name="platformcraft", + summary="A craft for testing custom platform definitions in craft-application.", + docs_url="https://canonical-craft-application.readthedocs-hosted.com", + source_ignore_patterns=["*.platformcraft"], + project_variables=["version"], + mandatory_adoptable_fields=["version"], + ProjectClass=FancyProject, +) diff --git a/platformcraft/cli.py b/platformcraft/cli.py new file mode 100644 index 000000000..4dc9906e4 --- /dev/null +++ b/platformcraft/cli.py @@ -0,0 +1,43 @@ +# This file is part of craft_application. +# +# Copyright 2025 Canonical Ltd. +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License version 3, as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, +# SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with this program. If not, see . +"""Main CLI for platformcraft.""" + +from typing import Any + +import craft_application +import craft_cli + +from platformcraft.application import PLATFORMCRAFT +from platformcraft.services import register_services + + +def create_app() -> craft_application.Application: + """Create the application. + + This is used both for running the app and for generating shell completion. + This function is where the app should be configured before running it. + """ + register_services() + services = craft_application.ServiceFactory(app=PLATFORMCRAFT) + + return craft_application.Application(PLATFORMCRAFT, services=services) + + +def get_completion_data() -> tuple[craft_cli.Dispatcher, dict[str, Any]]: + """Get the app info for use with craft-cli's completion module.""" + app = create_app() + + return app._create_dispatcher(), app.app_config # noqa: SLF001 diff --git a/platformcraft/models/__init__.py b/platformcraft/models/__init__.py new file mode 100644 index 000000000..0e1c3d033 --- /dev/null +++ b/platformcraft/models/__init__.py @@ -0,0 +1 @@ +"""Models for platformcraft.""" diff --git a/platformcraft/models/platform.py b/platformcraft/models/platform.py new file mode 100644 index 000000000..3d4bebd85 --- /dev/null +++ b/platformcraft/models/platform.py @@ -0,0 +1,30 @@ +# noqa: A005 +# This file is part of craft_application. +# +# Copyright 2025 Canonical Ltd. +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License version 3, as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, +# SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with this program. If not, see . +"""Model for a FANCY platform. 🎩🧐.""" + +from craft_application.models import platforms +from craft_application.models.constraints import UniqueList + + +class FancyPlatform(platforms.Platform): + """Model for a FANCY platform. 🎩🧐.""" + + extensions: UniqueList[str] + + +class FancyPlatformsDict(platforms.GenericPlatformsDict[FancyPlatform]): + """Model for a FANCY dictionary of platforms! 🎩🧐.""" diff --git a/platformcraft/models/project.py b/platformcraft/models/project.py new file mode 100644 index 000000000..07238711b --- /dev/null +++ b/platformcraft/models/project.py @@ -0,0 +1,26 @@ +# This file is part of craft_application. +# +# Copyright 2025 Canonical Ltd. +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License version 3, as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, +# SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with this program. If not, see . +"""Model for a FANCY project. 🎩🧐.""" + +from craft_application.models import project + +from platformcraft.models.platform import FancyPlatformsDict + + +class FancyProject(project.Project): + """Model for a FANCY project. 🎩🧐.""" + + platforms: FancyPlatformsDict diff --git a/platformcraft/services/__init__.py b/platformcraft/services/__init__.py new file mode 100644 index 000000000..10619dea5 --- /dev/null +++ b/platformcraft/services/__init__.py @@ -0,0 +1,34 @@ +# This file is part of craft_application. +# +# Copyright 2025 Canonical Ltd. +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License version 3, as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, +# SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with this program. If not, see . +"""Services for platformcraft.""" + +import craft_application + + +def register_services() -> None: + """Register Partitioncraft's services. + + This registers with the ServiceFactory all the services that platformcraft + adds or overrides. + """ + craft_application.ServiceFactory.register( + "package", "PackageService", module="platformcraft.services.package" + ) + craft_application.ServiceFactory.register( + "project", + "ProjectService", + module="platformcraft.services.project", + ) diff --git a/platformcraft/services/package.py b/platformcraft/services/package.py new file mode 100644 index 000000000..c56d3fd65 --- /dev/null +++ b/platformcraft/services/package.py @@ -0,0 +1,56 @@ +# This file is part of craft_application. +# +# Copyright 2025 Canonical Ltd. +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License version 3, as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, +# SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with this program. If not, see . +"""Partitioncraft package service.""" + +import pathlib +import tarfile +from typing import cast + +import craft_application +from craft_application.services import package +from testcraft.models.metadata import Metadata + +from platformcraft.models.project import FancyProject + + +class PackageService(package.PackageService): + """Package service for partitioncraft.""" + + @property + def metadata(self) -> Metadata: + """Get the metadata for this model.""" + project = self._services.get("project").get() + if project.version is None: + raise ValueError("Unknown version") + return Metadata( + name=project.name, + version=project.version, + craft_application_version=craft_application.__version__, + ) + + def pack(self, prime_dir: pathlib.Path, dest: pathlib.Path) -> list[pathlib.Path]: + """Pack a partitioncraft artifact set.""" + project = cast(FancyProject, self._services.get("project").get()) + platform = self._services.get("build_plan").plan()[0].platform + + extension = ".".join(project.platforms[platform].extensions) + + tarball_name = ( + f"{project.name}-{project.version}-{platform}.{extension}.platformcraft" + ) + with tarfile.open(dest / tarball_name, mode="w:xz") as tar: + tar.add(prime_dir, arcname=".") + return [dest / tarball_name] diff --git a/platformcraft/services/project.py b/platformcraft/services/project.py new file mode 100644 index 000000000..a8ab73909 --- /dev/null +++ b/platformcraft/services/project.py @@ -0,0 +1,48 @@ +# This file is part of craft_application. +# +# Copyright 2025 Canonical Ltd. +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License version 3, as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, +# SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with this program. If not, see . +"""Partitioncraft project service. + +Needed so we can set partitions. +""" + +import craft_platforms +import pydantic +from craft_application.services import project +from typing_extensions import override + +from platformcraft.models.platform import FancyPlatformsDict + + +class ProjectService(project.ProjectService): + """Package service for testcraft.""" + + @override + @classmethod + def _preprocess_platforms( + cls, platforms: dict[str, craft_platforms.PlatformDict] + ) -> dict[str, craft_platforms.PlatformDict]: + """Validate that the given platforms value is valid.""" + if platforms: + cls._vectorise_platforms(platforms) + platforms_project_adapter = pydantic.TypeAdapter( + FancyPlatformsDict, + ) + return platforms_project_adapter.dump_python( # type: ignore[no-any-return] + platforms_project_adapter.validate_python(platforms), + mode="json", + by_alias=True, + exclude_defaults=True, + )