-
Notifications
You must be signed in to change notification settings - Fork 41
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Co-authored-by: Tiago Nobrega <tiago.nobrega@canonical.com> Co-authored-by: Michael DuBelko <michael.dubelko@gmail.com> Co-authored-by: Callahan Kovacs <callahan.kovacs@canonical.com> Signed-off-by: Callahan Kovacs <callahan.kovacs@canonical.com>
- Loading branch information
1 parent
c6dc566
commit ba3891a
Showing
10 changed files
with
498 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*- | ||
# | ||
# Copyright 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 JLink plugin.""" | ||
|
||
from typing import Literal, cast | ||
|
||
from overrides import override | ||
|
||
from .base import Plugin | ||
from .properties import PluginProperties | ||
from .validator import PluginEnvironmentValidator | ||
|
||
|
||
class JLinkPluginProperties(PluginProperties, frozen=True): | ||
"""The part properties used by the JLink plugin.""" | ||
|
||
plugin: Literal["jlink"] = "jlink" | ||
jlink_jars: list[str] = [] | ||
|
||
|
||
class JLinkPluginEnvironmentValidator(PluginEnvironmentValidator): | ||
"""Check the execution environment for the JLink plugin. | ||
:param part_name: The part whose build environment is being validated. | ||
:param env: A string containing the build step environment setup. | ||
""" | ||
|
||
@override | ||
def validate_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 go is invalid | ||
and there are no parts named go. | ||
""" | ||
self.validate_dependency( | ||
dependency="jlink", plugin_name="jlink", part_dependencies=part_dependencies | ||
) | ||
|
||
|
||
class JLinkPlugin(Plugin): | ||
"""Create a Java Runtime using JLink.""" | ||
|
||
properties_class = JLinkPluginProperties | ||
validator_class = JLinkPluginEnvironmentValidator | ||
|
||
@override | ||
def get_build_packages(self) -> set[str]: | ||
"""Return a set of required packages to install in the build environment.""" | ||
return set() | ||
|
||
@override | ||
def get_build_environment(self) -> dict[str, str]: | ||
"""Return a dictionary with the environment to use in the build step.""" | ||
return {} | ||
|
||
@override | ||
def get_build_snaps(self) -> set[str]: | ||
"""Return a set of required snaps to install in the build environment.""" | ||
return set() | ||
|
||
@override | ||
def get_build_commands(self) -> list[str]: | ||
"""Return a list of commands to run during the build step.""" | ||
options = cast(JLinkPluginProperties, self._options) | ||
|
||
commands = [] | ||
|
||
# Set JAVA_HOME to be used in jlink commands | ||
commands.append( | ||
""" | ||
if [ -z "${JAVA_HOME+x}" ]; then | ||
JAVA_HOME=$(dirname $(dirname $(readlink -f $(which jlink)))) | ||
fi | ||
if [ ! -x "${JAVA_HOME}/bin/java" ]; then | ||
echo "Error: JAVA_HOME: '${JAVA_HOME}/bin/java' is not an executable." >&2 | ||
exit 1 | ||
fi | ||
JLINK=${JAVA_HOME}/bin/jlink | ||
JDEPS=${JAVA_HOME}/bin/jdeps | ||
""" | ||
) | ||
|
||
# extract jlink version and use it to define the destination | ||
# and multi-release jar version for the dependency enumeration | ||
commands.append("JLINK_VERSION=$(${JLINK} --version)") | ||
commands.append( | ||
"DEST=usr/lib/jvm/java-${JLINK_VERSION%%.*}-openjdk-${CRAFT_ARCH_BUILD_FOR}" | ||
) | ||
commands.append("MULTI_RELEASE=${JLINK_VERSION%%.*}") | ||
|
||
# find application jars - either all jars in the staging area | ||
# or a list specified in jlink_jars option | ||
if len(options.jlink_jars) > 0: | ||
jars = " ".join(["${CRAFT_STAGE}/" + x for x in options.jlink_jars]) | ||
commands.append(f"PROCESS_JARS={jars}") | ||
else: | ||
commands.append("PROCESS_JARS=$(find ${CRAFT_STAGE} -type f -name *.jar)") | ||
|
||
# create temp folder | ||
commands.append("mkdir -p ${CRAFT_PART_BUILD}/tmp") | ||
# extract jar files into temp folder - spring boot fat jar | ||
# contains dependent jars inside | ||
commands.append( | ||
"(cd ${CRAFT_PART_BUILD}/tmp && for jar in ${PROCESS_JARS}; do jar xvf ${jar}; done;)" | ||
) | ||
# create classpath - add all dependent jars and all staged jars | ||
commands.append("CPATH=.") | ||
commands.append( | ||
""" | ||
find ${CRAFT_PART_BUILD}/tmp -type f -name *.jar | while IFS= read -r file; do | ||
CPATH=$CPATH:${file} | ||
done | ||
find ${CRAFT_STAGE} -type f -name *.jar | while IFS= read -r file; do | ||
CPATH=$CPATH:${file} | ||
done | ||
""" | ||
) | ||
commands.append( | ||
"""if [ "x${PROCESS_JARS}" != "x" ]; then | ||
deps=$(${JDEPS} --class-path=${CPATH} -q --recursive --ignore-missing-deps \ | ||
--print-module-deps --multi-release ${MULTI_RELEASE} ${PROCESS_JARS}) | ||
else | ||
deps=java.base | ||
fi | ||
""" | ||
) | ||
commands.append("INSTALL_ROOT=${CRAFT_PART_INSTALL}/${DEST}") | ||
|
||
commands.append( | ||
"rm -rf ${INSTALL_ROOT} && ${JLINK} --no-header-files --no-man-pages --strip-debug --add-modules ${deps} --output ${INSTALL_ROOT}" | ||
) | ||
# create /usr/bin/java link | ||
commands.append( | ||
"(cd ${CRAFT_PART_INSTALL} && mkdir -p usr/bin && ln -s --relative ${DEST}/bin/java usr/bin/)" | ||
) | ||
return commands |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
107 changes: 107 additions & 0 deletions
107
docs/common/craft-parts/reference/plugins/jlink_plugin.rst
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
.. _craft_parts_jlink_plugin: | ||
|
||
JLink plugin | ||
============= | ||
|
||
The `JLink <jlink_>`_ plugin can be used for Java projects where | ||
you would want to deploy a Java runtime specific for your application | ||
or install a minimal Java runtime. | ||
|
||
|
||
Keywords | ||
-------- | ||
|
||
This plugin uses the common :ref:`plugin <part-properties-plugin>` keywords as | ||
well as those for :ref:`sources <part-properties-sources>`. | ||
|
||
Additionally, this plugin provides the plugin-specific keywords defined in the | ||
following sections. | ||
|
||
jlink-jars | ||
~~~~~~~~~~~~~~~~~~ | ||
**Type:** list of strings | ||
|
||
List of paths to your application's JAR files. If not specified, the plugin | ||
will find all JAR files in the staging area. | ||
|
||
Dependencies | ||
------------ | ||
|
||
The plugin expects OpenJDK to be available on the system and to contain | ||
the ``jlink`` executable. OpenJDK can be defined as a | ||
``build-package`` in the part using ``jlink`` plugin. | ||
Another alternative is to define another part with the name | ||
``jlink-deps``, and declare that the part using the | ||
``jlink`` plugin comes :ref:`after <after>` the ``jlink-deps`` part. | ||
|
||
If the system has multiple OpenJDK installations available, one | ||
must be selected by setting the ``JAVA_HOME`` environment variable. | ||
|
||
.. code-block:: yaml | ||
parts: | ||
runtime: | ||
plugin: jlink | ||
build-packages: | ||
- openjdk-21-jdk | ||
build-environment: | ||
- JAVA_HOME: /usr/jvm/java-21-openjdk-${CRAFT_ARCH_BUILD_FOR} | ||
The user is expected to stage OpenJDK dependencies either by installing | ||
an appropriate OpenJDK slice: | ||
|
||
.. code-block:: yaml | ||
parts: | ||
runtime: | ||
plugin: jlink | ||
build-packages: | ||
- openjdk-21-jdk | ||
after: | ||
- deps | ||
deps: | ||
plugin: nil | ||
stage-packages: | ||
- openjdk-21-jre-headless_security | ||
stage: | ||
- -usr/lib/jvm | ||
Or, by installing the dependencies directly: | ||
|
||
.. code-block:: yaml | ||
parts: | ||
runtime: | ||
plugin: jlink | ||
build-packages: | ||
- openjdk-21-jdk | ||
after: | ||
- deps | ||
deps: | ||
plugin: nil | ||
stage-packages: | ||
- libc6_libs | ||
- libgcc-s1_libs | ||
- libstdc++6_libs | ||
- zlib1g_libs | ||
- libnss3_libs | ||
How it works | ||
------------ | ||
|
||
During the build step, the plugin performs the following actions: | ||
|
||
* Finds all JAR files in the staging area or selects jars specified in | ||
``jlink-jars``. | ||
* Unpacks JAR files to the temporary location and concatenates all embedded jars | ||
into `jdeps <jdeps_>`_ classpath. | ||
* Runs `jdeps <jdeps_>`_ to discover Java modules required for the staged jars. | ||
* Runs `jlink <jlink_>`_ to create a runtime image from the build JDK. | ||
|
||
|
||
.. _`jdeps`: https://docs.oracle.com/en/java/javase/21/docs/specs/man/jdeps.html | ||
.. _`jlink`: https://docs.oracle.com/en/java/javase/21/docs/specs/man/jlink.html |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.