# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
#
# Copyright 2022 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 warranty of
# MERCHANTABILITY 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 <http://www.gnu.org/licenses/>.
"""The Ant plugin."""
import logging
from typing import Any, Dict, List, Optional, Set, cast
from overrides import override
from craft_parts import errors
from . import validator
from .base import JavaPlugin, PluginModel, extract_plugin_properties
from .properties import PluginProperties
logger = logging.getLogger(__name__)
[docs]class AntPluginProperties(PluginProperties, PluginModel):
"""The part properties used by the Ant plugin."""
ant_build_targets: List[str] = []
ant_build_file: Optional[str] = None
ant_properties: Dict[str, str] = {}
source: str
[docs] @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)
[docs]class AntPluginEnvironmentValidator(validator.PluginEnvironmentValidator):
"""Check the execution environment for the Ant plugin.
:param part_name: The part whose build environment is being validated.
:param env: A string containing the build step environment setup.
"""
[docs] @override
def validate_environment(
self, *, part_dependencies: Optional[List[str]] = None
) -> None:
"""Ensure the environment contains dependencies needed by the plugin.
:param part_dependencies: A list of the parts this part depends on.
:raises PluginEnvironmentValidationError: If ``ant`` is invalid
and there are no parts named ant.
"""
version = self.validate_dependency(
dependency="ant",
plugin_name="ant",
part_dependencies=part_dependencies,
argument="-version",
)
if not version.startswith("Apache Ant") and (
part_dependencies is None or "ant-deps" not in part_dependencies
):
raise errors.PluginEnvironmentValidationError(
part_name=self._part_name,
reason=f"invalid ant version {version!r}",
)
[docs]class AntPlugin(JavaPlugin):
"""A plugin for Apache Ant projects.
The plugin requires the ``ant`` tool installed on the system. This can
be achieved by adding the appropriate declarations to ``build-packages``
or ``build-snaps``, or by having it installed or built in a different
part. In this case, the name of the part supplying ``ant`` must be
"ant-deps".
Additionally, Java projects need a dev kit (jdk) to build and a runtime
environment (jre) to run. There are multiple choices here, but frequently
adding ``default-jdk-headless`` to ``build-packages`` and
``default-jre-headless`` to ``stage-packages`` is enough.
Once built, the plugin will create the following structure in the part's
install dir (which will later be staged/primed/packaged):
- A ``bin/java`` symlink pointing to the actual ``java`` binary provided
by the jre;
- A ``jar/`` directory containing the .jar files generated by the build.
The ant plugin uses the common plugin keywords, plus the following ant-
specific keywords:
- ``ant-build-targets``
(list of strings)
The ant targets to build. These are directly passed to the ``ant``
command line.
- ``ant-build-file``
(str)
The name of the main ant build file. Defaults to ``build.xml``.
- ``ant-properties``
(dict of strings to strings)
A series of key: value pairs that are passed to ant as properties
(using the ``-D{key}={value}`` notation).
"""
properties_class = AntPluginProperties
validator_class = AntPluginEnvironmentValidator
[docs] @override
def get_build_snaps(self) -> Set[str]:
"""Return a set of required snaps to install in the build environment."""
return set()
[docs] @override
def get_build_packages(self) -> Set[str]:
"""Return a set of required packages to install in the build environment."""
return set()
[docs] @override
def get_build_environment(self) -> Dict[str, str]:
"""Return a dictionary with the environment to use in the build step."""
return {}
[docs] @override
def get_build_commands(self) -> List[str]:
"""Return a list of commands to run during the build step."""
options = cast(AntPluginProperties, self._options)
command = ["ant"]
if options.ant_build_file:
command.extend(["-f", options.ant_build_file])
for prop_name, prop_value in options.ant_properties.items():
command.append(f"-D{prop_name}={prop_value}")
command.extend(options.ant_build_targets)
return [
" ".join(command),
] + self._get_java_post_build_commands()