Skip to content

Commit

Permalink
Merge pull request #48 from hexedtech/fix/java-ci
Browse files Browse the repository at this point in the history
ci: rewrite java ci
  • Loading branch information
zaaarf authored Oct 16, 2024
2 parents cda0584 + 3068773 commit d3e16a2
Show file tree
Hide file tree
Showing 10 changed files with 157 additions and 27 deletions.
28 changes: 21 additions & 7 deletions .github/workflows/java.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,30 +23,44 @@ jobs:
filename: codemp.dll
- runner: macos-14
target: darwin-arm64
filename: codemp.dylib
filename: libcodemp.dylib
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: arduino/setup-protoc@v3
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
- run: cargo build --release --features=java
- uses: actions/upload-artifact@v4
with:
name: codemp-java-${{ matrix.platform.target }}
path: target/release/${{ matrix.platform.filename }}

publish:
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
path: dist/java/artifacts
pattern: codemp-java-*
merge-multiple: true
- run: tree
working-directory: dist/java
- uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '11'
- uses: gradle/actions/setup-gradle@v4
with:
gradle-version: "8.10" # Quotes required to prevent YAML converting to number
- run: gradle build
gradle-version: "8.10"
working-directory: dist/java
- uses: actions/upload-artifact@v4
with:
name: codemp-java-${{ matrix.platform.target }}
path: dist/java/build/libs
- run: gradle publish
working-directory: dist/java
env:
ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.MAVEN_CENTRAL_USERNAME }}
ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.MAVEN_CENTRAL_PASSWORD }}
ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.MAVEN_CENTRAL_GPG_SECRET_KEY }}
ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.MAVEN_CENTRAL_GPG_PASSWORD }}

1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ dist/java/.gradle/
dist/java/.project
dist/java/.settings/
dist/java/bin/
dist/java/artifacts/

# intellij insists on creating the wrapper every time even if it's not strictly necessary
dist/java/gradle/
Expand Down
16 changes: 11 additions & 5 deletions dist/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,20 @@ Thus, we also provide pre-made Java glue code, wrapping all native calls and def

The Java bindings have no known major quirk. However, here are a list of facts that are useful to know when developing with these:

* Memory management is entirely delegated to the JVM's garbage collector.
* A more elegant solution than `Object.finalize()`, who is deprecated in newer Java versions, may be coming eventually.
* Memory management is entirely delegated to the JVM's garbage collector using the `Cleaner` API.
* Because of this, we require Java 11 as minimum version: `Cleaner` was added in version 9. This should not be a problem, as IDEs tend to run on recent versions, but if there is actual demand for it we may add a Java 8-friendly version using `Object.finalize()` (which is deprecated in modern JDKs).
* Exceptions coming from the native side have generally been made checked to imitate Rust's philosophy with `Result`.
* `JNIException`s are however unchecked: there is nothing you can do to recover from them, as they usually represent a severe error in the glue code. If they arise, it's probably a bug.

