Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
29 changes: 29 additions & 0 deletions .github/workflows/compatibility.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: Gradle and Java compatibility

on:
push:
pull_request:
workflow_dispatch:

permissions:
contents: read

jobs:
compatibility:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
java: ['11', '14', '15', '24']
name: Java ${{ matrix.java }} / Gradle 8.14.6
steps:
- uses: actions/checkout@v7
with:
submodules: recursive
- uses: actions/setup-java@v6
with:
distribution: zulu
java-version: ${{ matrix.java }}
- uses: gradle/actions/setup-gradle@v6
- run: ./gradlew build compileSamplesKotlin dokka --console=plain
- run: ./template/gradlew -p template --include-build "$PWD" tasks --all --console=plain
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,6 @@ misc/

# Ignore Gradle build output directory
build

# Kotlin compiler cache
.kotlin
26 changes: 22 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,30 +217,39 @@ ftppass=password

To use SubKt you will need:

* A [recent version of the JDK](https://www.oracle.com/uk/java/technologies/javase-downloads.html)
* A [JDK](https://www.oracle.com/java/technologies/downloads/), Java 11–24 (tested on Java 11, 14, 15, and 24). The included wrapper downloads Gradle 8.14.6 automatically.
* [mkvmerge](https://mkvtoolnix.download/downloads.html)

Ensure that both `java` and `mkvmerge` are available on the PATH.
Instructions for setting the PATH for JDK 14 on Windows can be found [here](https://docs.oracle.com/en/java/javase/14/install/installation-jdk-microsoft-windows-platforms.html#GUID-96EB3876-8C7A-4A25-9F3A-A2983FEC016A).
Set `JAVA_HOME` to your JDK installation and add its `bin` directory to the PATH.
The same procedure can be used to add `mkvmerge` to the PATH; take note of where you installed/extracted it.

Download the [project template](https://github.com/Myaamori/SubKt/releases/download/0.1.19/subkt-template-0.1.19.zip) and place the files in the directory where you keep your project files.
Use the files in the [`template`](template) directory for new projects. Older release archives contain an obsolete Gradle wrapper and do not include this JDK upgrade.
Until this upgrade is released, use a local SubKt checkout as described below, passing `--include-build /absolute/path/to/SubKt` when running the template's wrapper.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note to maintainers: README will need to be updated (in several places) upon release.

After you have modified `build.gradle.kts` and `sub.properties` as needed, you can run tasks using `gradlew`.
For instance, to run the `mux` task for episode `03`, navigate to the same directory as the `build.gradle.kts` file in a terminal, and run `./gradlew mux.03`.
On Windows, simply run `gradlew mux.03` from `cmd.exe`.

**Note**: The first time you run `gradlew` may take some time as Gradle as well as all dependencies need to be downloaded.
Future runs will be much quicker.

## Working alongside older projects

The updated SubKt source and template use Gradle 8.14.6 on Java 11–24. Collaborators can run the same project's `gradlew` with different supported Java installations, without editing the wrapper configuration or installing another JDK. The wrapper downloads Gradle and verifies its SHA-256 checksum.

Keep older projects on their existing SubKt and wrapper versions. For an updated project, copy both launchers and the `gradle/wrapper` directory from the template and select the updated SubKt source. Until this upgrade is released, use `--include-build` as described below; the template's default `subktVersion=0.1.19` still selects the old release. Gradle 8.14.6 cannot run on Java 25 or newer.

## Building and using a local checkout

Initialize the bundled torrent library, then build with the installed JDK:

```sh
git submodule update --init --recursive
./gradlew build
./gradlew build compileSamplesKotlin
```

Build plugins come from the Gradle Plugin Portal and dependencies from Maven Central; JCenter is no longer used. Java and Kotlin compile to Java 11 bytecode without downloading a separate JDK. Kotlin dependencies match the host Gradle's embedded Kotlin runtime, and Kotlin language/API version 2.0 keeps the plugin readable by Gradle 8.14's Kotlin DSL compiler.

To use this checkout from the included template:

```sh
Expand All @@ -251,8 +260,17 @@ cd template

For a template copied elsewhere, pass `--include-build /absolute/path/to/SubKt`. Gradle substitutes the local checkout for the `myaa:subkt` dependency, including uncommitted changes. Keep `subktRepo` and `subktVersion` configured: without `--include-build`, they select the Git repository and version as usual.

Run `./gradlew dokka` to generate Markdown API documentation in `build/dokka/gfm`. The checked-in documentation is not overwritten.

Projects using FTPS with `sslSessionReuse` enabled also need the two `--add-opens` JVM arguments in the template's `gradle.properties`. They allow the existing session-reuse implementation to access the JDK's SSL session cache on Java 17+. Merge these arguments into any existing `org.gradle.jvmargs` setting.

The compatibility workflow builds the plugin and samples, runs the functional tests, generates documentation, and loads the template on Java 11, 14, 15, and 24. Select a supported JDK with `JAVA_HOME`, then run:

```sh
./gradlew build compileSamplesKotlin dokka
./template/gradlew -p template --include-build "$PWD" tasks --all
```

# Manual

A detailed description of the different tasks, functions and classes provided can be found in [the documentation](docs/subkt/index.md).
Expand Down
96 changes: 59 additions & 37 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import java.net.URI
import java.net.URL
import org.jetbrains.dokka.gradle.DokkaTask
import org.jetbrains.dokka.gradle.formats.DokkaFormatPlugin
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion

plugins {
kotlin("jvm") version "1.3.72"
kotlin("jvm") version "2.4.21"
`java-gradle-plugin`
id("org.jetbrains.dokka") version "0.9.18"
id("org.jetbrains.dokka") version "2.2.0"
}

gradlePlugin {
Expand Down Expand Up @@ -40,8 +41,9 @@ sourceSets {
}

dependencies {
implementation(kotlin("stdlib-jdk8", "1.3.72"))
implementation(kotlin("reflect", "1.3.72"))
// Use the host Gradle's Kotlin runtime, including 2.0.21 on Gradle 8.14.
implementation(kotlin("stdlib", embeddedKotlinVersion))
implementation(kotlin("reflect", embeddedKotlinVersion))
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7")
implementation(gradleApi())
implementation(gradleKotlinDsl())
Expand All @@ -61,46 +63,66 @@ dependencies {
implementation("commons-codec:commons-codec:1.14")

"samplesImplementation"(sourceSets["main"].output)
testImplementation(gradleTestKit())

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to add a blank line before the testImplementation dependencies to separate the different kinds of dependencies.

testImplementation(kotlin("test-junit", embeddedKotlinVersion))
}

tasks {
withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
kotlinOptions.jvmTarget = "1.8"
kotlinOptions.freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn"
// Keep the plugin usable on Java 11–16 with Gradle 8.14 as well as modern Gradle.
java {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}

kotlin {
compilerOptions {
jvmTarget.set(JvmTarget.JVM_11)
// Gradle 8.14's Kotlin DSL compiler must be able to read our metadata.
languageVersion.set(KotlinVersion.KOTLIN_2_0)
apiVersion.set(KotlinVersion.KOTLIN_2_0)
}
}

val dokka by getting(DokkaTask::class) {
outputFormat = "gfm"
outputDirectory = "docs"
tasks.withType<JavaCompile>().configureEach {
options.release.set(11)
}

// configuration {
noStdlibLink = false
noJdkLink = false
jdkVersion = 9
//platform = "JVM"
// Dokka v2 ships HTML/Javadoc formats; retain the existing Markdown output too.
abstract class DokkaGfmPlugin : DokkaFormatPlugin("gfm")
apply<DokkaGfmPlugin>()

includes = listOf("src/docs/markdown/packages.md")
samples = listOf("src/samples/kotlin/tasks.kt")
dependencies {
add("dokkaGfmPlugin", "org.jetbrains.dokka:gfm-plugin:2.2.0")
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit, but I’d rather have one of the following:

  1. Move the plugin declaration all the way up to immediately after the plugins block, and move the dependency line inside the existing dependencies block. This avoids having two blocks of dependencies.

  2. It seems this isn’t how the legacy Dokka format plugins are supposed to be registered at all. The way I see officially documented at https://github.com/Kotlin/dokka/blob/v2.2.0/dokka-subprojects/plugin-gfm/README.md is this monstrosity:

    // Dokka v2 ships HTML/Javadoc formats; retain the existing Markdown output too.
    @OptIn(InternalDokkaGradlePluginApi::class)
    abstract class DokkaGfmPlugin : DokkaFormatPlugin("gfm") {
        override fun DokkaFormatPlugin.DokkaFormatPluginContext.configure() {
            project.dependencies {
                dokkaPlugin(dokka("gfm-plugin"))
            }
        }
    }
    apply<DokkaGfmPlugin>()

    with an additional import org.jetbrains.dokka.gradle.internal.InternalDokkaGradlePluginApi

    (and with the add("dokkaGfmPlugin", "org.jetbrains.dokka:gfm-plugin:2.2.0") invocation removed).

    This avoids relying on knowledge of Dokka’s internal configuration and artifact naming (and removes an opportunity for an accidental version conflict), but then this explicitly taps into an “internal API”, so I’m guessing it’s gonna be potentially fragile either way. But at least this is suggested in the official readme, so maybe this will be more reliable or at least easier to adapt in the future if they do change the API? It might be a good idea to add a link to the readme from where this is sourced, too, so that any future changes can be more easily copied from the same source.

    For reference, it appears to me that this does something extra compared to the add("dokkaGfmPlugin"...) line, but I can’t tell if the extra actually matters at all.


externalDocumentationLink {
url = URL("https://docs.gradle.org/current/javadoc/")
dokka {
dokkaPublications.named("gfm") {
outputDirectory.set(layout.buildDirectory.dir("dokka/gfm"))
}
dokkaSourceSets.named("main") {
jdkVersion.set(11)
includes.from("src/docs/markdown/packages.md")
samples.from("src/samples/kotlin/tasks.kt")
externalDocumentationLinks.register("gradle") {
url.set(URI("https://docs.gradle.org/current/javadoc/"))
packageListUrl.set(URI("https://docs.gradle.org/current/javadoc/element-list"))
}

externalDocumentationLink {
url = URL("https://velocity.apache.org/engine/2.2/apidocs/")
externalDocumentationLinks.register("velocity") {
url.set(URI("https://velocity.apache.org/engine/2.2/apidocs/"))
}

packageOptions/*perPackageOption*/ {
prefix = "com.turn.ttorrent"
suppress = true
perPackageOption {
matchingRegex.set("com\\.turn\\.ttorrent.*")
suppress.set(true)
}

linkMapping {
// replace \ with / since only unix paths are allowed
dir = project.file("src/main/kotlin").absolutePath.replace('\\', '/')
url = "https://github.com/Myaamori/SubKt/blob/$version/src/main/kotlin"
suffix = "#L"
sourceLink {
localDirectory.set(file("src/main/kotlin"))
remoteUrl.set(URI("https://github.com/Myaamori/SubKt/blob/$version/src/main/kotlin"))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You may wanna update this URL to point to TypesettingTools/SubKt instead of Myaamori/SubKt while you’re at it.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By the way: all new build.gradle.kts code in your entire PR stack seems to use .set(...). If I understand correctly, simple assignment = works equally well. Simple assignment is visually simpler and more consistent with other code that remains in build.gradle.kts, so I’d prefer that to be used if it works.

remoteLineSuffix.set("#L")
}
// }
}
}
}

tasks.register("dokka") {
group = "documentation"
description = "Generates Markdown API documentation."
dependsOn("dokkaGeneratePublicationGfm")
}
1 change: 1 addition & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
org.gradle.warning.mode=all
org.jetbrains.dokka.experimental.gradle.pluginMode=V2Enabled
Binary file modified gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
5 changes: 4 additions & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip
distributionSha256Sum=7988ed071b2a07900e2ec715fca15c6ab72bce6db433af301fa7fa7e9407bd24
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.6-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Loading
Loading