# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-## 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# 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."""importloggingimportosimportshlexfromcollections.abcimportIteratorfromtypingimportLiteral,castfromurllib.parseimporturlsplitfromoverridesimportoverridefromcraft_partsimporterrorsfrom.importvalidatorfrom.java_pluginimportJavaPluginfrom.propertiesimportPluginPropertieslogger=logging.getLogger(__name__)
[docs]classAntPluginProperties(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=Noneant_properties:dict[str,str]={}source:str# pyright: ignore[reportGeneralTypeIssues]
[docs]classAntPluginEnvironmentValidator(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]@overridedefvalidate_environment(self,*,part_dependencies:list[str]|None=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",)ifnotversion.startswith("Apache Ant")and(part_dependenciesisNoneor"ant-deps"notinpart_dependencies):raiseerrors.PluginEnvironmentValidationError(part_name=self._part_name,reason=f"invalid ant version {version!r}",)
[docs]classAntPlugin(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=AntPluginPropertiesvalidator_class=AntPluginEnvironmentValidator
[docs]@overridedefget_build_snaps(self)->set[str]:"""Return a set of required snaps to install in the build environment."""returnset()
[docs]@overridedefget_build_packages(self)->set[str]:"""Return a set of required packages to install in the build environment."""returnset()
[docs]@overridedefget_build_environment(self)->dict[str,str]:"""Return a dictionary with the environment to use in the build step."""env=super().get_build_environment()# Getting ant to use a proxy requires a little work; the JRE doesn't# help as much as it should. (java.net.useSystemProxies=true ought# to do the trick, but it relies on desktop configuration rather# than using the standard environment variables.)ant_opts:list[str]=[]ant_opts.extend(_get_proxy_options("http"))ant_opts.extend(_get_proxy_options("https"))ifant_opts:env["ANT_OPTS"]=_shlex_join(ant_opts)returnenv
[docs]@overridedefget_build_commands(self)->list[str]:"""Return a list of commands to run during the build step."""options=cast(AntPluginProperties,self._options)command=["ant"]ifoptions.ant_build_file:command.extend(["-f",options.ant_build_file])forprop_name,prop_valueinoptions.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()]
def_get_proxy_options(scheme:str)->Iterator[str]:proxy=os.environ.get(f"{scheme}_proxy")ifproxy:parsed=urlsplit(proxy)ifparsed.hostnameisnotNone:yieldf"-D{scheme}.proxyHost={parsed.hostname}"ifparsed.portisnotNone:yieldf"-D{scheme}.proxyPort={parsed.port}"ifparsed.usernameisnotNone:yieldf"-D{scheme}.proxyUser={parsed.username}"ifparsed.passwordisnotNone:yieldf"-D{scheme}.proxyPassword={parsed.password}"def_shlex_join(elements:list[str])->str:try:returnshlex.join(elements)exceptAttributeError:# Python older than 3.8 does not have shlex.joinreturn" ".join(elements)