Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: JLink plugin #688

Open
wants to merge 55 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 50 commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
276e669
feat: jlink plugin
vpa1977 Aug 28, 2024
1512a53
feat: register jlink plugin
vpa1977 Aug 28, 2024
b7654fa
lint: jlink_plugin.py - reformat
vpa1977 Aug 28, 2024
5d56347
lint: register.py reformat
vpa1977 Aug 28, 2024
c0d8419
lint: test_jlink_plugin.py reformat
vpa1977 Aug 28, 2024
ea176cf
feat: test_jlink_plugin.py integration wip
vpa1977 Aug 28, 2024
545b707
fix: jlink_plugin - dep commands
vpa1977 Aug 28, 2024
3f375f8
feat: rename slice to install dependencies
vpa1977 Aug 29, 2024
2ddf8cf
feat: add dep slices
vpa1977 Aug 29, 2024
4e3615d
test: update test assertions
vpa1977 Aug 29, 2024
ab8598f
test: drop project test.
vpa1977 Aug 29, 2024
7f76cc5
lint: reformat jlink_plugin
vpa1977 Aug 29, 2024
a4844ed
lint: reformat test_jlink_plugin
vpa1977 Aug 29, 2024
7798ac8
test: fix directory.
vpa1977 Aug 29, 2024
c277ac9
Merge branch 'main' into jlink-plugin
vpa1977 Aug 29, 2024
2e18adb
lint(test_jlink_plugin.py): unused import.
vpa1977 Aug 29, 2024
3411fbd
deps: add git and openjdk-21-jdk
vpa1977 Aug 29, 2024
29675ac
Merge branch 'jlink-plugin' of github.com:vpa1977/rockcraft into jlin…
vpa1977 Aug 29, 2024
ceb65d1
lint(jlink_plugin.py): mypy fixes.
vpa1977 Aug 29, 2024
6e875b8
fix(jlink_plugin.py): drop chisel dependency.
vpa1977 Aug 29, 2024
a776464
test(test_jlink_plugin.py): fix assertion
vpa1977 Aug 29, 2024
66ab695
deps: install chisel snap
vpa1977 Aug 29, 2024
212c9fd
deps: install chisel snap
vpa1977 Aug 29, 2024
48b54f4
lint(test_jlink_plugin.py): remove exclusion.
vpa1977 Aug 29, 2024
efde661
test(jlink_plugin): add integration test with jar
vpa1977 Aug 29, 2024
943d333
fix: add minimal default classpath
vpa1977 Aug 29, 2024
e2ce4b5
lint: formatting
vpa1977 Aug 29, 2024
a288da3
lint(test_jlink_plugin.py): remove f-string
vpa1977 Aug 29, 2024
3f2f61a
fix(jlink_plugin): capitalize variables
vpa1977 Aug 29, 2024
dbe14dd
fix(jlink_plugin): use options.jlink_java_version
vpa1977 Aug 29, 2024
d23ed5f
lint(jlink_plugin): fix command formatting
vpa1977 Aug 29, 2024
636e95b
Merge branch 'main' into jlink-plugin
vpa1977 Aug 29, 2024
3ba87e2
fix(jlink_plugin): drop chiselling dependencies
vpa1977 Aug 30, 2024
7a65ec3
Merge branch 'jlink-plugin' of github.com:vpa1977/rockcraft into jlin…
vpa1977 Aug 30, 2024
4c734fc
lint(test_jlink_plugin): reformat.
vpa1977 Aug 30, 2024
07ce839
Merge branch 'main' into jlink-plugin
vpa1977 Sep 4, 2024
609dcfb
lint(jlink_plugin): fix type annotations.
vpa1977 Sep 4, 2024
357f4a7
fix(jlink_plugin): doc comment
vpa1977 Sep 8, 2024
d647605
chore(jlink-plugin): use java_home variable
vpa1977 Sep 9, 2024
17a0dc4
Merge branch 'jlink-plugin' of github.com:vpa1977/rockcraft into jlin…
vpa1977 Sep 9, 2024
4d478cc
test(jlink_plugin): add spread test
vpa1977 Sep 9, 2024
5fbea13
fix(jlink_plugin): remove extra slash from INSTALL_ROOT
vpa1977 Sep 9, 2024
2a0421c
test(jlink_plugin): force compiler release.
vpa1977 Sep 9, 2024
953ad7f
test(plugin-jlink): fix build-base
vpa1977 Sep 9, 2024
a9ff503
test(plugin-jlink): use only 24.04 for testing
vpa1977 Sep 9, 2024
b9e52e4
Merge branch 'main' into jlink-plugin
vpa1977 Sep 11, 2024
e8097e2
fix: do not copy build cacerts
vpa1977 Sep 17, 2024
503f936
Merge branch 'jlink-plugin' of github.com:vpa1977/rockcraft into jlin…
vpa1977 Sep 17, 2024
719bb3f
chore: use format strings
vpa1977 Sep 19, 2024
15d584c
Merge branch 'main' into jlink-plugin
vpa1977 Sep 19, 2024
c3d77e7
Merge branch 'main' into jlink-plugin
vpa1977 Sep 26, 2024
716449a
test: use main chisel branch
vpa1977 Oct 8, 2024
38fafbb
Merge branch 'main' into jlink-plugin
vpa1977 Oct 9, 2024
2339c25
Merge branch 'main' into jlink-plugin
vpa1977 Oct 13, 2024
eb9733f
Merge branch 'main' into jlink-plugin
vpa1977 Oct 15, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,14 @@ jobs:

