Skip to content

Commit

Permalink
feat: maven rockcraft plugin
Browse files Browse the repository at this point in the history
Add overrides for craft-part maven plugin to allow
building Maven projects in rockcraft.

Namely:
 - Do not link /bin/java as it conflicts with the base-files_base slice
 - Restrict PATH to /usr/bin in order to avoid picking up unwanted JVM.
   Use can override PATH in the plugin environment settings if /usr/bin
   is not sufficient.
  • Loading branch information
vpa1977 committed Oct 8, 2024
1 parent ac841b4 commit 13f71d5
Show file tree
Hide file tree
Showing 6 changed files with 171 additions and 1 deletion.
76 changes: 76 additions & 0 deletions rockcraft/plugins/maven_plugin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
#
# Copyright 2023 Canonical Ltd.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

"""The Rockcraft Maven plugin."""
import logging
from textwrap import dedent

from craft_parts.plugins import maven_plugin
from overrides import override # type: ignore[reportUnknownVariableType]

logger = logging.getLogger(__name__)

# Template for the sitecustomize module that we'll add to the payload so that
# the pip-installed packages are found regardless of how the interpreter is
# called.
SITECUSTOMIZE_TEMPLATE = dedent(
"""
# sitecustomize added by Rockcraft.
import site
import sys
major, minor = sys.version_info.major, sys.version_info.minor
site_dir = f"/lib/python{major}.{minor}/site-packages"
dist_dir = "/usr/lib/python3/dist-packages"
# Add the directory that contains the venv-installed packages.
site.addsitedir(site_dir)
if dist_dir in sys.path:
# Make sure that this site-packages dir comes *before* the base-provided
# dist-packages dir in sys.path.
path = sys.path
site_index = path.index(site_dir)
dist_index = path.index(dist_dir)
if dist_index < site_index:
path[dist_index], path[site_index] = path[site_index], path[dist_index]
EOF
"""
).strip()


class MavenPlugin(maven_plugin.MavenPlugin):
"""A MavenPlugin plugin for Rockcraft.
This plugin extends Craft-parts' vanilla Maven plugin to properly
use and install the Java VM. Specifically:
- Do not link java executable to /bin/java
- Do not include staging area in the PATH
"""

@override
def _get_java_link_commands(self) -> list[str]:
"""Get the bash commands to provide /bin/java symlink."""
return []

@override
def get_build_environment(self) -> dict[str, str]:
env = super().get_build_environment()
env["PATH"] = "/usr/bin"
return env
3 changes: 2 additions & 1 deletion rockcraft/plugins/register.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import craft_parts
from craft_parts.plugins.plugins import PluginType

from .maven_plugin import MavenPlugin
from .poetry_plugin import PoetryPlugin
from .python_plugin import PythonPlugin

Expand All @@ -30,4 +31,4 @@ def register() -> None:

def get_plugins() -> dict[str, PluginType]:
"""Get a dict of Rockcraft-specific plugins."""
return {"poetry": PoetryPlugin, "python": PythonPlugin}
return {"poetry": PoetryPlugin, "python": PythonPlugin, "maven": MavenPlugin}
35 changes: 35 additions & 0 deletions tests/spread/rockcraft/plugin-maven/rockcraft.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: bare-build-2404
base: bare
build-base: ubuntu@24.04

version: '0.1'
summary: A rock that bundles a Maven project.
description: A rock that bundles a Python project.
license: GPL-3.0
platforms:
amd64:

services:
test:
command: /usr/lib/jvm/java-21-openjdk-${CRAFT_ARCH_BUILD_FOR}/bin/java -jar /jar/sample-0.0.1-SNAPSHOT.jar
override: replace
startup: enabled

parts:
maven-sample:
plugin: maven
source: sample
stage-packages:
- openjdk-21-jre-headless_core
- base-files_base
build-packages:
- maven
- openjdk-21-jdk-headless
# replace chiselled image with jlink
override-stage: |
craftctl default
rm -rf ${CRAFT_STAGE}/usr/lib/jvm/java-21-openjdk-${CRAFT_ARCH_BUILD_FOR}
jlink --no-header-files --no-man-pages --strip-debug \
--add-modules java.base,java.xml,java.logging,jdk.net \
--output ${CRAFT_STAGE}/usr/lib/jvm/java-21-openjdk-${CRAFT_ARCH_BUILD_FOR}
touch ${CRAFT_STAGE}/usr/lib/jvm/java-21-openjdk-${CRAFT_ARCH_BUILD_FOR}/lib/jvm.cfg-default
30 changes: 30 additions & 0 deletions tests/spread/rockcraft/plugin-maven/sample/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>test</groupId>
<artifactId>sample</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>sample</name>
<properties>
<maven.compiler.target>8</maven.compiler.target>
<maven.compiler.source>8</maven.compiler.source>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.4.2</version>
<configuration>
<archive>
<manifest>
<mainClass>test.Test</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package test;

public class Test {
public static void main(String[] args) {
System.out.println("hello world");
}
}
21 changes: 21 additions & 0 deletions tests/spread/rockcraft/plugin-maven/task.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
summary: Maven plugin tests
execute: |
SCENARIO="plugin-maven"
ROCK_FILE="${SCENARIO}_0.1_amd64.rock"
IMAGE="${SCENARIO}:0.1"
# Build the rock & load it into docker
run_rockcraft pack
test -f ${ROCK_FILE}
rockcraft.skopeo copy oci-archive:${ROCK_FILE} docker-daemon:${IMAGE}
docker images
rm ${ROCK_FILE}
# Run the packaged project, both via the console script and via "python -m"
docker run --rm $IMAGE exec hello | MATCH "hello world"
docker system prune -a -f
# Rebuild the java project
touch sample/src/main/java/test/Test.java
rockcraft pack

0 comments on commit 13f71d5

Please sign in to comment.