### Using
`codemp` **will be available soon** as an artifact on [Maven Central](https://mvnrepository.com)
`codemp` is available on [Maven Central](https://central.sonatype.com/artifact/mp.code/codemp), with each officially supported OS as an archive classifier.

### Building
This is a [Gradle](https://gradle.org/) project: building requires having both Gradle and Cargo installed, as well as the JDK (any non-abandoned version).
Once you have all the requirements, building is as simple as running `gradle build`: the output is going to be a JAR under `build/libs`, which you can import into your classpath with your IDE of choice.
> [!NOTE]
> The following instructions assume `dist/java` as current working directory.
This is a [Gradle](https://gradle.org/) project, so you must have install `gradle` (as well as JDK 11 or higher) in order to build it.
- You can build a JAR without bundling the native library with `gradle build`.
- Otherwise, you can compile the project for your current OS and create a JAR that bundles the resulting binary with `gradle nativeBuild`; do note that this second way of building also requires Cargo and the relevant Rust toolchain.

In both cases, the output is going to be a JAR under `build/libs`, which you can import into your classpath with your IDE of choice.
116 changes: 110 additions & 6 deletions dist/java/build.gradle
Original file line number Diff line number Diff line change
@@ -1,14 +1,104 @@
plugins {
id 'java-library'
id "com.vanniktech.maven.publish" version "0.29.0"
id "com.vanniktech.maven.publish.base" version "0.30.0"
id 'com.google.osdetector' version '1.7.3'
}

group = 'mp.code'
version = '0.7.3'

tasks.register('windowsJar', Jar) {
outputs.upToDateWhen { false }
archiveClassifier = 'windows-x86_64'
from sourceSets.main.runtimeClasspath
from('artifacts') {
include('*.dll')
into('natives/')
}
doFirst {
if(!(new File('artifacts/codemp.dll').exists())) {
throw new GradleException("The required file does not exist!")
}
}
}

tasks.register('macosJar', Jar) {
outputs.upToDateWhen { false }
archiveClassifier = 'osx-aarch_64'
from sourceSets.main.runtimeClasspath
from('artifacts') {
include('*.dylib')
into('natives/')
}
doFirst {
if(!(new File('artifacts/libcodemp.dylib').exists())) {
throw new GradleException("The required file does not exist!")
}
}
}

tasks.register('linuxJar', Jar) {
outputs.upToDateWhen { false }
archiveClassifier = 'linux-x86_64'
from sourceSets.main.runtimeClasspath
from('artifacts') {
include('*.so')
into('natives/')
}
doFirst {
if(!(new File('artifacts/libcodemp.so').exists())) {
throw new GradleException("The required file does not exist! Maybe you need to `cargo build` the main library first?")
}
}
}

tasks.register('multiplatformJar', Jar) {
outputs.upToDateWhen { false }
archiveClassifier = 'all'
from sourceSets.main.runtimeClasspath
from('artifacts') {
include('*')
into('natives/')
}
}

configurations {
windowsJar {
canBeConsumed = true
canBeResolved = false
extendsFrom implementation, runtimeOnly
}
linuxJar {
canBeConsumed = true
canBeResolved = false
extendsFrom implementation, runtimeOnly
}
macosJar {
canBeConsumed = true
canBeResolved = false
extendsFrom implementation, runtimeOnly
}
multiplatformJar {
canBeConsumed = true
canBeResolved = false
extendsFrom implementation, runtimeOnly
}
}

java {
sourceCompatibility = targetCompatibility = JavaVersion.VERSION_11
withSourcesJar()
withJavadocJar()
}

artifacts {
archives jar
archives sourcesJar
archives javadocJar
windowsJar(windowsJar)
macosJar(macosJar)
linuxJar(linuxJar)
multiplatformJar(multiplatformJar)
}

repositories {
Expand All @@ -29,17 +119,17 @@ tasks.register('cargoBuild', Exec) {
commandLine 'cargo', 'build', '--release', '--features=java'
}

jar.archiveClassifier = osdetector.classifier

def rustDir = projectDir.toPath()
.parent
.parent
.resolve('target')
.resolve('release')
.toFile()
processResources {

tasks.register('nativeBuild', Jar) {
archiveClassifier = osdetector.classifier
dependsOn cargoBuild
outputs.upToDateWhen { false } // no caching
from sourceSets.main.runtimeClasspath
from(rustDir) {
include('*.dll')
include('*.so')
Expand All @@ -48,9 +138,23 @@ processResources {
}
}

publishing {
publications {
mavenJava(MavenPublication) {
artifact jar
artifact sourcesJar
artifact javadocJar
artifact windowsJar
artifact linuxJar
artifact macosJar
artifact multiplatformJar
}
}
}

import com.vanniktech.maven.publish.SonatypeHost
mavenPublishing {
publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL, true)
publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL, true)
signAllPublications()
coordinates(project.group, rootProject.name, project.version)

Expand Down
3 changes: 3 additions & 0 deletions dist/java/src/mp/code/BufferController.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ public BufferUpdate recv() throws ControllerException {

/**
* Tries to send a {@link TextChange} update.
* @param change the update to send
* @throws ControllerException if the controller was stopped
*/
public void send(TextChange change) throws ControllerException {
Expand All @@ -81,6 +82,8 @@ public void send(TextChange change) throws ControllerException {
/**
* Registers a callback to be invoked whenever a {@link BufferUpdate} occurs.
* This will not work unless a Java thread has been dedicated to the event loop.
* @param cb a {@link Consumer} that receives the controller when the change occurs;
* you should probably spawn a new thread in here, to avoid deadlocking
* @see Extensions#drive(boolean)
*/
public void callback(Consumer<BufferController> cb) {
Expand Down
9 changes: 6 additions & 3 deletions dist/java/src/mp/code/CursorController.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,21 +43,24 @@ public Cursor recv() throws ControllerException {
return recv(this.ptr);
}

private static native void send(long self, Selection cursor) throws ControllerException;
private static native void send(long self, Selection selection) throws ControllerException;

/**
* Tries to send a {@link Selection} update.
* @param selection the update to send
* @throws ControllerException if the controller was stopped
*/
public void send(Selection cursor) throws ControllerException {
send(this.ptr, cursor);
public void send(Selection selection) throws ControllerException {
send(this.ptr, selection);
}

private static native void callback(long self, Consumer<CursorController> cb);

/**
* Registers a callback to be invoked whenever a {@link Cursor} update occurs.
* This will not work unless a Java thread has been dedicated to the event loop.
* @param cb a {@link Consumer} that receives the controller when the change occurs;
* you should probably spawn a new thread in here, to avoid deadlocking
* @see Extensions#drive(boolean)
*/
public void callback(Consumer<CursorController> cb) {
Expand Down
2 changes: 1 addition & 1 deletion dist/java/src/mp/code/Extensions.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public final class Extensions {
* <p>
* You may alternatively call this with true, in a separate and dedicated Java thread;
* it will remain active in the background and act as event loop. Assign it like this:
* <p><code>new Thread(() -> Extensions.drive(true)).start();</code></p>
* <p><code>new Thread(() -&gt; Extensions.drive(true)).start();</code></p>
* @param block true if it should use the current thread
*/
public static native void drive(boolean block);
Expand Down
2 changes: 2 additions & 0 deletions dist/java/src/mp/code/Workspace.java
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,8 @@ public Event recv() throws ControllerException {
/**
* Registers a callback to be invoked whenever a new {@link Event} is ready to be received.
* This will not work unless a Java thread has been dedicated to the event loop.
* @param cb a {@link Consumer} that receives the controller when the change occurs;
* you should probably spawn a new thread in here, to avoid deadlocking
* @see Extensions#drive(boolean)
*/
public void callback(Consumer<Workspace> cb) {
Expand Down
3 changes: 0 additions & 3 deletions dist/java/src/mp/code/data/TextChange.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@
import lombok.EqualsAndHashCode;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
import mp.code.Extensions;

import java.util.OptionalLong;

/**
* A data class holding information about a text change.
Expand Down
4 changes: 2 additions & 2 deletions dist/java/src/mp/code/exceptions/ControllerException.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

/**
* An exception that may occur when a {@link mp.code.BufferController} or
* a {@link mp.code.CursorController} perform an illegal operation.
* It may also occur as a result of {@link mp.code.Workspace#event()}.
* a {@link mp.code.CursorController} or {@link mp.code.Workspace} (in the
* receiver part) perform an illegal operation.
*/
public abstract class ControllerException extends Exception {

Expand Down

0 comments on commit d3e16a2

Please sign in to comment.