From 932f690610ef76b3880b31a84ec632e5e88b629f Mon Sep 17 00:00:00 2001 From: Tad Fisher Date: Sun, 31 Mar 2019 20:18:55 -0700 Subject: [PATCH] First stab --- .gitignore | 5 + app/build.gradle.kts | 45 + app/src/dist/gradle/init.gradle | 7 + .../org/nixos/gradle2nix/GradleRunner.kt | 45 + .../main/kotlin/org/nixos/gradle2nix/Main.kt | 25 + build.gradle.kts | 10 + default.nix | 71 + gradle-env.nix | 51 + gradle/nix/gradle-dist.json | 7 + gradle/nix/gradle-env.json | 1732 +++++++++++++++++ gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 55741 bytes gradle/wrapper/gradle-wrapper.properties | 5 + gradlew | 172 ++ gradlew.bat | 84 + plugin/build.gradle.kts | 34 + .../org/nixos/gradle2nix/Gradle2NixPlugin.kt | 137 ++ .../org/nixos/gradle2nix/NixBuildscriptEnv.kt | 43 + .../kotlin/org/nixos/gradle2nix/NixEnv.kt | 73 + .../org/nixos/gradle2nix/NixGradleDist.kt | 44 + .../org/nixos/gradle2nix/NixGradleEnv.kt | 58 + .../org/nixos/gradle2nix/NixPluginEnv.kt | 110 ++ .../org/nixos/gradle2nix/NixProjectEnv.kt | 41 + .../kotlin/org/nixos/gradle2nix/Resolver.kt | 166 ++ plugin/src/main/resources/gradle-env.nix | 51 + settings.gradle.kts | 2 + 25 files changed, 3018 insertions(+) create mode 100644 .gitignore create mode 100644 app/build.gradle.kts create mode 100644 app/src/dist/gradle/init.gradle create mode 100644 app/src/main/kotlin/org/nixos/gradle2nix/GradleRunner.kt create mode 100644 app/src/main/kotlin/org/nixos/gradle2nix/Main.kt create mode 100644 build.gradle.kts create mode 100644 default.nix create mode 100644 gradle-env.nix create mode 100644 gradle/nix/gradle-dist.json create mode 100644 gradle/nix/gradle-env.json create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100755 gradlew create mode 100644 gradlew.bat create mode 100644 plugin/build.gradle.kts create mode 100644 plugin/src/main/kotlin/org/nixos/gradle2nix/Gradle2NixPlugin.kt create mode 100644 plugin/src/main/kotlin/org/nixos/gradle2nix/NixBuildscriptEnv.kt create mode 100644 plugin/src/main/kotlin/org/nixos/gradle2nix/NixEnv.kt create mode 100644 plugin/src/main/kotlin/org/nixos/gradle2nix/NixGradleDist.kt create mode 100644 plugin/src/main/kotlin/org/nixos/gradle2nix/NixGradleEnv.kt create mode 100644 plugin/src/main/kotlin/org/nixos/gradle2nix/NixPluginEnv.kt create mode 100644 plugin/src/main/kotlin/org/nixos/gradle2nix/NixProjectEnv.kt create mode 100644 plugin/src/main/kotlin/org/nixos/gradle2nix/Resolver.kt create mode 100644 plugin/src/main/resources/gradle-env.nix create mode 100644 settings.gradle.kts diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..80d269a --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.idea/ +.gradle/ +*.iml +**/build/ +result \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100644 index 0000000..ce74a90 --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,45 @@ +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +plugins { + kotlin("jvm") version "1.3.21" + application +} + +group = "org.nixos" +version = "1.0.0-SNAPSHOT" + +application { + mainClassName = "org.nixos.gradle2nix.MainKt" + applicationName = "gradle2nix" + applicationDefaultJvmArgs += "-Dorg.nixos.gradle2nix.initScript=@APP_HOME@/gradle/init.gradle" + applicationDistribution + .from(tasks.getByPath(":plugin:shadowJar")) + .into("gradle") + .rename("plugin.*\\.jar", "plugin.jar") +} + +dependencies { + implementation(kotlin("stdlib-jdk8")) + implementation("org.gradle:gradle-tooling-api:${gradle.gradleVersion}") + implementation("com.github.ajalt:clikt:1.7.0") +} + +repositories { + jcenter() + maven { url = uri("https://repo.gradle.org/gradle/libs-releases") } +} + +tasks { + val startScripts by existing(CreateStartScripts::class) + startScripts { + doLast { + unixScript.writeText(unixScript.readText().replace("@APP_HOME@", "\$APP_HOME")) + windowsScript.writeText(windowsScript.readText().replace("@APP_HOME@", "%APP_HOME%")) + } + } + withType { + kotlinOptions { + jvmTarget = "1.8" + } + } +} diff --git a/app/src/dist/gradle/init.gradle b/app/src/dist/gradle/init.gradle new file mode 100644 index 0000000..f0c230f --- /dev/null +++ b/app/src/dist/gradle/init.gradle @@ -0,0 +1,7 @@ +initscript { + dependencies { + classpath files("plugin.jar") + } +} + +apply plugin: org.nixos.gradle2nix.Gradle2NixPlugin diff --git a/app/src/main/kotlin/org/nixos/gradle2nix/GradleRunner.kt b/app/src/main/kotlin/org/nixos/gradle2nix/GradleRunner.kt new file mode 100644 index 0000000..57ecc51 --- /dev/null +++ b/app/src/main/kotlin/org/nixos/gradle2nix/GradleRunner.kt @@ -0,0 +1,45 @@ +package org.nixos.gradle2nix + +import org.gradle.tooling.GradleConnector +import java.io.File + +class GradleRunner( + private val projectDir: File, + private val useWrapper: Boolean, + private val gradleVersion: String?, + private val configurations: List +) { + companion object { + val initScript: String = System.getProperty("org.nixos.gradle2nix.initScript") + } + + fun runGradle() { + GradleConnector.newConnector() + .apply { + if (useWrapper) { + useBuildDistribution() + } else if (gradleVersion != null) { + useGradleVersion(gradleVersion) + } + } + .forProjectDirectory(projectDir) + .connect() + .use { connection -> + connection.newBuild() + .withArguments("--init-script", initScript) + .apply { + if (configurations.isNotEmpty()) { + withArguments( + "-Dorg.nixos.gradle2nix.configurations=${configurations.joinToString( + "," + )}" + ) + } + } + .forTasks("nixGradleEnv") + .setStandardOutput(System.out) + .setStandardError(System.err) + .run() + } + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/org/nixos/gradle2nix/Main.kt b/app/src/main/kotlin/org/nixos/gradle2nix/Main.kt new file mode 100644 index 0000000..754ab73 --- /dev/null +++ b/app/src/main/kotlin/org/nixos/gradle2nix/Main.kt @@ -0,0 +1,25 @@ +package org.nixos.gradle2nix + +import com.github.ajalt.clikt.core.CliktCommand +import com.github.ajalt.clikt.parameters.arguments.argument +import com.github.ajalt.clikt.parameters.arguments.defaultLazy +import com.github.ajalt.clikt.parameters.options.flag +import com.github.ajalt.clikt.parameters.options.multiple +import com.github.ajalt.clikt.parameters.options.option +import com.github.ajalt.clikt.parameters.types.file +import java.io.File + +class Main : CliktCommand() { + val wrapper: Boolean by option(help = "Use the project's gradle wrapper for building").flag() + val gradleVersion: String? by option(help = "Use a specific Gradle version") + val configurations: List by option(help = "Project configuration(s)").multiple() + val projectDir: File by argument(help = "Path to the project root") + .file(exists = true, fileOkay = false, folderOkay = true, readable = true) + .defaultLazy { File(".") } + + override fun run() { + GradleRunner(projectDir, wrapper, gradleVersion, configurations).runGradle() + } +} + +fun main(args: Array) = Main().main(args) \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000..c0532f4 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,10 @@ +plugins { + base +} + +tasks { + wrapper { + gradleVersion = "5.3" + distributionType = Wrapper.DistributionType.ALL + } +} diff --git a/default.nix b/default.nix new file mode 100644 index 0000000..a4885b0 --- /dev/null +++ b/default.nix @@ -0,0 +1,71 @@ +{ pkgs ? import {} }: + +with pkgs; + +let + gradleEnvJson = builtins.fromJSON (builtins.readFile ./gradle/nix/gradle-env.json); + gradleDist = builtins.fromJSON (builtins.readFile ./gradle/nix/gradle-dist.json); + + mkGradleEnv = callPackage ./gradle-env.nix {}; + gradle = pkgs.gradleGen.gradleGen { + name = "gradle-dist-${gradleDist.version}-${gradleDist.type}"; + src = pkgs.fetchurl { + inherit (gradleDist) url sha256; + }; + inherit (gradleDist) nativeVersion; + }; + + maven = r: ''maven { url = uri("${r}") }''; + + projects = lib.mapAttrsToList (path: envs: { + inherit path; + config = '' + buildscript { + repositories { + clear() + ${maven (mkGradleEnv envs.buildscript)} + } + } + repositories { + clear() + ${maven (mkGradleEnv envs.project)} + } + ''; + }) gradleEnvJson; + + initScript = pkgs.writeText "init.gradle" '' + gradle.settingsEvaluated { + it.pluginManagement.repositories { + clear() + ${maven (mkGradleEnv gradleEnvJson.":".plugins)} + } + } + gradle.projectsLoaded { + ${lib.concatMapStringsSep "\n" (p: '' + rootProject.project("${p.path}") { + ${p.config} + } + '') projects} + } + ''; + +in stdenv.mkDerivation rec { + name = "gradle2nix-${version}"; + version = "1.0"; + + src = ./.; + + nativeBuildInputs = [ gradle ]; + + buildPhase = '' + export GRADLE_USER_HOME=$(mktemp -d) + gradle --offline --no-daemon --info --full-stacktrace --init-script ${initScript} installDist + ''; + + installPhase = '' + mkdir -p $out + cp -r app/build/install/gradle2nix/* $out/ + ''; + + dontStrip = true; +} diff --git a/gradle-env.nix b/gradle-env.nix new file mode 100644 index 0000000..771d2cf --- /dev/null +++ b/gradle-env.nix @@ -0,0 +1,51 @@ +# This file is generated by gradle2nix. + +{ stdenvNoCC, lib, buildEnv, fetchurl }: + +{ path, env, repositories, artifacts }@args: + +let + mkPath = artifact: with artifact; lib.concatStringsSep "/" [ + (lib.replaceChars ["."] ["/"] artifact.groupId) + artifact.artifactId + artifact.version + ]; + + mkFilename = artifact: with artifact; + "${artifactId}-${version}${lib.optionalString (classifier != "") "-${classifier}"}.${extension}"; + + mkArtifactUrl = base: artifact: + "${lib.removeSuffix "/" base}/${mkPath artifact}/${mkFilename artifact}"; + + fetchArtifact = artifact: + let + artifactPath = mkPath artifact; + artifactName = mkFilename artifact; + in stdenvNoCC.mkDerivation rec { + name = with artifact; lib.concatStrings [ + (lib.replaceChars ["."] ["_"] groupId) "-" + (lib.replaceChars ["."] ["_"] artifactId) "-" + version + (lib.optionalString (classifier != "") "-${classifier}") + "-" extension + ]; + + src = fetchurl { + name = mkFilename artifact; + urls = map (url: mkArtifactUrl url artifact) repositories; + inherit (artifact) sha256; + }; + + phases = "installPhase fixupPhase"; + + installPhase = '' + mkdir -p $out/${artifactPath} + ln -s ${src} $out/${artifactPath}/${artifactName} + ''; + }; + +in +buildEnv { + name = "gradle-env-${builtins.replaceStrings [":"] ["-"] path}-${env}"; + paths = map fetchArtifact artifacts; +} diff --git a/gradle/nix/gradle-dist.json b/gradle/nix/gradle-dist.json new file mode 100644 index 0000000..ad2b370 --- /dev/null +++ b/gradle/nix/gradle-dist.json @@ -0,0 +1,7 @@ +{ + "version": "5.3", + "type": "all", + "url": "https://services.gradle.org/distributions/gradle-5.3-all.zip", + "sha256": "f4d820c2a9685710eba5b92f10e0e4fb20e0d6c0dd1f46971e658160f25e7147", + "nativeVersion": "0.17" +} \ No newline at end of file diff --git a/gradle/nix/gradle-env.json b/gradle/nix/gradle-env.json new file mode 100644 index 0000000..935b3aa --- /dev/null +++ b/gradle/nix/gradle-env.json @@ -0,0 +1,1732 @@ +{ + ":": { + "plugins": { + "path": ":", + "env": "plugins", + "repositories": [ + "https://plugins.gradle.org/m2" + ], + "artifacts": [ + { + "groupId": "com.github.jengelman.gradle.plugins", + "artifactId": "shadow", + "version": "4.0.0", + "classifier": "", + "extension": "jar", + "sha256": "cXwxDqo6FVM7Xq6mfLe4AdpE9yIv94v8+ez151VOHnc=" + }, + { + "groupId": "com.github.jengelman.gradle.plugins", + "artifactId": "shadow", + "version": "4.0.0", + "classifier": "", + "extension": "pom", + "sha256": "BX4poPG89L1LDAAiJP806YtZMsulREwz4ieYr2ILzuQ=" + }, + { + "groupId": "com.github.johnrengelman.shadow", + "artifactId": "com.github.johnrengelman.shadow.gradle.plugin", + "version": "4.0.0", + "classifier": "", + "extension": "pom", + "sha256": "nm10H2Q75H9lAIKNT2P4vN8tYyLUnYA0G+K56SC63Kg=" + }, + { + "groupId": "commons-io", + "artifactId": "commons-io", + "version": "2.6", + "classifier": "", + "extension": "jar", + "sha256": "+HfTBGYKwqFC84ZbrfyXHex+1zx0fH+NXS9ROcpzZRM=" + }, + { + "groupId": "commons-io", + "artifactId": "commons-io", + "version": "2.6", + "classifier": "", + "extension": "pom", + "sha256": "DCOGOJOiKR9aev29jRWSOzlIr9h+Vj+jQc3Pbq4zimA=" + }, + { + "groupId": "org.apache.ant", + "artifactId": "ant-launcher", + "version": "1.9.7", + "classifier": "", + "extension": "jar", + "sha256": "vDdvbWy1hiKfRRrEWfrxRDsUTCbWZHYY7Jy6YOVMK3k=" + }, + { + "groupId": "org.apache.ant", + "artifactId": "ant-launcher", + "version": "1.9.7", + "classifier": "", + "extension": "pom", + "sha256": "17zdOrD/Ve2+G5bQbwbawhNexjtafDLO86Q2tJye7ic=" + }, + { + "groupId": "org.apache.ant", + "artifactId": "ant-parent", + "version": "1.9.7", + "classifier": "", + "extension": "pom", + "sha256": "ddLO9kxlzL3S+vcmHlO0RHeNVtM4djFU4w+tpKQdEhU=" + }, + { + "groupId": "org.apache.ant", + "artifactId": "ant", + "version": "1.9.7", + "classifier": "", + "extension": "jar", + "sha256": "ml2+P18suRhUyGgsq4AXivpBKrNaWrcYvznOAbNDXZM=" + }, + { + "groupId": "org.apache.ant", + "artifactId": "ant", + "version": "1.9.7", + "classifier": "", + "extension": "pom", + "sha256": "G5+9TzJacembJ5CA1jCE8S2ITUIIGvKY+eVT4f4M10o=" + }, + { + "groupId": "org.apache.commons", + "artifactId": "commons-parent", + "version": "42", + "classifier": "", + "extension": "pom", + "sha256": "zTE0lMZwtIPsJWlyrxaYszDlmPgHACNU63ZUefYEsJw=" + }, + { + "groupId": "org.apache.logging.log4j", + "artifactId": "log4j-api", + "version": "2.11.0", + "classifier": "", + "extension": "jar", + "sha256": "+lgolQJpsK5CXJbYifGPQLM26fqIaEGuBruSJVEfEhc=" + }, + { + "groupId": "org.apache.logging.log4j", + "artifactId": "log4j-api", + "version": "2.11.0", + "classifier": "", + "extension": "pom", + "sha256": "Bcwtp3otDyS0gDy/641kog9UlNCTobzXhy/iiqOQadk=" + }, + { + "groupId": "org.apache.logging.log4j", + "artifactId": "log4j-core", + "version": "2.11.0", + "classifier": "", + "extension": "jar", + "sha256": "wyApsy2j2M8v7KB5CkvCMx6n62KrNoqJgLkMfYyBAeA=" + }, + { + "groupId": "org.apache.logging.log4j", + "artifactId": "log4j-core", + "version": "2.11.0", + "classifier": "", + "extension": "pom", + "sha256": "1WKcz1cr6lcZLPjHXXTn6gWmk8Qu1xJkf67Zrp+/OIA=" + }, + { + "groupId": "org.apache.logging.log4j", + "artifactId": "log4j", + "version": "2.11.0", + "classifier": "", + "extension": "pom", + "sha256": "x4aYPHv6lQoCMbnPwrwrU3ATTALBHg9X2FZggqiDhvM=" + }, + { + "groupId": "org.apache.logging", + "artifactId": "logging-parent", + "version": "1", + "classifier": "", + "extension": "pom", + "sha256": "NLK/T1MagJFolhZy/0GdGr+WcluN/lKYDwDIxOsTS9Y=" + }, + { + "groupId": "org.apache", + "artifactId": "apache", + "version": "18", + "classifier": "", + "extension": "pom", + "sha256": "eDEwcoX9R1u8NrIK4454gvEcMVOx1ZMPhS1E7ajzPBc=" + }, + { + "groupId": "org.codehaus.plexus", + "artifactId": "plexus-utils", + "version": "3.0.24", + "classifier": "", + "extension": "jar", + "sha256": "g+50ixLQavsK1AUKWREys+gCX7sZkPHtAC6Lcyk+abQ=" + }, + { + "groupId": "org.codehaus.plexus", + "artifactId": "plexus-utils", + "version": "3.0.24", + "classifier": "", + "extension": "pom", + "sha256": "EQZ/anX97RK83I2vembd2ULOKJw9r4ij/g+LEoWKLuY=" + }, + { + "groupId": "org.codehaus.plexus", + "artifactId": "plexus", + "version": "4.0", + "classifier": "", + "extension": "pom", + "sha256": "ChtpLX/MkNakXa4uUPRmDUj3pEUE8XSqYO80++Eyf2o=" + }, + { + "groupId": "org.gradle.kotlin.kotlin-dsl", + "artifactId": "org.gradle.kotlin.kotlin-dsl.gradle.plugin", + "version": "1.2.5", + "classifier": "", + "extension": "pom", + "sha256": "/GETYUcM9nxmg0F/yZVoeaSWprC5j11s+zDG7OC1U4c=" + }, + { + "groupId": "org.gradle.kotlin", + "artifactId": "plugins", + "version": "1.2.5", + "classifier": "", + "extension": "jar", + "sha256": "hpQRbr0r/B1RZSpG75KTzxO+cX45Br5+5oKg+NZjIiw=" + }, + { + "groupId": "org.gradle.kotlin", + "artifactId": "plugins", + "version": "1.2.5", + "classifier": "", + "extension": "pom", + "sha256": "kEkRngpBhZfla6pdjhwTC0oTukscJuf8flnlt47lSuM=" + }, + { + "groupId": "org.jdom", + "artifactId": "jdom2", + "version": "2.0.6", + "classifier": "", + "extension": "jar", + "sha256": "E0XxG6YG0VYD1nQFUajCGUfAIVZAdw7GcnH+eL6pfPU=" + }, + { + "groupId": "org.jdom", + "artifactId": "jdom2", + "version": "2.0.6", + "classifier": "", + "extension": "pom", + "sha256": "R7I6ef4za3QbgkNMbgSdaBZSVuQF51wQkh/XL6imXY0=" + }, + { + "groupId": "org.jetbrains.intellij.deps", + "artifactId": "trove4j", + "version": "1.0.20181211", + "classifier": "", + "extension": "jar", + "sha256": "r/t8haPIe9z2n/HbuE3hH2PckxKTk0vAjNerGN4INgE=" + }, + { + "groupId": "org.jetbrains.intellij.deps", + "artifactId": "trove4j", + "version": "1.0.20181211", + "classifier": "", + "extension": "pom", + "sha256": "MQpqotkFNMMrj0bx/JjNDtrpXc38oj4oR+Xvqa4MAZo=" + }, + { + "groupId": "org.jetbrains.kotlin.jvm", + "artifactId": "org.jetbrains.kotlin.jvm.gradle.plugin", + "version": "1.3.21", + "classifier": "", + "extension": "pom", + "sha256": "8VCZqLaNedv5VVciEMDiCYt8iQEVKcPC5bln4VO9LEQ=" + }, + { + "groupId": "org.jetbrains.kotlin.kapt", + "artifactId": "org.jetbrains.kotlin.kapt.gradle.plugin", + "version": "1.3.21", + "classifier": "", + "extension": "pom", + "sha256": "TSKA8Hh+kGwH5V7vznjf+QM8rgX3GMGbZcYz5ntr2fw=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-android-extensions", + "version": "1.3.21", + "classifier": "", + "extension": "jar", + "sha256": "KwRirD5LNt/9s7+mFzy0Gw4k4lp9fu4QEkcfHSeuot0=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-android-extensions", + "version": "1.3.21", + "classifier": "", + "extension": "pom", + "sha256": "9jEKsCDHAlW7h+XUsHXCn67+ODhWtgQctTQ79ChdwVo=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-annotation-processing-gradle", + "version": "1.3.21", + "classifier": "", + "extension": "jar", + "sha256": "+viAMV1P1qZmzBeqXpYIx0aMcKJ5tJzMpn26KlSt9pI=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-annotation-processing-gradle", + "version": "1.3.21", + "classifier": "", + "extension": "pom", + "sha256": "9X3OxdUN+KLeVw86yJcYidSUPyuqyogUACoudn0L6Mk=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-build-common", + "version": "1.3.21", + "classifier": "", + "extension": "jar", + "sha256": "9NjQjG9ZZtnVF87WDFIkx+3KLYEeoKcCvXGZoA3U+iU=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-build-common", + "version": "1.3.21", + "classifier": "", + "extension": "pom", + "sha256": "wmwuwUIkyn+halRUOik6ll74dzTLc2TF6MEennnJjS4=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-compiler-embeddable", + "version": "1.3.21", + "classifier": "", + "extension": "jar", + "sha256": "r6rtwyT79jlNnzlUTvzJPPxZ+KWqGhpccdYeJINmbGo=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-compiler-embeddable", + "version": "1.3.21", + "classifier": "", + "extension": "pom", + "sha256": "Uyu5QViDU4ZwPnZUMH56w2ccCUfZZWGs2quaC3Lp30Q=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-compiler-runner", + "version": "1.3.21", + "classifier": "", + "extension": "jar", + "sha256": "c+cIigdPnFF81LsqhhGDQWhFlmHIMhNs82KMzVmUzDs=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-compiler-runner", + "version": "1.3.21", + "classifier": "", + "extension": "pom", + "sha256": "KB9vwpwuA5E5mJrjZBv4aDS3URFJ/e5l2NkICOwn4oM=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-daemon-client", + "version": "1.3.21", + "classifier": "", + "extension": "jar", + "sha256": "s+zOEex7MR7g0czGXoEfN0jzKAEHZehsvbKbK3D3Pxw=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-daemon-client", + "version": "1.3.21", + "classifier": "", + "extension": "pom", + "sha256": "itMzMl3sJgv3wlG4l9bZlAatonHFHSE8fFQX4f9DX7Q=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-gradle-plugin-api", + "version": "1.3.21", + "classifier": "", + "extension": "jar", + "sha256": "7QqxFDcxDNQJZXxeX4pr9YmvCoNIV3zWAPVGAfyXw2k=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-gradle-plugin-api", + "version": "1.3.21", + "classifier": "", + "extension": "pom", + "sha256": "RhrUeSzPSgDhyR+JBIHL688FQdTsbWrEyiTqcFols5U=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-gradle-plugin-model", + "version": "1.3.21", + "classifier": "", + "extension": "jar", + "sha256": "+63meio/sjTi1MG48Hsq9sCWmT807XMv5vra9pa8IIo=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-gradle-plugin-model", + "version": "1.3.21", + "classifier": "", + "extension": "pom", + "sha256": "vMX1stCbzYkO35paf1ugyMDAMQrBjmGFJOq2OHCVDjs=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-gradle-plugin", + "version": "1.3.21", + "classifier": "", + "extension": "jar", + "sha256": "eFjFj0xnioQWUg9MCUKCpIGYHP5wLSMSERjJx+mtIyY=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-gradle-plugin", + "version": "1.3.21", + "classifier": "", + "extension": "pom", + "sha256": "uABbgVT1VnJ6aviVPC6AuOWrspGXMZRXYU06zvIIe9g=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-native-utils", + "version": "1.3.21", + "classifier": "", + "extension": "jar", + "sha256": "QGAQo59MjN0jUcwRELmO2ATAqoEMthBue59PK8whzUc=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-native-utils", + "version": "1.3.21", + "classifier": "", + "extension": "pom", + "sha256": "AG/oxlzaUE9MrkwrMlR/Hx+7nG+99YAuk0fgt7J+Xes=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-reflect", + "version": "1.3.21", + "classifier": "", + "extension": "jar", + "sha256": "owZcgiYzGR4KPj7hKim+wjT8SyhkpruH70jM4+ngwmo=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-reflect", + "version": "1.3.21", + "classifier": "", + "extension": "pom", + "sha256": "QtTq+ZQiO5Yet71owWo7tK775B8vdL1wJ0Lv+QkXC8w=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-sam-with-receiver", + "version": "1.3.21", + "classifier": "", + "extension": "jar", + "sha256": "DYASsAOo2O/p+0ADrkyyuOtJvfH6FNmPW9oKIy+BZ3I=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-sam-with-receiver", + "version": "1.3.21", + "classifier": "", + "extension": "pom", + "sha256": "wdYGy0qD/mrV8VugwzRbVH/Si9DJXqqWGIO+G+BhDd4=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-script-runtime", + "version": "1.3.21", + "classifier": "", + "extension": "jar", + "sha256": "LiW6vI3NIkucR54sFs57TFBAfSXxjWDR/SYveMK0dMs=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-script-runtime", + "version": "1.3.21", + "classifier": "", + "extension": "pom", + "sha256": "65n/mMkw7B9deLEt5j+o0aqEnLp+ZjyNuYz/F83HV0c=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-scripting-compiler-embeddable", + "version": "1.3.21", + "classifier": "", + "extension": "jar", + "sha256": "9Ob5/ThNQhZ+m4n5he5KSKBna/5wWy4vnRPhWR1LfAs=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-scripting-compiler-embeddable", + "version": "1.3.21", + "classifier": "", + "extension": "pom", + "sha256": "zogfIC+Za2bxr3XBK3JgBI+Zy6IqDyqNXVquIGI1g1Y=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-stdlib-common", + "version": "1.3.21", + "classifier": "", + "extension": "jar", + "sha256": "zqYfe2EYleZPWFaal1f8CrDVgvEHIR4ZMODOKgrdUqc=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-stdlib-common", + "version": "1.3.21", + "classifier": "", + "extension": "pom", + "sha256": "HkQzMKGrEIPdEjMesYI7zaGM06YWLtxTagNeTeHXhz0=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-stdlib-jdk7", + "version": "1.3.21", + "classifier": "", + "extension": "jar", + "sha256": "qHh1YE/UIUDaaTiuTTXuYQgfRIJTbvxtJhW4tiahmK8=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-stdlib-jdk7", + "version": "1.3.21", + "classifier": "", + "extension": "pom", + "sha256": "Jke6QWznPfilAYm2gN2TuHn7031z4xEIt5+9tVAAWnY=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-stdlib-jdk8", + "version": "1.3.21", + "classifier": "", + "extension": "jar", + "sha256": "WCPtZqwSKhxVRC68paIJqEPM2H9WLtwxp4fz0uR/dNQ=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-stdlib-jdk8", + "version": "1.3.21", + "classifier": "", + "extension": "pom", + "sha256": "Vy3BzP3Nbd1GkYKm1Ty8eAKIsyXaUvJ8J/pc+mv5mYc=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-stdlib", + "version": "1.3.21", + "classifier": "", + "extension": "jar", + "sha256": "OLojcNnwb1BDPgayyndblEc8LieF9BCSYHmreTxysDQ=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-stdlib", + "version": "1.3.21", + "classifier": "", + "extension": "pom", + "sha256": "nOHqMzlsW/5I7IQSoM1WHsyQnXHI+TZZZ6FPnyT9uaU=" + }, + { + "groupId": "org.jetbrains", + "artifactId": "annotations", + "version": "13.0", + "classifier": "", + "extension": "jar", + "sha256": "rOKhDcji1f00kl7KwD5JiLLA+FFlDJS4zvSbob0RFHg=" + }, + { + "groupId": "org.jetbrains", + "artifactId": "annotations", + "version": "13.0", + "classifier": "", + "extension": "pom", + "sha256": "llrrK+3/NpgZvd4b96CzuJuCR91pyIuGN112Fju4w5c=" + }, + { + "groupId": "org.ow2.asm", + "artifactId": "asm-analysis", + "version": "6.2.1", + "classifier": "", + "extension": "jar", + "sha256": "TJNCyY50bpwtfyzcaJb3NIMX6bHlpsWRBH/Ilp3vSyM=" + }, + { + "groupId": "org.ow2.asm", + "artifactId": "asm-analysis", + "version": "6.2.1", + "classifier": "", + "extension": "pom", + "sha256": "jq++RQVJv6RBWjjRM6qg1CrzTTELxaZJ4LtMeBa5wxI=" + }, + { + "groupId": "org.ow2.asm", + "artifactId": "asm-commons", + "version": "6.2.1", + "classifier": "", + "extension": "jar", + "sha256": "P1eNMe8w+UttH0SBL0H+T5inzUKvNTNfXUhmqzuQGGU=" + }, + { + "groupId": "org.ow2.asm", + "artifactId": "asm-commons", + "version": "6.2.1", + "classifier": "", + "extension": "pom", + "sha256": "Xv6KkF/PEsDrWd/JLazN17lP1DZiK1MAWX8vXjjFtWk=" + }, + { + "groupId": "org.ow2.asm", + "artifactId": "asm-parent", + "version": "6.0", + "classifier": "", + "extension": "pom", + "sha256": "eR0GS7nsyaRtQ7ye/s10yRRk38RR8yG4AtImHizNfRQ=" + }, + { + "groupId": "org.ow2.asm", + "artifactId": "asm-tree", + "version": "6.2.1", + "classifier": "", + "extension": "jar", + "sha256": "pSC1THvk4H5TPbhCDd+Tb+g0H/VqXfJVurWER43ZCqs=" + }, + { + "groupId": "org.ow2.asm", + "artifactId": "asm-tree", + "version": "6.2.1", + "classifier": "", + "extension": "pom", + "sha256": "9HsK0Kct4wRIb9PsWQDqghtgSQBwApCW1kdIaKPdMQM=" + }, + { + "groupId": "org.ow2.asm", + "artifactId": "asm-util", + "version": "6.0", + "classifier": "", + "extension": "jar", + "sha256": "NWr+vbD4cBdSYuUYj4cJo7F6oqWmpLA0CwTUtEm8pfY=" + }, + { + "groupId": "org.ow2.asm", + "artifactId": "asm-util", + "version": "6.0", + "classifier": "", + "extension": "pom", + "sha256": "PN/GH5iNFnuXUDQZ2oKlgIsg9CBa60bDlObn/9MhHxI=" + }, + { + "groupId": "org.ow2.asm", + "artifactId": "asm", + "version": "6.2.1", + "classifier": "", + "extension": "jar", + "sha256": "FGDbbDPMmchOXLMORrAX5NHMmn+8F0EB1vhIKbtkwIU=" + }, + { + "groupId": "org.ow2.asm", + "artifactId": "asm", + "version": "6.2.1", + "classifier": "", + "extension": "pom", + "sha256": "rCBe+QYK3x8qssJLyUKcd7zkih+0lv37WTjq9ZD046M=" + }, + { + "groupId": "org.ow2", + "artifactId": "ow2", + "version": "1.3", + "classifier": "", + "extension": "pom", + "sha256": "USFcZ9LAaNi30vb4D1E3KgmAdd7MxEjUvde5h7qDKPs=" + }, + { + "groupId": "org.ow2", + "artifactId": "ow2", + "version": "1.5", + "classifier": "", + "extension": "pom", + "sha256": "D4obEW52C4/mOJxRuE5LB6cPwRCC1Pk25FO1g91QtDs=" + }, + { + "groupId": "org.sonatype.forge", + "artifactId": "forge-parent", + "version": "10", + "classifier": "", + "extension": "pom", + "sha256": "wU+5wytZzAMlH2CUFtt8DP8B+BHtzMtPaoZdbnBGvQs=" + }, + { + "groupId": "org.vafer", + "artifactId": "jdependency", + "version": "1.3", + "classifier": "", + "extension": "jar", + "sha256": "DRE1VU9pho+SfUauQV5BnqFVlZJcVW5VohuO+bfJ8rE=" + }, + { + "groupId": "org.vafer", + "artifactId": "jdependency", + "version": "1.3", + "classifier": "", + "extension": "pom", + "sha256": "1L6Tzna2f9ir8rCYa5rBB7VeIo+PGgb4lkDAzxlBFFU=" + } + ] + }, + "buildscript": { + "path": ":", + "env": "buildscript", + "repositories": [], + "artifacts": [] + }, + "project": { + "path": ":", + "env": "project", + "repositories": [], + "artifacts": [] + } + }, + ":app": { + "buildscript": { + "path": ":app", + "env": "buildscript", + "repositories": [], + "artifacts": [] + }, + "project": { + "path": ":app", + "env": "project", + "repositories": [ + "https://jcenter.bintray.com/", + "https://repo.gradle.org/gradle/libs-releases" + ], + "artifacts": [ + { + "groupId": "com.github.ajalt", + "artifactId": "clikt", + "version": "1.7.0", + "classifier": "", + "extension": "jar", + "sha256": "BvUGcF+n7UlzPQFz7treWWKKPZxcoj30apGDBq2Y8X8=" + }, + { + "groupId": "com.github.ajalt", + "artifactId": "clikt", + "version": "1.7.0", + "classifier": "", + "extension": "pom", + "sha256": "D6xVOlI5cEVPsyl04UrY+jUqfinPs5K2VZtqNbrkmG0=" + }, + { + "groupId": "org.gradle", + "artifactId": "gradle-tooling-api", + "version": "5.3", + "classifier": "", + "extension": "jar", + "sha256": "3AflRCc5b3i/wZFbTJ9Tbp8Vqi95mxaVSg1G+L3QKvo=" + }, + { + "groupId": "org.gradle", + "artifactId": "gradle-tooling-api", + "version": "5.3", + "classifier": "", + "extension": "pom", + "sha256": "yIh7MGQj1zfYLXbGfkcRddqSUn9Css56Kv+tDB8oPcM=" + }, + { + "groupId": "org.jetbrains.intellij.deps", + "artifactId": "trove4j", + "version": "1.0.20181211", + "classifier": "", + "extension": "jar", + "sha256": "r/t8haPIe9z2n/HbuE3hH2PckxKTk0vAjNerGN4INgE=" + }, + { + "groupId": "org.jetbrains.intellij.deps", + "artifactId": "trove4j", + "version": "1.0.20181211", + "classifier": "", + "extension": "pom", + "sha256": "MQpqotkFNMMrj0bx/JjNDtrpXc38oj4oR+Xvqa4MAZo=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-compiler-embeddable", + "version": "1.3.21", + "classifier": "", + "extension": "jar", + "sha256": "r6rtwyT79jlNnzlUTvzJPPxZ+KWqGhpccdYeJINmbGo=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-compiler-embeddable", + "version": "1.3.21", + "classifier": "", + "extension": "pom", + "sha256": "Uyu5QViDU4ZwPnZUMH56w2ccCUfZZWGs2quaC3Lp30Q=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-reflect", + "version": "1.3.21", + "classifier": "", + "extension": "jar", + "sha256": "owZcgiYzGR4KPj7hKim+wjT8SyhkpruH70jM4+ngwmo=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-reflect", + "version": "1.3.21", + "classifier": "", + "extension": "pom", + "sha256": "QtTq+ZQiO5Yet71owWo7tK775B8vdL1wJ0Lv+QkXC8w=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-script-runtime", + "version": "1.3.21", + "classifier": "", + "extension": "jar", + "sha256": "LiW6vI3NIkucR54sFs57TFBAfSXxjWDR/SYveMK0dMs=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-script-runtime", + "version": "1.3.21", + "classifier": "", + "extension": "pom", + "sha256": "65n/mMkw7B9deLEt5j+o0aqEnLp+ZjyNuYz/F83HV0c=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-scripting-compiler-embeddable", + "version": "1.3.21", + "classifier": "", + "extension": "jar", + "sha256": "9Ob5/ThNQhZ+m4n5he5KSKBna/5wWy4vnRPhWR1LfAs=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-scripting-compiler-embeddable", + "version": "1.3.21", + "classifier": "", + "extension": "pom", + "sha256": "zogfIC+Za2bxr3XBK3JgBI+Zy6IqDyqNXVquIGI1g1Y=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-stdlib-common", + "version": "1.3.21", + "classifier": "", + "extension": "jar", + "sha256": "zqYfe2EYleZPWFaal1f8CrDVgvEHIR4ZMODOKgrdUqc=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-stdlib-common", + "version": "1.3.21", + "classifier": "", + "extension": "pom", + "sha256": "HkQzMKGrEIPdEjMesYI7zaGM06YWLtxTagNeTeHXhz0=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-stdlib-jdk7", + "version": "1.3.21", + "classifier": "", + "extension": "jar", + "sha256": "qHh1YE/UIUDaaTiuTTXuYQgfRIJTbvxtJhW4tiahmK8=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-stdlib-jdk7", + "version": "1.3.21", + "classifier": "", + "extension": "pom", + "sha256": "Jke6QWznPfilAYm2gN2TuHn7031z4xEIt5+9tVAAWnY=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-stdlib-jdk8", + "version": "1.3.21", + "classifier": "", + "extension": "jar", + "sha256": "WCPtZqwSKhxVRC68paIJqEPM2H9WLtwxp4fz0uR/dNQ=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-stdlib-jdk8", + "version": "1.3.21", + "classifier": "", + "extension": "pom", + "sha256": "Vy3BzP3Nbd1GkYKm1Ty8eAKIsyXaUvJ8J/pc+mv5mYc=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-stdlib", + "version": "1.3.21", + "classifier": "", + "extension": "jar", + "sha256": "OLojcNnwb1BDPgayyndblEc8LieF9BCSYHmreTxysDQ=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-stdlib", + "version": "1.3.21", + "classifier": "", + "extension": "pom", + "sha256": "nOHqMzlsW/5I7IQSoM1WHsyQnXHI+TZZZ6FPnyT9uaU=" + }, + { + "groupId": "org.jetbrains", + "artifactId": "annotations", + "version": "13.0", + "classifier": "", + "extension": "jar", + "sha256": "rOKhDcji1f00kl7KwD5JiLLA+FFlDJS4zvSbob0RFHg=" + }, + { + "groupId": "org.jetbrains", + "artifactId": "annotations", + "version": "13.0", + "classifier": "", + "extension": "pom", + "sha256": "llrrK+3/NpgZvd4b96CzuJuCR91pyIuGN112Fju4w5c=" + }, + { + "groupId": "org.slf4j", + "artifactId": "slf4j-api", + "version": "1.7.25", + "classifier": "", + "extension": "jar", + "sha256": "GMSgCV1cHaa4F1kudnuyPSndL1YK1033X/OWHb3iW3k=" + }, + { + "groupId": "org.slf4j", + "artifactId": "slf4j-api", + "version": "1.7.25", + "classifier": "", + "extension": "pom", + "sha256": "fNnXoLXZPf1GGhSIkbQ1Cc9AOpx/n7SQYNNVTfHIHh4=" + }, + { + "groupId": "org.slf4j", + "artifactId": "slf4j-parent", + "version": "1.7.25", + "classifier": "", + "extension": "pom", + "sha256": "GPXFISDbA26I1hNviDnIMtB0vdqVx1bG9CkknS21SsY=" + } + ] + } + }, + ":plugin": { + "buildscript": { + "path": ":plugin", + "env": "buildscript", + "repositories": [], + "artifacts": [] + }, + "project": { + "path": ":plugin", + "env": "project", + "repositories": [ + "https://repo.maven.apache.org/maven2/" + ], + "artifacts": [ + { + "groupId": "com.google.auto", + "artifactId": "auto-common", + "version": "0.10", + "classifier": "", + "extension": "jar", + "sha256": "uHa1/drO66fTWWZ/bE+4xvhljaGrkC/7eeyaQV3u3l8=" + }, + { + "groupId": "com.google.auto", + "artifactId": "auto-common", + "version": "0.10", + "classifier": "", + "extension": "pom", + "sha256": "RnreF6BwnXsdXEYeZ/NZ5O/8UjD8Yr0L4oDs4aCPAzI=" + }, + { + "groupId": "com.google.auto", + "artifactId": "auto-parent", + "version": "6", + "classifier": "", + "extension": "pom", + "sha256": "BfdAxmSBZdsAz2GN1WwgDEcl41jm1U9YU+C+wVc06go=" + }, + { + "groupId": "com.google.code.findbugs", + "artifactId": "jsr305", + "version": "1.3.9", + "classifier": "", + "extension": "jar", + "sha256": "kFchoO6pCoFTSrt+5u9OouXmRfod7wpc2IQC3xtGye0=" + }, + { + "groupId": "com.google.code.findbugs", + "artifactId": "jsr305", + "version": "1.3.9", + "classifier": "", + "extension": "pom", + "sha256": "/quRkTEcPXru8rZtYGSvyA09HVLZgPsHrkPHjJh7qTo=" + }, + { + "groupId": "com.google.errorprone", + "artifactId": "error_prone_annotations", + "version": "2.0.18", + "classifier": "", + "extension": "jar", + "sha256": "y0z62HC/VjoHGZ8+vqV2Pw3sRA/NoLMYZAsf6qeIZWs=" + }, + { + "groupId": "com.google.errorprone", + "artifactId": "error_prone_annotations", + "version": "2.0.18", + "classifier": "", + "extension": "pom", + "sha256": "kUQScZLW9hLCNmgl3OrrI7DVMTC4Pgvx/+EH0UcKhIc=" + }, + { + "groupId": "com.google.errorprone", + "artifactId": "error_prone_parent", + "version": "2.0.18", + "classifier": "", + "extension": "pom", + "sha256": "zxSZVSebB9TxHoF5hcEWSmnpMNc9t0QbQ6bvU7vShsQ=" + }, + { + "groupId": "com.google.guava", + "artifactId": "guava-parent", + "version": "20.0", + "classifier": "", + "extension": "pom", + "sha256": "8SJv0H/HKvjWIyvfpwvzHYg6GgHLxUfyOnTpBmxpLfE=" + }, + { + "groupId": "com.google.guava", + "artifactId": "guava-parent", + "version": "23.5-jre", + "classifier": "", + "extension": "pom", + "sha256": "1pr4WZD3fvVLSqjnRMAU3oEcrYpi55Cxd8IZtZx12Rg=" + }, + { + "groupId": "com.google.guava", + "artifactId": "guava", + "version": "20.0", + "classifier": "", + "extension": "jar", + "sha256": "NqZm47ca5/Dw3KI2VLZ+CG5sk9GS9gul39VRnbbCiMg=" + }, + { + "groupId": "com.google.guava", + "artifactId": "guava", + "version": "20.0", + "classifier": "", + "extension": "pom", + "sha256": "NjzIN2e3YNelZNUwHglGfm1I/BwcFmSx4YxQgVzhkHY=" + }, + { + "groupId": "com.google.guava", + "artifactId": "guava", + "version": "23.5-jre", + "classifier": "", + "extension": "jar", + "sha256": "yUZ3iO/7x+awZUo/18fgRE1wRmSjItIY6oxydrFkIrs=" + }, + { + "groupId": "com.google.guava", + "artifactId": "guava", + "version": "23.5-jre", + "classifier": "", + "extension": "pom", + "sha256": "TLEZ2NT4pf4purQgSDvVSOHfHffnOm9oe1ZqgoO6I9k=" + }, + { + "groupId": "com.google.j2objc", + "artifactId": "j2objc-annotations", + "version": "1.1", + "classifier": "", + "extension": "jar", + "sha256": "KZSn63jycQvT07+2ObLJTiGc7awNTQhNUW54wW3d7PY=" + }, + { + "groupId": "com.google.j2objc", + "artifactId": "j2objc-annotations", + "version": "1.1", + "classifier": "", + "extension": "pom", + "sha256": "8MmMVx6Tp8tN0Y3w+jCPCWPnoGIKwtQkTmHnCdA61r4=" + }, + { + "groupId": "com.squareup.moshi", + "artifactId": "moshi-kotlin-codegen", + "version": "1.8.0", + "classifier": "", + "extension": "jar", + "sha256": "9ntaKPRwWpgqs5WTBBT0WDUprk9CeQ4kZ1fbSm9MsmU=" + }, + { + "groupId": "com.squareup.moshi", + "artifactId": "moshi-kotlin-codegen", + "version": "1.8.0", + "classifier": "", + "extension": "pom", + "sha256": "W5vWOvAMhcIsn0grubfVz7B4mYQEHkFoegr3Vd0KNg8=" + }, + { + "groupId": "com.squareup.moshi", + "artifactId": "moshi-parent", + "version": "1.8.0", + "classifier": "", + "extension": "pom", + "sha256": "2t8UzX/uSexrgqkORdccwax1imVTFwGtlNy+98xgP7c=" + }, + { + "groupId": "com.squareup.moshi", + "artifactId": "moshi", + "version": "1.8.0", + "classifier": "", + "extension": "jar", + "sha256": "Qv50bSaU6hH+agK+zZ2iyj2v6Xye/VCg+a9cRZbnSmo=" + }, + { + "groupId": "com.squareup.moshi", + "artifactId": "moshi", + "version": "1.8.0", + "classifier": "", + "extension": "pom", + "sha256": "FLuAWbnddiACWSkN+IfjfmaaB0qsnImUAePIEC/lII8=" + }, + { + "groupId": "com.squareup.okio", + "artifactId": "okio-parent", + "version": "1.16.0", + "classifier": "", + "extension": "pom", + "sha256": "C3Qkw/qrO7UzMJbjmVf4j41QzgyYv7pxo/z6oKrwVSw=" + }, + { + "groupId": "com.squareup.okio", + "artifactId": "okio", + "version": "1.16.0", + "classifier": "", + "extension": "jar", + "sha256": "7ASE/xkDZA44RcKxCruZ7/LTIwj/40WeX5IwmkUbnH4=" + }, + { + "groupId": "com.squareup.okio", + "artifactId": "okio", + "version": "1.16.0", + "classifier": "", + "extension": "pom", + "sha256": "HSUhYhwIdRI6qRMRsv6O3v0O2T9mvm3+oYzGG8XJnjY=" + }, + { + "groupId": "com.squareup.okio", + "artifactId": "okio", + "version": "2.2.2", + "classifier": "", + "extension": "jar", + "sha256": "5YyXQGprsROIk3UCmaxjxqoEs4trSerhv8rRpj75uhs=" + }, + { + "groupId": "com.squareup.okio", + "artifactId": "okio", + "version": "2.2.2", + "classifier": "", + "extension": "pom", + "sha256": "/WIZiPf2lXAlc13G3QkLAKIPOju413ynkDYHf2KbFAs=" + }, + { + "groupId": "me.eugeniomarletti.kotlin.metadata", + "artifactId": "kotlin-compiler-lite", + "version": "1.0.3-k-1.2.40", + "classifier": "", + "extension": "jar", + "sha256": "fQ4eR9yYT/wPS8QoXmKY+FFaaNKmzsKPEHr5WRa0L0A=" + }, + { + "groupId": "me.eugeniomarletti.kotlin.metadata", + "artifactId": "kotlin-compiler-lite", + "version": "1.0.3-k-1.2.40", + "classifier": "", + "extension": "pom", + "sha256": "RZzOYInqbcmuceVUuqxR0WN1Em/otGAACBV5MhVt6LY=" + }, + { + "groupId": "me.eugeniomarletti.kotlin.metadata", + "artifactId": "kotlin-metadata", + "version": "1.4.0", + "classifier": "", + "extension": "jar", + "sha256": "gucO7w0UgtrgWelR3s4ShtYDIZYxaoFD6yxtLSlZ5I0=" + }, + { + "groupId": "me.eugeniomarletti.kotlin.metadata", + "artifactId": "kotlin-metadata", + "version": "1.4.0", + "classifier": "", + "extension": "pom", + "sha256": "1JJVW7TRHs4dBFbSfRif/vtYi+GG9BdDC0SFx/Qf+OY=" + }, + { + "groupId": "org.apache.commons", + "artifactId": "commons-lang3", + "version": "3.5", + "classifier": "", + "extension": "jar", + "sha256": "islvxoZRLXd/yoXhRPGWzXz+DArsIxJyKUl9Gjj/ZRw=" + }, + { + "groupId": "org.apache.commons", + "artifactId": "commons-lang3", + "version": "3.5", + "classifier": "", + "extension": "pom", + "sha256": "Ref7ssIx25A6XVqtr8Y2oXOk1UVg94oR/0mAKO+eNF4=" + }, + { + "groupId": "org.apache.commons", + "artifactId": "commons-parent", + "version": "41", + "classifier": "", + "extension": "pom", + "sha256": "sod8gBb4sokkyOkN1a5AzRHzKNAqHemNgN4iV0qzbsc=" + }, + { + "groupId": "org.apache.maven", + "artifactId": "maven-artifact", + "version": "3.5.4", + "classifier": "", + "extension": "jar", + "sha256": "b78l3obM46+69cUC3/V99tfJDPm+wK4P/lqyRnJDw1s=" + }, + { + "groupId": "org.apache.maven", + "artifactId": "maven-artifact", + "version": "3.5.4", + "classifier": "", + "extension": "pom", + "sha256": "TlRXCRfQUZHbgztcTku6Q3NeXePzf6043VoHe1lJgXo=" + }, + { + "groupId": "org.apache.maven", + "artifactId": "maven-builder-support", + "version": "3.5.4", + "classifier": "", + "extension": "jar", + "sha256": "Q4Vc4p/IAB72Y6W7K7BHNIGx+PgM6ns8wdQmr5lpYLI=" + }, + { + "groupId": "org.apache.maven", + "artifactId": "maven-builder-support", + "version": "3.5.4", + "classifier": "", + "extension": "pom", + "sha256": "uQVYL/SmxiEWLL2MdCykLe0G6mmh9IoFAE5Tj/o8nbM=" + }, + { + "groupId": "org.apache.maven", + "artifactId": "maven-model-builder", + "version": "3.5.4", + "classifier": "", + "extension": "jar", + "sha256": "XcENaf0KbjjzrDeIvx5j79Zorx/COgii/c/9hZIdb1Y=" + }, + { + "groupId": "org.apache.maven", + "artifactId": "maven-model-builder", + "version": "3.5.4", + "classifier": "", + "extension": "pom", + "sha256": "t/YeBFhitMjFKMXa5itKq7oyppzRmps4BoVwcsMPBp8=" + }, + { + "groupId": "org.apache.maven", + "artifactId": "maven-model", + "version": "3.5.4", + "classifier": "", + "extension": "jar", + "sha256": "XsG5TpJUwlSAVIYzpIt66Kmtp1J+KPXFdZQ/4MKrc1A=" + }, + { + "groupId": "org.apache.maven", + "artifactId": "maven-model", + "version": "3.5.4", + "classifier": "", + "extension": "pom", + "sha256": "6vlL7ccg1cKihoSCJU2g9xQTpo7ATxez+ENUnjnUMUE=" + }, + { + "groupId": "org.apache.maven", + "artifactId": "maven-parent", + "version": "31", + "classifier": "", + "extension": "pom", + "sha256": "Qv3nY6bm/oSAsWCK3/LDXQJhLieeyc5y+rtP2PtcV1M=" + }, + { + "groupId": "org.apache.maven", + "artifactId": "maven", + "version": "3.5.4", + "classifier": "", + "extension": "pom", + "sha256": "55XO8tL4cloZoALAkl2W+w6GrudCK1GdjyERBSopr2c=" + }, + { + "groupId": "org.apache", + "artifactId": "apache", + "version": "18", + "classifier": "", + "extension": "pom", + "sha256": "eDEwcoX9R1u8NrIK4454gvEcMVOx1ZMPhS1E7ajzPBc=" + }, + { + "groupId": "org.apache", + "artifactId": "apache", + "version": "19", + "classifier": "", + "extension": "pom", + "sha256": "kfejMJbqabrCy69tAf65NMrAAsSNjIz6nCQLQPHsId8=" + }, + { + "groupId": "org.checkerframework", + "artifactId": "checker-qual", + "version": "2.0.0", + "classifier": "", + "extension": "jar", + "sha256": "/IRBYy9fpVN0ksnwJtHIsa22p3lvRgMbBLTMBiJCeZU=" + }, + { + "groupId": "org.checkerframework", + "artifactId": "checker-qual", + "version": "2.0.0", + "classifier": "", + "extension": "pom", + "sha256": "3rEDU90rG+4OVIt0AU2AoReaj6r40NiGwBtNbKkwAGg=" + }, + { + "groupId": "org.codehaus.mojo", + "artifactId": "animal-sniffer-annotations", + "version": "1.14", + "classifier": "", + "extension": "jar", + "sha256": "IGgyC9a610TDZzqwSPZ+ML749RiZb6OAAzVWYAZpkF0=" + }, + { + "groupId": "org.codehaus.mojo", + "artifactId": "animal-sniffer-annotations", + "version": "1.14", + "classifier": "", + "extension": "pom", + "sha256": "GHnxmgWZHj7ZWRC5ZokzM5awxGeiFdxNH5ABhAS3KiY=" + }, + { + "groupId": "org.codehaus.mojo", + "artifactId": "animal-sniffer-parent", + "version": "1.14", + "classifier": "", + "extension": "pom", + "sha256": "9RVQoGsUEL1JYssOcd8Lkhpgp+9Hv6nEgloUvnIxbuo=" + }, + { + "groupId": "org.codehaus.mojo", + "artifactId": "mojo-parent", + "version": "34", + "classifier": "", + "extension": "pom", + "sha256": "Pjldb7xDwJo3dMrIaUzlJzmDBeo/1UktgOJa8n04Kpw=" + }, + { + "groupId": "org.codehaus.plexus", + "artifactId": "plexus-component-annotations", + "version": "1.7.1", + "classifier": "", + "extension": "jar", + "sha256": "p/7pQ123Fr/1k+n7ViK8+fJeUnGWSFkpsM1AZcQ+Yd8=" + }, + { + "groupId": "org.codehaus.plexus", + "artifactId": "plexus-component-annotations", + "version": "1.7.1", + "classifier": "", + "extension": "pom", + "sha256": "qQmgy+KS5UEitreF9pJKsvCbFjC3iJyADgmeJif5Gng=" + }, + { + "groupId": "org.codehaus.plexus", + "artifactId": "plexus-containers", + "version": "1.7.1", + "classifier": "", + "extension": "pom", + "sha256": "VWagu1HcmUwDUCBmCMe0zcybZogUl7q1ajLELtylPnk=" + }, + { + "groupId": "org.codehaus.plexus", + "artifactId": "plexus-interpolation", + "version": "1.24", + "classifier": "", + "extension": "jar", + "sha256": "j+K+BLBnp10C+4oanK9sHIYV8NVXfM7QLpC1IHY9L3c=" + }, + { + "groupId": "org.codehaus.plexus", + "artifactId": "plexus-interpolation", + "version": "1.24", + "classifier": "", + "extension": "pom", + "sha256": "tdi6wu9/0RNimCI+U0iZgK16B30cnlTAayiEZwdxgZ8=" + }, + { + "groupId": "org.codehaus.plexus", + "artifactId": "plexus-utils", + "version": "3.1.0", + "classifier": "", + "extension": "jar", + "sha256": "D/oK0ITr/1cSVAp7fqCr2kh8U9Ohj3jJjRo2ddq5v2E=" + }, + { + "groupId": "org.codehaus.plexus", + "artifactId": "plexus-utils", + "version": "3.1.0", + "classifier": "", + "extension": "pom", + "sha256": "FHPR654v++0CWBmJKweJhcXdVcGQsdgv0bVoVQWyuBk=" + }, + { + "groupId": "org.codehaus.plexus", + "artifactId": "plexus", + "version": "4.0", + "classifier": "", + "extension": "pom", + "sha256": "ChtpLX/MkNakXa4uUPRmDUj3pEUE8XSqYO80++Eyf2o=" + }, + { + "groupId": "org.codehaus", + "artifactId": "codehaus-parent", + "version": "4", + "classifier": "", + "extension": "pom", + "sha256": "a4cjfejC4XQM+AYnx/POPhXeGTC7JQxVoeypT6PgFN8=" + }, + { + "groupId": "org.jetbrains.intellij.deps", + "artifactId": "trove4j", + "version": "1.0.20181211", + "classifier": "", + "extension": "jar", + "sha256": "r/t8haPIe9z2n/HbuE3hH2PckxKTk0vAjNerGN4INgE=" + }, + { + "groupId": "org.jetbrains.intellij.deps", + "artifactId": "trove4j", + "version": "1.0.20181211", + "classifier": "", + "extension": "pom", + "sha256": "MQpqotkFNMMrj0bx/JjNDtrpXc38oj4oR+Xvqa4MAZo=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-annotation-processing-embeddable", + "version": "1.2.71", + "classifier": "", + "extension": "jar", + "sha256": "rPoYJ6iKfJ5VHkyqpzWrn7tsVChe4y+wawJ2/sLGx6c=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-annotation-processing-embeddable", + "version": "1.2.71", + "classifier": "", + "extension": "pom", + "sha256": "uDtOT5E2+uv6fskLjJ11vS6xwpTEku3a6fgNpUvJquE=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-annotation-processing-gradle", + "version": "1.3.21", + "classifier": "", + "extension": "jar", + "sha256": "+viAMV1P1qZmzBeqXpYIx0aMcKJ5tJzMpn26KlSt9pI=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-annotation-processing-gradle", + "version": "1.3.21", + "classifier": "", + "extension": "pom", + "sha256": "9X3OxdUN+KLeVw86yJcYidSUPyuqyogUACoudn0L6Mk=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-compiler-embeddable", + "version": "1.2.71", + "classifier": "", + "extension": "jar", + "sha256": "Yj5UYxDT2ontK8DPn3/t14+t2c1l0v95j6iUwU5SdmU=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-compiler-embeddable", + "version": "1.2.71", + "classifier": "", + "extension": "pom", + "sha256": "4XIB+2uoiBi8K3Vs4XnWGYJiaToL73BIUZvnPqj0200=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-compiler-embeddable", + "version": "1.3.21", + "classifier": "", + "extension": "jar", + "sha256": "r6rtwyT79jlNnzlUTvzJPPxZ+KWqGhpccdYeJINmbGo=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-compiler-embeddable", + "version": "1.3.21", + "classifier": "", + "extension": "pom", + "sha256": "Uyu5QViDU4ZwPnZUMH56w2ccCUfZZWGs2quaC3Lp30Q=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-reflect", + "version": "1.2.71", + "classifier": "", + "extension": "jar", + "sha256": "Hz4Qq9aNCwgWvdq3MU9hJp4B2KosocvRIMEtO03JSw8=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-reflect", + "version": "1.2.71", + "classifier": "", + "extension": "pom", + "sha256": "OiUeTEuWcSe0gO1fTVGtqebyz2Ibwz6qvkIlduJMaSs=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-reflect", + "version": "1.3.21", + "classifier": "", + "extension": "jar", + "sha256": "owZcgiYzGR4KPj7hKim+wjT8SyhkpruH70jM4+ngwmo=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-reflect", + "version": "1.3.21", + "classifier": "", + "extension": "pom", + "sha256": "QtTq+ZQiO5Yet71owWo7tK775B8vdL1wJ0Lv+QkXC8w=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-sam-with-receiver", + "version": "1.3.21", + "classifier": "", + "extension": "jar", + "sha256": "DYASsAOo2O/p+0ADrkyyuOtJvfH6FNmPW9oKIy+BZ3I=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-sam-with-receiver", + "version": "1.3.21", + "classifier": "", + "extension": "pom", + "sha256": "wdYGy0qD/mrV8VugwzRbVH/Si9DJXqqWGIO+G+BhDd4=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-script-runtime", + "version": "1.2.71", + "classifier": "", + "extension": "jar", + "sha256": "MH0KVnNEWKXlfj6niMFbIlkZEro5+BssyLCgkJRAErs=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-script-runtime", + "version": "1.2.71", + "classifier": "", + "extension": "pom", + "sha256": "NvuWlPDSbW2lK6KkmPLa4eoX0Sr0HZVf5cLwLQREI9c=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-script-runtime", + "version": "1.3.21", + "classifier": "", + "extension": "jar", + "sha256": "LiW6vI3NIkucR54sFs57TFBAfSXxjWDR/SYveMK0dMs=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-script-runtime", + "version": "1.3.21", + "classifier": "", + "extension": "pom", + "sha256": "65n/mMkw7B9deLEt5j+o0aqEnLp+ZjyNuYz/F83HV0c=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-scripting-compiler-embeddable", + "version": "1.3.21", + "classifier": "", + "extension": "jar", + "sha256": "9Ob5/ThNQhZ+m4n5he5KSKBna/5wWy4vnRPhWR1LfAs=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-scripting-compiler-embeddable", + "version": "1.3.21", + "classifier": "", + "extension": "pom", + "sha256": "zogfIC+Za2bxr3XBK3JgBI+Zy6IqDyqNXVquIGI1g1Y=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-stdlib-common", + "version": "1.2.71", + "classifier": "", + "extension": "jar", + "sha256": "Y5mWh/8vzopZLdGA/7v48dIcJrQETFXNx0/zzzs88yg=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-stdlib-common", + "version": "1.2.71", + "classifier": "", + "extension": "pom", + "sha256": "qMPtWJIDK56TlVJKTaKVOXXJlii5Mt8zNrJdVG58ZpM=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-stdlib-common", + "version": "1.3.21", + "classifier": "", + "extension": "jar", + "sha256": "zqYfe2EYleZPWFaal1f8CrDVgvEHIR4ZMODOKgrdUqc=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-stdlib-common", + "version": "1.3.21", + "classifier": "", + "extension": "pom", + "sha256": "HkQzMKGrEIPdEjMesYI7zaGM06YWLtxTagNeTeHXhz0=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-stdlib-jdk7", + "version": "1.3.21", + "classifier": "", + "extension": "jar", + "sha256": "qHh1YE/UIUDaaTiuTTXuYQgfRIJTbvxtJhW4tiahmK8=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-stdlib-jdk7", + "version": "1.3.21", + "classifier": "", + "extension": "pom", + "sha256": "Jke6QWznPfilAYm2gN2TuHn7031z4xEIt5+9tVAAWnY=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-stdlib-jdk8", + "version": "1.3.21", + "classifier": "", + "extension": "jar", + "sha256": "WCPtZqwSKhxVRC68paIJqEPM2H9WLtwxp4fz0uR/dNQ=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-stdlib-jdk8", + "version": "1.3.21", + "classifier": "", + "extension": "pom", + "sha256": "Vy3BzP3Nbd1GkYKm1Ty8eAKIsyXaUvJ8J/pc+mv5mYc=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-stdlib", + "version": "1.2.71", + "classifier": "", + "extension": "jar", + "sha256": "TIlcJwuH9f7ConluHYnBVAfugh3pYVJ8KFiLtGr7xos=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-stdlib", + "version": "1.2.71", + "classifier": "", + "extension": "pom", + "sha256": "cT23fJoMR6Zw+VwjsAUbm9lCs6DqH2zJu12eq6H6da4=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-stdlib", + "version": "1.3.21", + "classifier": "", + "extension": "jar", + "sha256": "OLojcNnwb1BDPgayyndblEc8LieF9BCSYHmreTxysDQ=" + }, + { + "groupId": "org.jetbrains.kotlin", + "artifactId": "kotlin-stdlib", + "version": "1.3.21", + "classifier": "", + "extension": "pom", + "sha256": "nOHqMzlsW/5I7IQSoM1WHsyQnXHI+TZZZ6FPnyT9uaU=" + }, + { + "groupId": "org.jetbrains", + "artifactId": "annotations", + "version": "13.0", + "classifier": "", + "extension": "jar", + "sha256": "rOKhDcji1f00kl7KwD5JiLLA+FFlDJS4zvSbob0RFHg=" + }, + { + "groupId": "org.jetbrains", + "artifactId": "annotations", + "version": "13.0", + "classifier": "", + "extension": "pom", + "sha256": "llrrK+3/NpgZvd4b96CzuJuCR91pyIuGN112Fju4w5c=" + }, + { + "groupId": "org.sonatype.forge", + "artifactId": "forge-parent", + "version": "10", + "classifier": "", + "extension": "pom", + "sha256": "wU+5wytZzAMlH2CUFtt8DP8B+BHtzMtPaoZdbnBGvQs=" + }, + { + "groupId": "org.sonatype.oss", + "artifactId": "oss-parent", + "version": "7", + "classifier": "", + "extension": "pom", + "sha256": "tR+IZ8kranIkmVV/w6H96ne9+e9XRyL+kM5DailVlFQ=" + } + ] + } + } +} \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..457aad0d98108420a977756b7145c93c8910b076 GIT binary patch literal 55741 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 literal 0 HcmV?d00001 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..b8a51fe --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.3-all.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..af6708f --- /dev/null +++ b/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..0f8d593 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/plugin/build.gradle.kts b/plugin/build.gradle.kts new file mode 100644 index 0000000..ee802b2 --- /dev/null +++ b/plugin/build.gradle.kts @@ -0,0 +1,34 @@ +plugins { + id("com.github.johnrengelman.shadow") version "4.0.0" + `java-gradle-plugin` + `kotlin-dsl` + `maven-publish` + kotlin("kapt") version embeddedKotlinVersion +} + +group = "org.nixos" +version = "1.0.0-SNAPSHOT" + +repositories { + mavenCentral() +} + +dependencies { + implementation(kotlin("stdlib-jdk8")) + implementation("org.apache.maven:maven-model:3.5.4") + implementation("org.apache.maven:maven-model-builder:3.5.4") + implementation("com.squareup.okio:okio:2.2.2") + implementation("com.squareup.moshi:moshi:1.8.0") + kapt("com.squareup.moshi:moshi-kotlin-codegen:1.8.0") +} + +gradlePlugin { + plugins { + register("gradle2nix") { + id = "org.nixos.gradle2nix" + displayName = "gradle2nix" + description = "Create Nix configurations suitable for reproducible packaging" + implementationClass = "org.nixos.gradle2nix.Gradle2NixPlugin" + } + } +} \ No newline at end of file diff --git a/plugin/src/main/kotlin/org/nixos/gradle2nix/Gradle2NixPlugin.kt b/plugin/src/main/kotlin/org/nixos/gradle2nix/Gradle2NixPlugin.kt new file mode 100644 index 0000000..6d40da9 --- /dev/null +++ b/plugin/src/main/kotlin/org/nixos/gradle2nix/Gradle2NixPlugin.kt @@ -0,0 +1,137 @@ +package org.nixos.gradle2nix + +import com.squareup.moshi.Moshi +import okio.buffer +import okio.source +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.file.RegularFile +import org.gradle.api.file.RegularFileProperty +import org.gradle.api.internal.DocumentationRegistry +import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.strategy.VersionSelectorScheme +import org.gradle.api.internal.plugins.PluginRegistry +import org.gradle.api.invocation.Gradle +import org.gradle.api.provider.Provider +import org.gradle.api.tasks.TaskProvider +import org.gradle.api.tasks.wrapper.Wrapper +import org.gradle.kotlin.dsl.create +import org.gradle.kotlin.dsl.named +import org.gradle.kotlin.dsl.property +import org.gradle.kotlin.dsl.register +import org.gradle.kotlin.dsl.withType +import org.gradle.plugin.management.PluginRequest +import org.gradle.plugin.use.internal.PluginDependencyResolutionServices +import org.gradle.plugin.use.internal.PluginResolverFactory +import java.io.File +import java.net.URL +import java.util.Locale +import javax.inject.Inject + +open class Gradle2NixPlugin : Plugin { + override fun apply(gradle: Gradle) { + val configurationNames: List = + System.getProperty("org.nixos.gradle2nix.configurations")?.split(",") ?: emptyList() + + val pluginRequests = collectPlugins(gradle) + + gradle.projectsLoaded { + val extension = rootProject.extensions.create( + "gradle2nix", + rootProject, + configurationNames + ) + + val gradleEnv = rootProject.tasks.register("nixGradleEnv", NixGradleEnv::class) { + outputDir.set(extension.outputDir) + } + + val pluginEnv = + rootProject.tasks.register("nixPluginEnv", NixPluginEnv::class, pluginRequests) + gradleEnv.configure { + inputEnvs.from(pluginEnv) + } + + allprojects { + val buildscriptEnv = tasks.register("nixBuildscriptEnv", NixBuildscriptEnv::class) { + pluginEnvFile.set(pluginEnv.flatMap { it.outputFile }) + } + val projectEnv = tasks.register("nixProjectEnv", NixProjectEnv::class) { + configurations.addAll(extension.configurations) + } + gradleEnv.configure { + inputEnvs.from(buildscriptEnv) + inputEnvs.from(projectEnv) + } + } + + resolveGradleDist(gradle, extension, gradleEnv) + } + } + + private fun collectPlugins(gradle: Gradle): List { + val pluginRequests = mutableListOf() + gradle.settingsEvaluated { + pluginManagement.resolutionStrategy.eachPlugin { + if (requested.id.namespace != null && requested.id.namespace != "org.gradle") { + pluginRequests.add(target) + } + } + } + return pluginRequests + } + + private fun resolveGradleDist( + gradle: Gradle, + extension: Gradle2NixExtension, + gradleEnv: TaskProvider + ) { + gradle.projectsEvaluated { + val gradleDist = rootProject.tasks.named("wrapper", Wrapper::class).map { + GradleDist( + version = it.gradleVersion, + type = it.distributionType.name.toLowerCase(Locale.US), + url = it.distributionUrl, + sha256 = it.distributionSha256Sum ?: fetchDistSha256(it.distributionUrl), + nativeVersion = gradle.gradleHomeDir?.resolve("lib")?.listFiles() + ?.firstOrNull { f -> f.name.matches(nativePlatformJarRegex) }?.let { nf -> + nativePlatformJarRegex.find(nf.name)?.groupValues?.get(1) + } + ?: throw IllegalStateException(""" + Failed to find native-platform jar in ${gradle.gradleHomeDir}. + + Ask Tad to fix this. + """.trimIndent()) + ) + } + val gradleDistTask = + gradle.rootProject.tasks.register("nixGradleDist", NixGradleDist::class) { + this.gradleDist.set(gradleDist) + outputDir.set(extension.outputDir) + } + gradleEnv.configure { + dependsOn(gradleDistTask) + } + } + } +} + +internal val moshi by lazy { Moshi.Builder().build() } + +open class Gradle2NixExtension(project: Project, defaultConfigurations: List) { + var outputDir: File = project.projectDir.resolve("gradle/nix") + var configurations: MutableList = mutableListOf().apply { + addAll(defaultConfigurations) + } +} + +private fun fetchDistSha256(url: String): String { + return URL("$url.sha256").openConnection().run { + connect() + getInputStream().source().buffer().use { source -> + source.readUtf8() + } + } +} + +private val nativePlatformJarRegex = Regex("""native-platform-(\d\.\d+)\.jar""") + diff --git a/plugin/src/main/kotlin/org/nixos/gradle2nix/NixBuildscriptEnv.kt b/plugin/src/main/kotlin/org/nixos/gradle2nix/NixBuildscriptEnv.kt new file mode 100644 index 0000000..09095c2 --- /dev/null +++ b/plugin/src/main/kotlin/org/nixos/gradle2nix/NixBuildscriptEnv.kt @@ -0,0 +1,43 @@ +package org.nixos.gradle2nix + +import okio.buffer +import okio.source +import org.gradle.api.tasks.InputFile +import java.lang.IllegalStateException +import java.net.URI + +open class NixBuildscriptEnv : NixEnv() { + @InputFile + val pluginEnvFile = project.objects.fileProperty() + + private val pluginEnv: BuildEnv by lazy { + pluginEnvFile.get().asFile.source().buffer().use { src -> + moshi.adapter(BuildEnv::class.java).fromJson(src) + ?: throw IllegalStateException( + "Cannot load plugin env from ${pluginEnvFile.get().asFile.path}") + } + } + + private val resolver by lazy { + Resolver(project.buildscript.configurations, + project.buildscript.dependencies, + logger + ) + } + + override fun environment(): String = "buildscript" + + override fun repositories(): List = + project.buildscript.repositories.flatMap { it.repositoryUrls() }.map(URI::toString) + + override fun artifacts(): List { + return project.buildscript.configurations + .filter { it.isCanBeResolved } + .flatMap { resolver.resolveDependencies(it) + resolver.resolvePoms(it) } + .minus(pluginEnv.artifacts) + .sorted() + .distinct() + } + + override fun filename(): String = "buildscript.json" +} \ No newline at end of file diff --git a/plugin/src/main/kotlin/org/nixos/gradle2nix/NixEnv.kt b/plugin/src/main/kotlin/org/nixos/gradle2nix/NixEnv.kt new file mode 100644 index 0000000..e6803e4 --- /dev/null +++ b/plugin/src/main/kotlin/org/nixos/gradle2nix/NixEnv.kt @@ -0,0 +1,73 @@ +package org.nixos.gradle2nix + +import com.squareup.moshi.JsonClass +import com.squareup.moshi.Moshi +import okio.buffer +import okio.sink +import org.gradle.api.DefaultTask +import org.gradle.api.artifacts.repositories.ArtifactRepository +import org.gradle.api.artifacts.repositories.MavenArtifactRepository +import org.gradle.api.tasks.Internal +import org.gradle.api.tasks.OutputDirectory +import org.gradle.api.tasks.OutputFile +import org.gradle.api.tasks.TaskAction +import java.net.URI + +abstract class NixEnv : DefaultTask() { + abstract fun environment(): String + abstract fun repositories(): List + abstract fun artifacts(): List + abstract fun filename(): String + + @Internal + val outputDir = project.objects.directoryProperty() + .convention(project.layout.buildDirectory.dir("nix")) + + @OutputFile + val outputFile = project.objects.fileProperty() + .convention(outputDir.map { it.file(filename()) }) + + @TaskAction + open fun run() { + val outFile = outputFile.get().asFile + outFile.parentFile.mkdirs() + + val buildEnv = BuildEnv(project.path, environment(), repositories(), artifacts()) + outFile.sink().buffer().use { out -> + moshi.adapter(BuildEnv::class.java) + .indent(" ") + .toJson(out, buildEnv) + } + } +} + +@JsonClass(generateAdapter = true) +data class BuildEnv( + val path: String, + val env: String, + val repositories: List, + val artifacts: List +) + +@JsonClass(generateAdapter = true) +data class Artifact( + val groupId: String, + val artifactId: String, + val version: String, + val classifier: String, + val extension: String, + val sha256: String +) : Comparable { + override fun toString() = "$groupId:$artifactId:$version:$classifier:$extension" + + override fun compareTo(other: Artifact): Int { + return toString().compareTo(other.toString()) + } +} + +internal fun ArtifactRepository.repositoryUrls(): Set { + return when (this) { + is MavenArtifactRepository -> setOf(url) + artifactUrls + else -> emptySet() + }.filterNotTo(mutableSetOf()) { it.scheme == "file" } +} \ No newline at end of file diff --git a/plugin/src/main/kotlin/org/nixos/gradle2nix/NixGradleDist.kt b/plugin/src/main/kotlin/org/nixos/gradle2nix/NixGradleDist.kt new file mode 100644 index 0000000..eb338b7 --- /dev/null +++ b/plugin/src/main/kotlin/org/nixos/gradle2nix/NixGradleDist.kt @@ -0,0 +1,44 @@ +package org.nixos.gradle2nix + +import com.squareup.moshi.JsonClass +import okio.buffer +import okio.sink +import org.gradle.api.DefaultTask +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.OutputDirectory +import org.gradle.api.tasks.OutputFile +import org.gradle.api.tasks.TaskAction +import org.gradle.kotlin.dsl.property +import java.io.Serializable + +open class NixGradleDist : DefaultTask() { + @Input + internal val gradleDist = project.objects.property() + + @OutputDirectory + val outputDir = project.objects.directoryProperty() + + @OutputFile + val outputFile = project.objects.fileProperty() + .convention(outputDir.file("gradle-dist.json")) + + @TaskAction + fun run() { + if (gradleDist.isPresent) { + outputFile.asFile.get().also { it.parentFile.mkdirs() }.sink().buffer().use { out -> + moshi.adapter(GradleDist::class.java) + .indent(" ") + .toJson(out, gradleDist.get()) + } + } + } +} + +@JsonClass(generateAdapter = true) +internal data class GradleDist( + val version: String, + val type: String, + val url: String, + val sha256: String, + val nativeVersion: String +) : Serializable \ No newline at end of file diff --git a/plugin/src/main/kotlin/org/nixos/gradle2nix/NixGradleEnv.kt b/plugin/src/main/kotlin/org/nixos/gradle2nix/NixGradleEnv.kt new file mode 100644 index 0000000..99a7b58 --- /dev/null +++ b/plugin/src/main/kotlin/org/nixos/gradle2nix/NixGradleEnv.kt @@ -0,0 +1,58 @@ +package org.nixos.gradle2nix + +import com.squareup.moshi.JsonWriter +import okio.buffer +import okio.sink +import okio.source +import org.gradle.api.DefaultTask +import org.gradle.api.file.RegularFile +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.InputFiles +import org.gradle.api.tasks.Internal +import org.gradle.api.tasks.OutputDirectory +import org.gradle.api.tasks.OutputFile +import org.gradle.api.tasks.TaskAction +import org.gradle.kotlin.dsl.listProperty + +open class NixGradleEnv : DefaultTask() { + + @InputFiles + val inputEnvs = project.objects.fileCollection() + + @Internal + val outputDir = project.objects.directoryProperty() + + @OutputFile + val outputFile = project.objects.fileProperty() + .convention(outputDir.file("gradle-env.json")) + + @TaskAction + fun run() { + val envsByPath = inputEnvs.map { file -> + file.source().buffer().use { + moshi.adapter(BuildEnv::class.java).fromJson(it) + ?: throw IllegalStateException( + "Failed to load build env from ${file.path}." + ) + } + }.groupBy(BuildEnv::path) + + val outFile = outputFile.get().asFile.also { it.parentFile.mkdirs() } + + JsonWriter.of(outFile.sink().buffer()).use { writer -> + val adapter = moshi.adapter(BuildEnv::class.java).indent(" ") + writer.indent = " " + writer.beginObject() + for ((path, envs) in envsByPath) { + writer.name(path) + writer.beginObject() + for (env in envs) { + writer.name(env.env) + adapter.toJson(writer, env) + } + writer.endObject() + } + writer.endObject() + } + } +} diff --git a/plugin/src/main/kotlin/org/nixos/gradle2nix/NixPluginEnv.kt b/plugin/src/main/kotlin/org/nixos/gradle2nix/NixPluginEnv.kt new file mode 100644 index 0000000..0d118af --- /dev/null +++ b/plugin/src/main/kotlin/org/nixos/gradle2nix/NixPluginEnv.kt @@ -0,0 +1,110 @@ +package org.nixos.gradle2nix + +import org.gradle.api.artifacts.ExternalModuleDependency +import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.strategy.VersionSelectorScheme +import org.gradle.api.internal.plugins.PluginImplementation +import org.gradle.plugin.management.PluginRequest +import org.gradle.plugin.management.internal.PluginRequestInternal +import org.gradle.plugin.use.PluginId +import org.gradle.plugin.use.internal.PluginDependencyResolutionServices +import org.gradle.plugin.use.resolve.internal.ArtifactRepositoriesPluginResolver +import org.gradle.plugin.use.resolve.internal.PluginResolution +import org.gradle.plugin.use.resolve.internal.PluginResolutionResult +import org.gradle.plugin.use.resolve.internal.PluginResolveContext +import java.net.URI +import javax.inject.Inject + +open class NixPluginEnv @Inject constructor( + private val pluginDependencyResolutionServices: PluginDependencyResolutionServices, + versionSelectorScheme: VersionSelectorScheme, + private val pluginRequests: Collection +) : NixEnv() { + private val repositories by lazy { + pluginDependencyResolutionServices.resolveRepositoryHandler + } + + private val artifactRepositoriesPluginResolver = ArtifactRepositoriesPluginResolver( + pluginDependencyResolutionServices, + versionSelectorScheme + ) + + private val resolver by lazy { + Resolver( + pluginDependencyResolutionServices.configurationContainer, + pluginDependencyResolutionServices.dependencyHandler, + logger + ) + } + + private val pluginResult by lazy { + PluginResult().apply { + for (request in pluginRequests.filterIsInstance()) { + artifactRepositoriesPluginResolver.resolve(request, this) + } + } + } + + private val pluginContext by lazy { + PluginContext().apply { + for (result in pluginResult.found) result.execute(this) + } + } + + override fun environment(): String = "plugins" + + override fun repositories(): List { + return repositories.flatMap { it.repositoryUrls() }.map(URI::toString) + + pluginContext.repositories.toList() + } + + override fun artifacts(): List { + return (resolver.resolveDependencies(pluginContext.dependencies, true) + + resolver.resolvePoms(pluginContext.dependencies, true)) + .sorted() + .distinct() + } + + override fun filename(): String = "plugins.json" +} + +private class PluginResult : PluginResolutionResult { + val found = mutableSetOf() + + override fun notFound(sourceDescription: String?, notFoundMessage: String?) {} + + override fun notFound( + sourceDescription: String?, + notFoundMessage: String?, + notFoundDetail: String? + ) { + } + + override fun isFound(): Boolean = true + + override fun found(sourceDescription: String, pluginResolution: PluginResolution) { + found.add(pluginResolution) + } +} + +private class PluginContext : PluginResolveContext { + val dependencies = mutableSetOf() + val repositories = mutableSetOf() + + override fun add(plugin: PluginImplementation<*>) { + println("add: $plugin") + } + + override fun addFromDifferentLoader(plugin: PluginImplementation<*>) { + println("addFromDifferentLoader: $plugin") + } + + override fun addLegacy(pluginId: PluginId, m2RepoUrl: String, dependencyNotation: Any) { + repositories.add(m2RepoUrl) + } + + override fun addLegacy(pluginId: PluginId, dependencyNotation: Any) { + if (dependencyNotation is ExternalModuleDependency) { + dependencies.add(dependencyNotation) + } + } +} \ No newline at end of file diff --git a/plugin/src/main/kotlin/org/nixos/gradle2nix/NixProjectEnv.kt b/plugin/src/main/kotlin/org/nixos/gradle2nix/NixProjectEnv.kt new file mode 100644 index 0000000..0a1cb9f --- /dev/null +++ b/plugin/src/main/kotlin/org/nixos/gradle2nix/NixProjectEnv.kt @@ -0,0 +1,41 @@ +package org.nixos.gradle2nix + +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.Optional +import org.gradle.kotlin.dsl.setProperty +import java.net.URI + +open class NixProjectEnv : NixEnv() { + @Input @Optional + val configurations = project.objects.setProperty() + + private val resolveConfigurations by lazy { + val configs = configurations.get() + if (configs.isEmpty()) { + project.configurations.filter { it.isCanBeResolved } + } else { + project.configurations.filter { it.name in configs } + } + } + + private val resolver by lazy { + Resolver(project.configurations, + project.dependencies, + logger + ) + } + + override fun environment(): String = "project" + + override fun repositories(): List = + project.repositories.flatMap { it.repositoryUrls() }.map(URI::toString) + + override fun artifacts(): List { + return resolveConfigurations + .flatMap { resolver.resolveDependencies(it) + resolver.resolvePoms(it) } + .sorted() + .distinct() + } + + override fun filename(): String = "project.json" +} \ No newline at end of file diff --git a/plugin/src/main/kotlin/org/nixos/gradle2nix/Resolver.kt b/plugin/src/main/kotlin/org/nixos/gradle2nix/Resolver.kt new file mode 100644 index 0000000..45af037 --- /dev/null +++ b/plugin/src/main/kotlin/org/nixos/gradle2nix/Resolver.kt @@ -0,0 +1,166 @@ +package org.nixos.gradle2nix + +import okio.ByteString +import okio.HashingSource +import okio.blackholeSink +import okio.buffer +import okio.source +import org.apache.maven.model.Parent +import org.apache.maven.model.Repository +import org.apache.maven.model.building.DefaultModelBuilderFactory +import org.apache.maven.model.building.DefaultModelBuildingRequest +import org.apache.maven.model.building.ModelBuildingRequest +import org.apache.maven.model.building.ModelSource2 +import org.apache.maven.model.resolution.ModelResolver +import org.gradle.api.artifacts.Configuration +import org.gradle.api.artifacts.ConfigurationContainer +import org.gradle.api.artifacts.Dependency +import org.gradle.api.artifacts.component.ModuleComponentIdentifier +import org.gradle.api.artifacts.dsl.DependencyHandler +import org.gradle.api.artifacts.result.ResolvedArtifactResult +import org.gradle.api.logging.Logger +import org.gradle.maven.MavenModule +import org.gradle.maven.MavenPomArtifact +import java.io.File +import java.io.InputStream +import java.net.URI + +internal class Resolver( + private val configurations: ConfigurationContainer, + private val dependencies: DependencyHandler, + private val logger: Logger +) { + private val mavenPomResolver = MavenPomResolver(configurations, dependencies) + + fun resolveDependencies(configuration: Configuration): Set { + if (!configuration.isCanBeResolved) { + logger.warn("Cannot resolve configuration ${configuration.name}; ignoring.") + return emptySet() + } + return configuration.resolvedConfiguration.resolvedArtifacts.mapTo(sortedSetOf()) { + with (it) { + Artifact( + groupId = moduleVersion.id.group, + artifactId = moduleVersion.id.name, + version = moduleVersion.id.version, + classifier = classifier ?: "", + extension = extension, + sha256 = sha256(file) + ) + } + } + } + + fun resolveDependencies( + dependencies: Collection, + includeTransitive: Boolean = false + ): Set { + val configuration = configurations.detachedConfiguration(*(dependencies.toTypedArray())) + configuration.isTransitive = includeTransitive + return resolveDependencies(configuration) + } + + fun resolvePoms(configuration: Configuration): Set { + return dependencies.createArtifactResolutionQuery() + .forComponents(configuration.incoming.resolutionResult.allComponents.map { it.id }) + .withArtifacts(MavenModule::class.java, MavenPomArtifact::class.java) + .execute() + .resolvedComponents.asSequence() + .flatMap { component -> + val id = component.id + if (id !is ModuleComponentIdentifier) { + emptySequence() + } else { + component.getArtifacts(MavenPomArtifact::class.java).asSequence() + .filterIsInstance() + .map { id to it } + } + } + .flatMapTo(sortedSetOf()) { (id, artifact) -> + sequenceOf(Artifact( + groupId = id.group, + artifactId = id.module, + version = id.version, + classifier = "", + extension = artifact.file.extension, + sha256 = sha256(artifact.file) + )) + mavenPomResolver.resolve(artifact.file).asSequence() + } + } + + fun resolvePoms( + dependencies: Collection, + includeTransitive: Boolean = false + ): Set { + val configuration = configurations.detachedConfiguration(*(dependencies.toTypedArray())) + configuration.isTransitive = includeTransitive + return resolvePoms(configuration) + } +} + +private class MavenPomResolver( + private val configurations: ConfigurationContainer, + private val dependencies: DependencyHandler +) : ModelResolver { + private val modelBuilder = DefaultModelBuilderFactory().newInstance() + private val resolvedDependencies = mutableSetOf() + + @Synchronized + fun resolve(pom: File): Set { + resolvedDependencies.clear() + modelBuilder.build( + DefaultModelBuildingRequest() + .setModelResolver(this) + .setPomFile(pom) + .setSystemProperties(System.getProperties()) + .setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL) + ).effectiveModel + return resolvedDependencies.toSet() + } + + override fun newCopy() = this + + override fun resolveModel( + groupId: String, + artifactId: String, + version: String + ): ModelSource2 { + val file = configurations + .detachedConfiguration(dependencies.create("$groupId:$artifactId:$version@pom")) + .singleFile + resolvedDependencies.add(Artifact( + groupId = groupId, + artifactId = artifactId, + version = version, + classifier = "", + extension = file.extension, + sha256 = sha256(file) + )) + + return object : ModelSource2 { + override fun getLocation(): String = file.absolutePath + override fun getLocationURI(): URI = file.absoluteFile.toURI() + override fun getRelatedSource(relPath: String?): ModelSource2? = null + override fun getInputStream(): InputStream = file.inputStream() + } + } + + override fun resolveModel(parent: Parent): ModelSource2 = + resolveModel(parent.groupId, parent.artifactId, parent.version) + + override fun resolveModel(dependency: org.apache.maven.model.Dependency): ModelSource2 = + resolveModel(dependency.groupId, dependency.artifactId, dependency.version) + + override fun addRepository(repository: Repository) {} + + override fun addRepository(repository: Repository, replace: Boolean) {} +} + +fun sha256(file: File): String { + val hashSource = HashingSource.sha256(file.source()) + val hash: ByteString = hashSource.buffer().use { source -> + source.readAll(blackholeSink()) + hashSource.hash + } + return hash.base64() +} \ No newline at end of file diff --git a/plugin/src/main/resources/gradle-env.nix b/plugin/src/main/resources/gradle-env.nix new file mode 100644 index 0000000..2904921 --- /dev/null +++ b/plugin/src/main/resources/gradle-env.nix @@ -0,0 +1,51 @@ +# This file is generated by gradle2nix. + +{ stdenvNoCC, lib, buildEnv, fetchurl }: + +{ name, repositories, dependencies }: + +let + mkPath = artifact: with artifact; lib.concatStringsSep "/" [ + (lib.replaceChars ["."] ["/"] artifact.groupId) + artifact.artifactId + artifact.version + ]; + + mkFilename = artifact: with artifact; + "${artifactId}-${version}${lib.optionalString (classifier != "") "-${classifier}"}.${extension}"; + + mkArtifactUrl = base: artifact: + "${lib.removeSuffix "/" base}/${mkPath artifact}/${mkFilename artifact}"; + + fetchArtifact = artifact: + let + artifactPath = mkPath artifact; + artifactName = mkFilename artifact; + in stdenvNoCC.mkDerivation rec { + name = with artifact; lib.concatStrings [ + (lib.replaceChars ["."] ["_"] groupId) "-" + (lib.replaceChars ["."] ["_"] artifactId) "-" + version + (lib.optionalString (classifier != "") "-${classifier}") + "-" type + ]; + + src = fetchurl { + name = mkFilename artifact; + urls = map (url: mkArtifactUrl url artifact) repositories; + inherit (artifact) sha256; + }; + + phases = "installPhase fixupPhase"; + + installPhase = '' + mkdir -p $out/${artifactPath} + ln -s ${src} $out/${artifactPath}/${artifactName} + ''; + }; + +in +buildEnv { + inherit name; + paths = map fetchArtifact dependencies; +} diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 0000000..2d198e9 --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,2 @@ +include(":app") +include(":plugin")