- name: Install dependencies
run: |
echo "::group::snap install"
sudo snap install chisel --edge
echo "::endgroup::"
echo "::group::apt-get update"
sudo apt-get update
echo "::endgroup::"
echo "::group::apt-get install..."
sudo apt-get install -y python3 python3-dev libapt-pkg-dev libyaml-dev umoci
sudo apt-get install -y python3 python3-dev libapt-pkg-dev libyaml-dev umoci git openjdk-21-jdk
vpa1977 marked this conversation as resolved.
Show resolved Hide resolved
echo "::endgroup::"
echo "::group::pip install"
python -m pip install -U wheel setuptools pip
Expand All @@ -99,4 +102,3 @@ jobs:
- name: Run integration tests
run: |
make test-integrations

3 changes: 2 additions & 1 deletion rockcraft/plugins/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"""Rockcraft-specific plugins."""

from .python_plugin import PythonPlugin
from .jlink_plugin import JLinkPlugin
from .register import get_plugins, register

__all__ = ["PythonPlugin", "get_plugins", "register"]
__all__ = ["PythonPlugin", "JLinkPlugin", "get_plugins", "register"]
93 changes: 93 additions & 0 deletions rockcraft/plugins/jlink_plugin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# -*- 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 craft_parts.plugins import Plugin, PluginProperties
from overrides import override


class JLinkPluginProperties(PluginProperties, frozen=True):
"""The part properties used by the JLink plugin."""

plugin: Literal["jlink"] = "jlink"
jlink_java_version: int = 21
jlink_jars: list[str] = []


class JLinkPlugin(Plugin):
"""Create a Java Runtime using JLink."""

properties_class = JLinkPluginProperties

@override
def get_build_packages(self) -> set[str]:
options = cast(JLinkPluginProperties, self._options)
return {f"openjdk-{options.jlink_java_version}-jdk"}

@override
def get_build_environment(self) -> dict[str, str]:
return {}

@override
def get_build_snaps(self) -> set[str]:
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 = []

java_home = f"usr/lib/jvm/java-{options.jlink_java_version}-openjdk-${{CRAFT_TARGET_ARCH}}"

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
commands.append(
"(cd ${CRAFT_PART_BUILD}/tmp && for jar in ${PROCESS_JARS}; do jar xvf ${jar}; done;)"
)
commands.append("CPATH=$(find ${CRAFT_PART_BUILD}/tmp -type f -name *.jar)")
commands.append("CPATH=$(echo ${CPATH}:. | sed s'/[[:space:]]/:/'g)")
commands.append("echo ${CPATH}")
commands.append(
f"""if [ "x${{PROCESS_JARS}}" != "x" ]; then
deps=$(jdeps --class-path=${{CPATH}} -q --recursive --ignore-missing-deps \
--print-module-deps --multi-release {options.jlink_java_version} ${{PROCESS_JARS}})
else
deps=java.base
fi
"""
)
commands.append(f"INSTALL_ROOT=${{CRAFT_PART_INSTALL}}/{java_home}")

commands.append(
"rm -rf ${INSTALL_ROOT} && jlink --add-modules ${deps} --output ${INSTALL_ROOT}"
)
# create /usr/bin/java link
commands.append(
f"(cd ${{CRAFT_PART_INSTALL}} && mkdir -p usr/bin && ln -s --relative {java_home}/bin/java usr/bin/)"
)
return commands
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 .jlink_plugin import JLinkPlugin
from .python_plugin import PythonPlugin


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

