diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 000000000..faaa3d2d3 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,85 @@ +name: Build + +on: + push: + branches: + - main + tags: + - v*.* + pull_request: + workflow_dispatch: + + +jobs: + build_wheels: + runs-on: ubuntu-latest + strategy: + matrix: + # macos-13 is an intel runner, macos-14 is apple silicon + pyver: [ cp311, cp312 ] + steps: + - name: Checkout + uses: actions/checkout@v4 + + # Used to host cibuildwheel + - name: Setup python + uses: actions/setup-python@v5 + + - name: Set up QEMU + if: runner.os == 'Linux' + uses: docker/setup-qemu-action@v3 + with: + platforms: all + + - name: Build wheels + uses: pypa/cibuildwheel@v2.21.3 + env: + # configure cibuildwheel to build native archs ('auto'), and some + # emulated ones + CIBW_BUILD: ${{matrix.pyver}}-* + CIBW_ARCHS_LINUX: auto aarch64 + CIBW_BEFORE_ALL_LINUX: > + yum install -y java-11-openjdk-devel + CIBW_SKIP: '*-musllinux_*' + + - uses: actions/upload-artifact@v4 + with: + name: cibw-wheels-${{ matrix.pyver }} + path: ./wheelhouse/*.whl + + build_sdist: + name: Build source distribution + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Build sdist + run: pipx run build --sdist + + - uses: actions/upload-artifact@v4 + with: + name: cibw-sdist + path: dist/*.tar.gz + + upload_pypi: + needs: [build_wheels, build_sdist] + runs-on: ubuntu-latest + environment: + name: pypi + url: https://pypi.org/p/jpype1-ext + permissions: + id-token: write + # if: github.event_name == 'release' && github.event.action == 'published' + # or, alternatively, upload to PyPI on every tag starting with 'v' (remove on: release above to use this) + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') + steps: + - uses: actions/download-artifact@v4 + with: + # unpacks all CIBW artifacts into dist/ + pattern: cibw-* + path: dist + merge-multiple: true + - name: List artifacts + run: ls -lah dist/ + - name: Publish package distributions to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 \ No newline at end of file diff --git a/.gitignore b/.gitignore index 171de2920..9c07df97c 100755 --- a/.gitignore +++ b/.gitignore @@ -85,3 +85,4 @@ jacoco/ wheelhouse/ vc*.pdb *.class +.venv diff --git a/README.rst b/README.rst index 01618319f..d89685eef 100644 --- a/README.rst +++ b/README.rst @@ -7,6 +7,11 @@ JPype |implementation| |pyversions| |javaversions| |jvm| |platform| |license| +Why this fork for LocalStack? +-------------- +We forked the jpype project to add a SIGTERM signal handler to be used in `LocalStack ` +We plan on contributing the changes upstream, should they be accepted. + JPype is a Python module to provide full access to Java from within Python. It allows Python to make use of Java only libraries, exploring and visualization of Java structures, development and testing diff --git a/native/common/jp_context.cpp b/native/common/jp_context.cpp index d6e25cb2f..9d2f8a068 100644 --- a/native/common/jp_context.cpp +++ b/native/common/jp_context.cpp @@ -446,10 +446,10 @@ extern "C" JNIEXPORT void JNICALL Java_org_jpype_JPypeContext_onShutdown static int interruptState = 0; extern "C" JNIEXPORT void JNICALL Java_org_jpype_JPypeSignal_interruptPy -(JNIEnv *env, jclass cls) +(JNIEnv *env, jclass cls, jint signal) { interruptState = 1; - PyErr_SetInterrupt(); + PyErr_SetInterruptEx((int) signal); } extern "C" JNIEXPORT void JNICALL Java_org_jpype_JPypeSignal_acknowledgePy diff --git a/native/java/org/jpype/JPypeSignal.java b/native/java/org/jpype/JPypeSignal.java index be8f1d476..666336638 100644 --- a/native/java/org/jpype/JPypeSignal.java +++ b/native/java/org/jpype/JPypeSignal.java @@ -15,7 +15,6 @@ **************************************************************************** */ package org.jpype; -import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Proxy; @@ -31,6 +30,17 @@ public class JPypeSignal static Thread main; + static Object getSignalHandler(Class signalHandlerClazz, int signal) throws ClassNotFoundException { + return Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[] + { + signalHandlerClazz + }, (proxy, method, args) -> { + main.interrupt(); + interruptPy(signal); + return null; + }); + } + static void installHandlers() { try @@ -39,28 +49,17 @@ static void installHandlers() Class SignalHandler = Class.forName("sun.misc.SignalHandler"); main = Thread.currentThread(); Method method = Signal.getMethod("handle", Signal, SignalHandler); - - Object handler = Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[] - { - SignalHandler - }, new InvocationHandler() - { - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable - { - main.interrupt(); - interruptPy(); - return null; - } - }); Object intr = Signal.getDeclaredConstructor(String.class).newInstance("INT"); - method.invoke(null, intr, handler); + method.invoke(null, intr, getSignalHandler(SignalHandler, 2)); + Object intrTerm = Signal.getDeclaredConstructor(String.class).newInstance("TERM"); + method.invoke(null, intrTerm, getSignalHandler(SignalHandler, 15)); } catch (InvocationTargetException | IllegalArgumentException | IllegalAccessException | InstantiationException | ClassNotFoundException | NoSuchMethodException | SecurityException ex) { // If we don't get the signal handler run without it. (ANDROID) } } - native static void interruptPy(); + native static void interruptPy(int signal); + native static void acknowledgePy(); } diff --git a/pyproject.toml b/pyproject.toml index a4136135d..80397a78d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,15 +6,16 @@ build-backend = "setuptools.build_meta" [project] -name = "jpype1" -version = '1.5.2.dev0' +name = "jpype1-ext" +version = '0.0.2' authors = [ {name = "Steve Menard", email = "devilwolf@users.sourceforge.net"}, ] maintainers = [ {name = "Luis Nell", email = "cooperate@originell.org"}, + {name = "LocalStack Contributors", email = "info@localstack.cloud"}, ] -description = "A Python to Java bridge" +description = "A Python to Java bridge - ext" readme = "README.rst" requires-python = ">=3.8" license = {text = "License :: OSI Approved :: Apache Software License"} @@ -52,7 +53,7 @@ tests = [ [project.urls] -homepage = "https://github.com/jpype-project/jpype" +homepage = "https://github.com/localstack/jpype" [[tool.mypy.overrides]]