mlt-ffi 0.2.2

Diplomat FFI bindings for mlt-core
Documentation
plugins {
    id 'java-library'
    id 'com.vanniktech.maven.publish' version '0.36.0'
}

repositories {
    mavenCentral()
}

dependencies {
    // Nullness annotations only, so consumers need no runtime jar.
    compileOnlyApi 'org.jspecify:jspecify:1.0.0'
    testImplementation platform('org.junit:junit-bom:6.0.3')
    testImplementation 'org.junit.jupiter:junit-jupiter'
    // Planetiler's MVT command encoder, without the dependencies of the rest of planetiler-core.
    testImplementation('com.onthegomap.planetiler:planetiler-core:0.10.2') { transitive = false }
    testImplementation 'org.locationtech.jts:jts-core:1.20.0'
    testImplementation 'com.carrotsearch:hppc:0.10.0'
    testImplementation 'com.google.protobuf:protobuf-java:4.34.1'
    testImplementation 'org.slf4j:slf4j-api:2.0.17'
    testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}

// java.lang.foreign is final from Java 22.
java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(25)
    }
}

tasks.withType(JavaCompile).configureEach {
    options.release = 22
}

sourceSets {
    test {
        java {
            srcDirs = ['../../tests/java']
        }
    }
}

// raw is left to the compiled classes, so its sources are not documented.
javadoc {
    exclude 'org/maplibre/mlt/ffi/raw/**'
    options.addBooleanOption('Xdoclint:none', true)
    options.addStringOption('-patch-module', "org.maplibre.mlt.ffi=${sourceSets.main.output.classesDirs.asPath}")
}

test {
    useJUnitPlatform()
    // The native library comes from build/resources/main, like it does for consumers.
    jvmArgs '--enable-native-access=ALL-UNNAMED'
    testLogging {
        events 'passed', 'skipped', 'failed'
        exceptionFormat = 'full'
        showStandardStreams = true
    }
}

// Natives arrive as build/natives/<ci-classifier>/<lib>. mlt-ffi-kotlin packs the same prefixes at the jar root, so these move below the package.
def resourcePrefix(String classifier) {
    switch (classifier) {
        case 'linux-x86_64':       return 'linux-x86-64'
        case 'linux-x86_64-musl':  return 'linux-x86-64-musl'
        case 'linux-aarch64':      return 'linux-aarch64'
        case 'linux-aarch64-musl': return 'linux-aarch64-musl'
        case 'macos-aarch64':      return 'darwin-aarch64'
        case 'macos-x86_64':       return 'darwin-x86-64'
        case 'freebsd-x86_64':     return 'freebsd-x86-64'
        case 'windows-x86_64':     return 'win32-x86-64'
        case 'windows-aarch64':    return 'win32-aarch64'
        default: throw new GradleException("Unknown native classifier: ${classifier}")
    }
}

processResources {
    from(layout.buildDirectory.dir('natives')) {
        eachFile { details ->
            def segments = details.relativePath.segments
            if (segments.length < 2) {
                details.exclude()
                return
            }
            details.path = 'org/maplibre/mlt/ffi/native/' + resourcePrefix(segments[0]) + '/' + segments[-1]
        }
        includeEmptyDirs = false
    }
}

tasks.register('validateSemver') {
    doLast {
        def v = project.version?.toString()
        if (v == null || v == 'unspecified') {
            throw new GradleException("Version is not set. Provide one with -Pversion=<major.minor.patch>")
        }
        if (!v.matches(/^\d+\.\d+\.\d+$/)) {
            throw new GradleException("Version '${v}' is not a valid semantic version. Expected major.minor.patch")
        }
    }
}

mavenPublishing {
    publishToMavenCentral(true)
    signAllPublications()

    coordinates('org.maplibre', 'mlt-ffi-java', version)

    publishToMavenCentral.dependsOn validateSemver

    pom {
        name = 'MapLibre Tile FFI (Java)'
        description = 'Java bindings for the MapLibre Tile (MLT) FFI using java.lang.foreign'
        url = 'https://github.com/maplibre/maplibre-tile-spec'

        licenses {
            license {
                name = 'The Apache License, Version 2.0'
                url = 'https://www.apache.org/licenses/LICENSE-2.0.txt'
            }
        }

        developers {
            developer {
                id = 'maplibre'
                name = 'MapLibre contributors'
                url = 'https://github.com/maplibre'
            }
        }

        scm {
            connection = 'scm:git:git://github.com/maplibre/maplibre-tile-spec.git'
            developerConnection = 'scm:git:ssh://github.com:maplibre/maplibre-tile-spec.git'
            url = 'https://github.com/maplibre/maplibre-tile-spec'
        }
    }
}

// Sign only when CI supplies ORG_GRADLE_PROJECT_signingInMemoryKey, so mavenLocal installs skip it.
tasks.withType(Sign).configureEach {
    onlyIf { project.hasProperty('signingInMemoryKey') }
}