def get_plugins() -> dict[str, PluginType]:
"""Get a dict of Rockcraft-specific plugins."""
return {"python": PythonPlugin}
return {"python": PythonPlugin, "jlink": JLinkPlugin}
115 changes: 115 additions & 0 deletions tests/integration/plugins/test_jlink_plugin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# -*- 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/>.

import atexit
import os
import shutil
import subprocess
from pathlib import Path

import pytest
from craft_application.models import DEVEL_BASE_INFOS
from rockcraft import plugins
from rockcraft.models.project import Project

from tests.testing.project import create_project
from tests.util import ubuntu_only

pytestmark = ubuntu_only


@pytest.fixture(autouse=True)
def setup_test(monkeypatch):
# Keep craft-parts from trying to refresh apt's cache, so that we can run
# this test as regular users.
monkeypatch.setenv("CRAFT_PARTS_PACKAGE_REFRESH", "0")
plugins.register()


def create_test_project(base, parts) -> Project:
build_base = None
if base in [info.current_devel_base for info in DEVEL_BASE_INFOS]:
build_base = "devel"

return create_project(base=base, parts=parts, build_base=build_base)


def get_tmp_path(tmp_path: str) -> Path:
# chisel snap is confined to user home
home = os.path.expanduser("~")
basename = os.path.basename(tmp_path)
ret = Path(f"{home}/{basename}")
atexit.register(lambda: shutil.rmtree(ret))
return ret


def test_jlink_plugin_with_jar(tmp_path, run_lifecycle):
"""Test that jlink produces tailored modules"""
user_home_tmp = get_tmp_path(tmp_path)
parts = {
"my-part": {
"plugin": "jlink",
"source": "https://github.com/vpa1977/chisel-releases",
"source-type": "git",
"source-branch": "24.04-openjdk-21-jre-headless",
"jlink-jars": ["test.jar"],
"after": ["stage-jar"],
},
"stage-jar": {
"plugin": "dump",
"source": ".",
},
}
# build test jar
Path("Test.java").write_text(
"""
import javax.swing.*;
public class Test {
public static void main(String[] args) {
new JFrame("foo").setVisible(true);
}
}
"""
)
subprocess.run(["javac", "Test.java"], check=True, capture_output=True)
subprocess.run(
["jar", "cvf", "test.jar", "Test.class"], check=True, capture_output=True
)
atexit.register(lambda: os.remove("Test.class"))
atexit.register(lambda: os.remove("Test.java"))
atexit.register(lambda: os.remove("test.jar"))

project = create_test_project("ubuntu@24.04", parts)
run_lifecycle(project=project, work_dir=user_home_tmp)
# java.desktop module should be included in the image
assert len(list(Path(f"{user_home_tmp}/stage/usr/lib/jvm/").rglob("libawt.so"))) > 0


def test_jlink_plugin_base(tmp_path, run_lifecycle):
"""Test that jlink produces base image"""
parts = {
"my-part": {
"plugin": "jlink",
"source": "https://github.com/vpa1977/chisel-releases",
"source-type": "git",
"source-branch": "24.04-openjdk-21-jre-headless",
}
}
user_home_tmp = get_tmp_path(tmp_path)
project = create_test_project("ubuntu@24.04", parts)
run_lifecycle(project=project, work_dir=user_home_tmp)
java = user_home_tmp / "stage/usr/bin/java"
assert java.is_file()
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
name: bare-build-2404
base: bare
build-base: ubuntu@24.04

# Remaining contents will come from "parts.yaml"
4 changes: 4 additions & 0 deletions tests/spread/rockcraft/plugin-jlink/base-2404/rockcraft.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
name: base-2404
base: ubuntu@24.04

# Remaining contents will come from "parts.yaml"
73 changes: 73 additions & 0 deletions tests/spread/rockcraft/plugin-jlink/helloworld/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.yourcompany</groupId>
<artifactId>helloworld</artifactId>
<version>1.0-SNAPSHOT</version>

<name>helloworld</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.yourcompany.helloworld;

/**
* Hello world!
*
*/
public class App
{
public static void main( String[] args )
{
System.out.println( "Hello World!" );
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.yourcompany.helloworld;

import static org.junit.Assert.assertTrue;

import org.junit.Test;

/**
* Unit test for simple App.
*/
public class AppTest
{
/**
* Rigorous Test :-)
*/
@Test
public void shouldAnswerWithTrue()
{
assertTrue( true );
}
}
Loading
Loading