mirror of
https://github.com/tadfisher/gradle2nix.git
synced 2026-01-11 23:40:37 -05:00
Rewrite based on code from the GitHub Dependency Graph Gradle Plugin
This commit is contained in:
@@ -1,5 +0,0 @@
|
||||
# DO NOT MODIFY: Generated by Stutter plugin.
|
||||
5.0
|
||||
5.6.4
|
||||
6.0.1
|
||||
6.8.1
|
||||
@@ -1,7 +0,0 @@
|
||||
# DO NOT MODIFY: Generated by Stutter plugin.
|
||||
4.4.1
|
||||
4.10.3
|
||||
5.0
|
||||
5.6.4
|
||||
6.0.1
|
||||
6.8.1
|
||||
@@ -1,52 +1,29 @@
|
||||
buildscript {
|
||||
configurations.classpath {
|
||||
resolutionStrategy.activateDependencyLocking()
|
||||
}
|
||||
}
|
||||
import com.github.jengelman.gradle.plugins.shadow.relocation.SimpleRelocator
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
import org.jetbrains.kotlin.gradle.utils.extendsFrom
|
||||
|
||||
plugins {
|
||||
`kotlin-dsl`
|
||||
id("org.jetbrains.kotlin.jvm")
|
||||
id("com.gradle.plugin-publish")
|
||||
id("com.github.johnrengelman.shadow")
|
||||
id("org.ajoberstar.stutter")
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
test {
|
||||
java.srcDir("src/test/kotlin")
|
||||
}
|
||||
}
|
||||
|
||||
dependencyLocking {
|
||||
lockAllConfigurations()
|
||||
}
|
||||
|
||||
configurations {
|
||||
compile {
|
||||
dependencies.remove(project.dependencies.gradleApi())
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly("org.gradle:gradle-tooling-api:${gradle.gradleVersion}")
|
||||
implementation("org.apache.maven:maven-repository-metadata:latest.release")
|
||||
implementation(project(":ivy"))
|
||||
compileOnly(kotlin("stdlib-jdk8"))
|
||||
compileOnly(kotlin("reflect"))
|
||||
implementation(project(":model"))
|
||||
shadow(gradleApi())
|
||||
implementation(libs.serialization.json)
|
||||
}
|
||||
|
||||
compatTestImplementation("com.adobe.testing:s3mock-junit5:latest.release")
|
||||
compatTestImplementation("com.squareup.okio:okio:latest.release")
|
||||
compatTestImplementation("dev.minutest:minutest:latest.release")
|
||||
compatTestImplementation("io.javalin:javalin:latest.release")
|
||||
compatTestImplementation("io.strikt:strikt-core:latest.release")
|
||||
compatTestImplementation("org.junit.jupiter:junit-jupiter-api:latest.release")
|
||||
compatTestImplementation("org.junit.jupiter:junit-jupiter-params:latest.release")
|
||||
compatTestImplementation(embeddedKotlin("reflect"))
|
||||
compatTestImplementation(embeddedKotlin("stdlib-jdk8"))
|
||||
compatTestImplementation(embeddedKotlin("test-junit5"))
|
||||
compatTestImplementation(gradleTestKit())
|
||||
compatTestImplementation(project(":model"))
|
||||
compatTestRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:latest.release")
|
||||
compatTestRuntimeOnly("org.junit.platform:junit-platform-launcher:latest.release")
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
jvmTarget.set(JvmTarget.JVM_1_8)
|
||||
}
|
||||
}
|
||||
|
||||
gradlePlugin {
|
||||
@@ -60,35 +37,25 @@ gradlePlugin {
|
||||
}
|
||||
}
|
||||
|
||||
kotlinDslPluginOptions {
|
||||
experimentalWarning.set(false)
|
||||
}
|
||||
|
||||
stutter {
|
||||
isSparse = true
|
||||
java(8) {
|
||||
compatibleRange("4.4")
|
||||
}
|
||||
java(11) {
|
||||
compatibleRange("5.0")
|
||||
}
|
||||
}
|
||||
|
||||
tasks {
|
||||
pluginUnderTestMetadata {
|
||||
pluginClasspath.setFrom(files(shadowJar))
|
||||
jar {
|
||||
manifest {
|
||||
attributes["Implementation-Version"] = archiveVersion.get()
|
||||
attributes["Implementation-Title"] = "Gradle2Nix Plugin"
|
||||
attributes["Implementation-Vendor"] = "Tad Fisher"
|
||||
}
|
||||
}
|
||||
|
||||
withType<Test> {
|
||||
useJUnitPlatform {
|
||||
includeEngines("junit-jupiter")
|
||||
}
|
||||
shadowJar {
|
||||
archiveClassifier.set("")
|
||||
relocate("kotlin", "${project.group}.shadow.kotlin")
|
||||
relocate("kotlinx.serialization", "${project.group}.shadow.serialization")
|
||||
relocate("net.swiftzer.semver", "${project.group}.shadow.semver")
|
||||
relocate("org.intellij", "${project.group}.shadow.intellij")
|
||||
relocate("org.jetbrains", "${project.group}.shadow.jetbrains")
|
||||
}
|
||||
|
||||
// Default logging config exposes a classpath conflict between
|
||||
// the Gradle API and SFL4J.
|
||||
// (Sprint Boot is used in S3Mock)
|
||||
systemProperty("org.springframework.boot.logging.LoggingSystem", "org.springframework.boot.logging.java.JavaLoggingSystem")
|
||||
|
||||
systemProperty("fixtures", "$rootDir/fixtures")
|
||||
validatePlugins {
|
||||
enableStricterValidation.set(true)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
com.github.gundy:semver4j:0.16.4=classpath
|
||||
com.google.code.gson:gson:2.8.6=classpath
|
||||
de.undercouch:gradle-download-task:4.0.2=classpath
|
||||
org.antlr:antlr4-runtime:4.5.2-1=classpath
|
||||
org.gradle.kotlin.kotlin-dsl:org.gradle.kotlin.kotlin-dsl.gradle.plugin:1.4.9=classpath
|
||||
org.gradle.kotlin:gradle-kotlin-dsl-plugins:1.4.9=classpath
|
||||
org.jetbrains.intellij.deps:trove4j:1.0.20181211=classpath
|
||||
org.jetbrains.kotlin:kotlin-android-extensions:1.4.20=classpath
|
||||
org.jetbrains.kotlin:kotlin-annotation-processing-gradle:1.4.20=classpath
|
||||
org.jetbrains.kotlin:kotlin-build-common:1.4.20=classpath
|
||||
org.jetbrains.kotlin:kotlin-compiler-embeddable:1.4.20=classpath
|
||||
org.jetbrains.kotlin:kotlin-compiler-runner:1.4.20=classpath
|
||||
org.jetbrains.kotlin:kotlin-daemon-client:1.4.20=classpath
|
||||
org.jetbrains.kotlin:kotlin-daemon-embeddable:1.4.20=classpath
|
||||
org.jetbrains.kotlin:kotlin-gradle-plugin-api:1.4.20=classpath
|
||||
org.jetbrains.kotlin:kotlin-gradle-plugin-model:1.4.20=classpath
|
||||
org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.20=classpath
|
||||
org.jetbrains.kotlin:kotlin-reflect:1.4.20=classpath
|
||||
org.jetbrains.kotlin:kotlin-sam-with-receiver:1.4.20=classpath
|
||||
org.jetbrains.kotlin:kotlin-script-runtime:1.4.20=classpath
|
||||
org.jetbrains.kotlin:kotlin-scripting-common:1.4.20=classpath
|
||||
org.jetbrains.kotlin:kotlin-scripting-compiler-embeddable:1.4.20=classpath
|
||||
org.jetbrains.kotlin:kotlin-scripting-compiler-impl-embeddable:1.4.20=classpath
|
||||
org.jetbrains.kotlin:kotlin-scripting-jvm:1.4.20=classpath
|
||||
org.jetbrains.kotlin:kotlin-stdlib-common:1.4.20=classpath
|
||||
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.4.20=classpath
|
||||
org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.4.20=classpath
|
||||
org.jetbrains.kotlin:kotlin-stdlib:1.4.20=classpath
|
||||
org.jetbrains.kotlin:kotlin-util-io:1.4.20=classpath
|
||||
org.jetbrains.kotlin:kotlin-util-klib:1.4.20=classpath
|
||||
org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7=classpath
|
||||
org.jetbrains:annotations:13.0=classpath
|
||||
empty=
|
||||
@@ -1,170 +0,0 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
ch.qos.logback:logback-classic:1.2.3=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
ch.qos.logback:logback-core:1.2.3=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
com.adobe.testing:s3mock-junit5:2.1.28=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
com.adobe.testing:s3mock-testsupport-common:2.1.28=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
com.adobe.testing:s3mock:2.1.28=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
com.amazonaws:aws-java-sdk-core:1.11.488=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
com.amazonaws:aws-java-sdk-core:1.11.946=compileClasspath,default,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
|
||||
com.amazonaws:aws-java-sdk-kms:1.11.488=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
com.amazonaws:aws-java-sdk-kms:1.11.946=compileClasspath,default,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
|
||||
com.amazonaws:aws-java-sdk-s3:1.11.488=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
com.amazonaws:aws-java-sdk-s3:1.11.946=compileClasspath,default,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
|
||||
com.amazonaws:jmespath-java:1.11.488=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
com.amazonaws:jmespath-java:1.11.946=compileClasspath,default,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
|
||||
com.christophsturm:filepeek:0.1.2=compatTestRuntimeClasspath
|
||||
com.fasterxml.jackson.core:jackson-annotations:2.6.0=compileClasspath,default,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
|
||||
com.fasterxml.jackson.core:jackson-annotations:2.9.0=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
com.fasterxml.jackson.core:jackson-core:2.6.7=compileClasspath,default,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
|
||||
com.fasterxml.jackson.core:jackson-core:2.9.9=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
com.fasterxml.jackson.core:jackson-databind:2.6.7.4=compileClasspath,default,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
|
||||
com.fasterxml.jackson.core:jackson-databind:2.9.9.3=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
com.fasterxml.jackson.dataformat:jackson-dataformat-cbor:2.6.7=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath,compileClasspath,default,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
|
||||
com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.9.9=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.9.9=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.9.9=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
com.fasterxml.jackson.module:jackson-module-jaxb-annotations:2.9.9=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
com.fasterxml.jackson.module:jackson-module-parameter-names:2.9.9=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
com.fasterxml.woodstox:woodstox-core:5.1.0=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
com.fasterxml:classmate:1.3.4=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
com.squareup.moshi:moshi:1.11.0=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath,compileClasspath,default,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
|
||||
com.squareup.okio:okio-metadata:3.0.0-alpha.1=compatTestImplementationDependenciesMetadata
|
||||
com.squareup.okio:okio:1.17.5=compileClasspath,default,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
|
||||
com.squareup.okio:okio:3.0.0-alpha.1=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
com.typesafe.netty:netty-reactive-streams-http:2.0.0=compatTestRuntimeClasspath
|
||||
com.typesafe.netty:netty-reactive-streams:2.0.0=compatTestRuntimeClasspath
|
||||
commons-codec:commons-codec:1.11=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath,compileClasspath,default,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
|
||||
commons-io:commons-io:2.6=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
commons-logging:commons-logging:1.2=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath,compileClasspath,default,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
|
||||
dev.minutest:minutest:2.0.0-alpha=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
io.github.classgraph:classgraph:4.8.28=compatTestRuntimeClasspath
|
||||
io.javalin:javalin:3.13.3=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
io.netty:netty-buffer:4.1.33.Final=compatTestRuntimeClasspath
|
||||
io.netty:netty-codec-http2:4.1.33.Final=compatTestRuntimeClasspath
|
||||
io.netty:netty-codec-http:4.1.33.Final=compatTestRuntimeClasspath
|
||||
io.netty:netty-codec:4.1.33.Final=compatTestRuntimeClasspath
|
||||
io.netty:netty-common:4.1.33.Final=compatTestRuntimeClasspath
|
||||
io.netty:netty-handler:4.1.33.Final=compatTestRuntimeClasspath
|
||||
io.netty:netty-resolver:4.1.33.Final=compatTestRuntimeClasspath
|
||||
io.netty:netty-transport-native-epoll:4.1.33.Final=compatTestRuntimeClasspath
|
||||
io.netty:netty-transport-native-unix-common:4.1.33.Final=compatTestRuntimeClasspath
|
||||
io.netty:netty-transport:4.1.33.Final=compatTestRuntimeClasspath
|
||||
io.strikt:strikt-core:0.28.2=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
javax.annotation:javax.annotation-api:1.3.2=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
javax.servlet:javax.servlet-api:3.1.0=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
javax.validation:validation-api:2.0.1.Final=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
joda-time:joda-time:2.8.1=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath,compileClasspath,default,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
|
||||
net.swiftzer.semver:semver:1.1.1=compatTestRuntimeClasspath,default,runtimeClasspath,testRuntimeClasspath
|
||||
org.apache.commons:commons-lang3:3.8.1=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.apache.httpcomponents:httpclient:4.5.13=compileClasspath,default,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
|
||||
org.apache.httpcomponents:httpclient:4.5.5=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata
|
||||
org.apache.httpcomponents:httpclient:4.5.9=compatTestRuntimeClasspath
|
||||
org.apache.httpcomponents:httpcore:4.4.11=compatTestRuntimeClasspath
|
||||
org.apache.httpcomponents:httpcore:4.4.13=compileClasspath,default,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
|
||||
org.apache.httpcomponents:httpcore:4.4.9=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata
|
||||
org.apache.ivy:ivy:2.5.0=compileClasspath,default,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
|
||||
org.apache.logging.log4j:log4j-api:2.11.2=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.apache.logging.log4j:log4j-to-slf4j:2.11.2=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.apache.maven:maven-repository-metadata:3.6.3=compileClasspath,default,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
|
||||
org.apiguardian:apiguardian-api:1.1.0=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath,compatTestRuntimeOnlyDependenciesMetadata
|
||||
org.codehaus.plexus:plexus-utils:3.2.1=compileClasspath,default,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
|
||||
org.codehaus.woodstox:stax2-api:4.1=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.eclipse.jetty.websocket:websocket-api:9.4.35.v20201120=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.eclipse.jetty.websocket:websocket-client:9.4.35.v20201120=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.eclipse.jetty.websocket:websocket-common:9.4.35.v20201120=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.eclipse.jetty.websocket:websocket-server:9.4.35.v20201120=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.eclipse.jetty.websocket:websocket-servlet:9.4.35.v20201120=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.eclipse.jetty:jetty-client:9.4.35.v20201120=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.eclipse.jetty:jetty-continuation:9.4.19.v20190610=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.eclipse.jetty:jetty-http:9.4.35.v20201120=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.eclipse.jetty:jetty-io:9.4.35.v20201120=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.eclipse.jetty:jetty-security:9.4.35.v20201120=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.eclipse.jetty:jetty-server:9.4.35.v20201120=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.eclipse.jetty:jetty-servlet:9.4.35.v20201120=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.eclipse.jetty:jetty-servlets:9.4.19.v20190610=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.eclipse.jetty:jetty-util-ajax:9.4.35.v20201120=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.eclipse.jetty:jetty-util:9.4.35.v20201120=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.eclipse.jetty:jetty-webapp:9.4.35.v20201120=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.eclipse.jetty:jetty-xml:9.4.35.v20201120=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.gradle:gradle-tooling-api:6.8.1=compileClasspath,compileOnly,compileOnlyDependenciesMetadata
|
||||
org.hibernate.validator:hibernate-validator:6.0.17.Final=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.jboss.logging:jboss-logging:3.3.2.Final=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.jetbrains.intellij.deps:trove4j:1.0.20181211=kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
|
||||
org.jetbrains.kotlin:kotlin-compiler-embeddable:1.4.20=kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
|
||||
org.jetbrains.kotlin:kotlin-daemon-embeddable:1.4.20=kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
|
||||
org.jetbrains.kotlin:kotlin-gradle-plugin-api:1.4.20=kotlinCompilerPluginClasspath
|
||||
org.jetbrains.kotlin:kotlin-gradle-plugin-model:1.4.20=kotlinCompilerPluginClasspath
|
||||
org.jetbrains.kotlin:kotlin-klib-commonizer-embeddable:1.4.20=kotlinKlibCommonizerClasspath
|
||||
org.jetbrains.kotlin:kotlin-reflect:1.4.20=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compileClasspath,compileOnly,compileOnlyDependenciesMetadata,embeddedKotlin,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
|
||||
org.jetbrains.kotlin:kotlin-reflect:1.4.21-2=compatTestRuntimeClasspath
|
||||
org.jetbrains.kotlin:kotlin-sam-with-receiver:1.4.20=kotlinCompilerPluginClasspath
|
||||
org.jetbrains.kotlin:kotlin-script-runtime:1.4.20=kotlinCompilerClasspath,kotlinCompilerPluginClasspath,kotlinKlibCommonizerClasspath
|
||||
org.jetbrains.kotlin:kotlin-scripting-common:1.4.20=kotlinCompilerPluginClasspath
|
||||
org.jetbrains.kotlin:kotlin-scripting-compiler-embeddable:1.4.20=kotlinCompilerPluginClasspath
|
||||
org.jetbrains.kotlin:kotlin-scripting-compiler-impl-embeddable:1.4.20=kotlinCompilerPluginClasspath
|
||||
org.jetbrains.kotlin:kotlin-scripting-jvm:1.4.20=kotlinCompilerPluginClasspath
|
||||
org.jetbrains.kotlin:kotlin-stdlib-common:1.4.20=compileClasspath,compileOnly,compileOnlyDependenciesMetadata,default,embeddedKotlin,implementationDependenciesMetadata,kotlinCompilerClasspath,kotlinCompilerPluginClasspath,kotlinKlibCommonizerClasspath,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
|
||||
org.jetbrains.kotlin:kotlin-stdlib-common:1.4.21-2=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.4.20=compileClasspath,compileOnly,compileOnlyDependenciesMetadata,embeddedKotlin,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
|
||||
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.4.21-2=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.4.20=compileClasspath,compileOnly,compileOnlyDependenciesMetadata,embeddedKotlin,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
|
||||
org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.4.21-2=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.jetbrains.kotlin:kotlin-stdlib:1.4.20=compileClasspath,compileOnly,compileOnlyDependenciesMetadata,default,embeddedKotlin,implementationDependenciesMetadata,kotlinCompilerClasspath,kotlinCompilerPluginClasspath,kotlinKlibCommonizerClasspath,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
|
||||
org.jetbrains.kotlin:kotlin-stdlib:1.4.21-2=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.jetbrains.kotlin:kotlin-test-annotations-common:1.4.20=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.jetbrains.kotlin:kotlin-test-common:1.4.20=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.jetbrains.kotlin:kotlin-test-junit5:1.4.20=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.jetbrains.kotlin:kotlin-test:1.4.20=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.4.2=compatTestRuntimeClasspath
|
||||
org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7=kotlinCompilerPluginClasspath
|
||||
org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.2=compatTestRuntimeClasspath
|
||||
org.jetbrains:annotations:13.0=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath,compileClasspath,compileOnly,compileOnlyDependenciesMetadata,default,embeddedKotlin,implementationDependenciesMetadata,kotlinCompilerClasspath,kotlinCompilerPluginClasspath,kotlinKlibCommonizerClasspath,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
|
||||
org.junit.jupiter:junit-jupiter-api:5.7.0=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath,compatTestRuntimeOnlyDependenciesMetadata
|
||||
org.junit.jupiter:junit-jupiter-engine:5.7.0=compatTestRuntimeClasspath,compatTestRuntimeOnlyDependenciesMetadata
|
||||
org.junit.jupiter:junit-jupiter-params:5.7.0=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.junit.platform:junit-platform-commons:1.7.0=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath,compatTestRuntimeOnlyDependenciesMetadata
|
||||
org.junit.platform:junit-platform-engine:1.7.0=compatTestRuntimeClasspath,compatTestRuntimeOnlyDependenciesMetadata
|
||||
org.junit.platform:junit-platform-launcher:1.7.0=compatTestRuntimeClasspath,compatTestRuntimeOnlyDependenciesMetadata
|
||||
org.junit:junit-bom:5.7.0=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath,compatTestRuntimeOnlyDependenciesMetadata
|
||||
org.mortbay.jasper:apache-el:8.5.40=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.opentest4j:opentest4j:1.2.0=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath,compatTestRuntimeOnlyDependenciesMetadata
|
||||
org.reactivestreams:reactive-streams:1.0.2=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.slf4j:jul-to-slf4j:1.7.28=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.slf4j:slf4j-api:1.7.28=compileClasspath,compileOnly,compileOnlyDependenciesMetadata
|
||||
org.slf4j:slf4j-api:1.7.30=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.springframework.boot:spring-boot-autoconfigure:2.1.9.RELEASE=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.springframework.boot:spring-boot-starter-jetty:2.1.9.RELEASE=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.springframework.boot:spring-boot-starter-json:2.1.9.RELEASE=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.springframework.boot:spring-boot-starter-logging:2.1.9.RELEASE=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.springframework.boot:spring-boot-starter-web:2.1.9.RELEASE=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.springframework.boot:spring-boot-starter:2.1.9.RELEASE=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.springframework.boot:spring-boot:2.1.9.RELEASE=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.springframework:spring-aop:5.1.10.RELEASE=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.springframework:spring-beans:5.1.10.RELEASE=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.springframework:spring-context:5.1.10.RELEASE=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.springframework:spring-core:5.1.10.RELEASE=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.springframework:spring-expression:5.1.10.RELEASE=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.springframework:spring-jcl:5.1.10.RELEASE=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.springframework:spring-web:5.1.10.RELEASE=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.springframework:spring-webmvc:5.1.10.RELEASE=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
org.yaml:snakeyaml:1.23=compatTestRuntimeClasspath
|
||||
software.amazon.awssdk:annotations:2.7.19=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
software.amazon.awssdk:apache-client:2.7.19=compatTestRuntimeClasspath
|
||||
software.amazon.awssdk:auth:2.7.19=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
software.amazon.awssdk:aws-core:2.7.19=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
software.amazon.awssdk:aws-query-protocol:2.7.19=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
software.amazon.awssdk:aws-xml-protocol:2.7.19=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
software.amazon.awssdk:http-client-spi:2.7.19=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
software.amazon.awssdk:netty-nio-client:2.7.19=compatTestRuntimeClasspath
|
||||
software.amazon.awssdk:profiles:2.7.19=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
software.amazon.awssdk:protocol-core:2.7.19=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
software.amazon.awssdk:regions:2.7.19=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
software.amazon.awssdk:s3:2.7.19=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
software.amazon.awssdk:sdk-core:2.7.19=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
software.amazon.awssdk:url-connection-client:2.7.19=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
software.amazon.awssdk:utils:2.7.19=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
software.amazon.eventstream:eventstream:1.0.1=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath
|
||||
software.amazon.ion:ion-java:1.0.2=compatTestCompileClasspath,compatTestImplementationDependenciesMetadata,compatTestRuntimeClasspath,compileClasspath,default,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
|
||||
empty=annotationProcessor,apiDependenciesMetadata,archives,compatTestAnnotationProcessor,compatTestApiDependenciesMetadata,compatTestCompile,compatTestCompileOnly,compatTestCompileOnlyDependenciesMetadata,compatTestKotlinScriptDef,compatTestKotlinScriptDefExtensions,compatTestRuntime,compile,kotlinNativeCompilerPluginClasspath,kotlinScriptDef,kotlinScriptDefExtensions,runtime,runtimeOnlyDependenciesMetadata,shadow,testAnnotationProcessor,testApiDependenciesMetadata,testCompile,testCompileOnly,testCompileOnlyDependenciesMetadata,testKotlinScriptDef,testKotlinScriptDefExtensions,testRuntime,testRuntimeOnlyDependenciesMetadata
|
||||
@@ -1,74 +0,0 @@
|
||||
package org.nixos.gradle2nix
|
||||
|
||||
import dev.minutest.Tests
|
||||
import dev.minutest.experimental.minus
|
||||
import dev.minutest.junit.JUnit5Minutests
|
||||
import dev.minutest.rootContext
|
||||
import dev.minutest.test
|
||||
import org.gradle.api.internal.artifacts.dsl.DefaultRepositoryHandler.BINTRAY_JCENTER_URL
|
||||
import org.gradle.api.internal.artifacts.dsl.DefaultRepositoryHandler.MAVEN_CENTRAL_URL
|
||||
import strikt.api.expectThat
|
||||
import strikt.assertions.all
|
||||
import strikt.assertions.containsExactly
|
||||
import strikt.assertions.flatMap
|
||||
import strikt.assertions.get
|
||||
import strikt.assertions.hasSize
|
||||
import strikt.assertions.isEqualTo
|
||||
import strikt.assertions.map
|
||||
import strikt.assertions.none
|
||||
import strikt.assertions.startsWith
|
||||
|
||||
class BasicTest : JUnit5Minutests {
|
||||
@Tests
|
||||
fun tests() = rootContext("basic tests") {
|
||||
withFixture("basic/basic-java-project") {
|
||||
test("builds basic java project") {
|
||||
expectThat(build()) {
|
||||
get("gradle version") { gradle.version }.isEqualTo(System.getProperty("compat.gradle.version"))
|
||||
|
||||
get("all dependencies") {
|
||||
pluginDependencies +
|
||||
rootProject.buildscriptDependencies +
|
||||
rootProject.projectDependencies
|
||||
}.flatMap { it.urls }.none { startsWith("file:") }
|
||||
|
||||
get("root project dependencies") { rootProject.projectDependencies }.and {
|
||||
ids.containsExactly(
|
||||
"com.squareup.moshi:moshi:1.8.0@jar",
|
||||
"com.squareup.moshi:moshi:1.8.0@pom",
|
||||
"com.squareup.moshi:moshi-parent:1.8.0@pom",
|
||||
"com.squareup.okio:okio:2.2.2@jar",
|
||||
"com.squareup.okio:okio:2.2.2@pom",
|
||||
"org.jetbrains:annotations:13.0@jar",
|
||||
"org.jetbrains:annotations:13.0@pom",
|
||||
"org.jetbrains.kotlin:kotlin-stdlib:1.2.60@jar",
|
||||
"org.jetbrains.kotlin:kotlin-stdlib:1.2.60@pom",
|
||||
"org.jetbrains.kotlin:kotlin-stdlib-common:1.2.60@jar",
|
||||
"org.jetbrains.kotlin:kotlin-stdlib-common:1.2.60@pom",
|
||||
"org.sonatype.oss:oss-parent:7@pom"
|
||||
)
|
||||
|
||||
map { it.urls }.all {
|
||||
hasSize(2)
|
||||
get(0).startsWith(BINTRAY_JCENTER_URL)
|
||||
get(1).startsWith(MAVEN_CENTRAL_URL)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
withFixture("basic/basic-kotlin-project") {
|
||||
GRADLE_MIN("4.9") - test("excludes embedded kotlin repo") {
|
||||
|
||||
expectThat(build()) {
|
||||
get("all dependencies") {
|
||||
pluginDependencies +
|
||||
rootProject.buildscriptDependencies +
|
||||
rootProject.projectDependencies
|
||||
}.flatMap { it.urls }.all { not { startsWith("file:") } }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
package org.nixos.gradle2nix
|
||||
|
||||
import dev.minutest.Tests
|
||||
import dev.minutest.experimental.minus
|
||||
import dev.minutest.junit.JUnit5Minutests
|
||||
import dev.minutest.rootContext
|
||||
import dev.minutest.test
|
||||
import strikt.api.expectThat
|
||||
import strikt.assertions.all
|
||||
import strikt.assertions.containsExactly
|
||||
import strikt.assertions.filter
|
||||
import strikt.assertions.isEqualTo
|
||||
import strikt.assertions.isNotNull
|
||||
import strikt.assertions.isNull
|
||||
|
||||
class DependencyTest : JUnit5Minutests {
|
||||
@Tests
|
||||
fun tests() = rootContext("dependency tests") {
|
||||
|
||||
withRepository("m2") {
|
||||
|
||||
withFixture("dependency/classifier") {
|
||||
test("resolves dependency with classifier") {
|
||||
expectThat(build()) {
|
||||
get("root project dependencies") { rootProject.projectDependencies }.ids.containsExactly(
|
||||
"com.badlogicgames.gdx:gdx-parent:1.9.9@pom",
|
||||
"com.badlogicgames.gdx:gdx-platform:1.9.9:natives-desktop@jar",
|
||||
"com.badlogicgames.gdx:gdx-platform:1.9.9@pom",
|
||||
"org.sonatype.oss:oss-parent:5@pom"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
withFixture("dependency/maven-bom") {
|
||||
GRADLE_MIN("5.0") - test("resolves dependencies from maven bom platform") {
|
||||
expectThat(build()) {
|
||||
get("root project dependencies") { rootProject.projectDependencies }
|
||||
.ids
|
||||
.containsExactly(
|
||||
"io.micrometer:micrometer-bom:1.5.1@pom",
|
||||
"io.micrometer:micrometer-core:1.5.1@jar",
|
||||
"io.micrometer:micrometer-core:1.5.1@pom",
|
||||
"org.hdrhistogram:HdrHistogram:2.1.12@jar",
|
||||
"org.hdrhistogram:HdrHistogram:2.1.12@pom"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
withFixture("dependency/snapshot") {
|
||||
test("resolves snapshot dependency") {
|
||||
expectThat(build()) {
|
||||
get("root project dependencies") { rootProject.projectDependencies }
|
||||
.and {
|
||||
ids.containsExactly(
|
||||
"org.apache:test-SNAPSHOT2:2.0.2-SNAPSHOT@jar",
|
||||
"org.apache:test-SNAPSHOT2:2.0.2-SNAPSHOT@pom"
|
||||
)
|
||||
all {
|
||||
get("timestamp") { timestamp }.isNull()
|
||||
get("build") { build }.isNotNull()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
withFixture("dependency/snapshot-dynamic") {
|
||||
test("resolves snapshot dependency with dynamic version") {
|
||||
expectThat(build()) {
|
||||
get("root project dependencies") { rootProject.projectDependencies }
|
||||
.and {
|
||||
ids.containsExactly(
|
||||
"org.apache:test-SNAPSHOT1:2.0.2-SNAPSHOT@jar",
|
||||
"org.apache:test-SNAPSHOT1:2.0.2-SNAPSHOT@pom"
|
||||
)
|
||||
all {
|
||||
get("timestamp") { timestamp }.isEqualTo("20070310.181613")
|
||||
get("build") { build }.isEqualTo(3)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
withFixture("dependency/snapshot-redirect") {
|
||||
test("resolves snapshot dependency with redirect") {
|
||||
expectThat(build()) {
|
||||
get("root project dependencies") { rootProject.projectDependencies }
|
||||
.filter { it.id.name == "packr" }
|
||||
.all {
|
||||
get("id.version") { id.version }.isEqualTo("-SNAPSHOT")
|
||||
get("timestamp") { timestamp }.isNotNull()
|
||||
get("build") { build }.isNotNull()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package org.nixos.gradle2nix
|
||||
|
||||
import dev.minutest.Tests
|
||||
import dev.minutest.junit.JUnit5Minutests
|
||||
import dev.minutest.rootContext
|
||||
import dev.minutest.test
|
||||
import strikt.api.expectThat
|
||||
import strikt.assertions.all
|
||||
import strikt.assertions.containsExactly
|
||||
import strikt.assertions.map
|
||||
import strikt.assertions.single
|
||||
import strikt.assertions.startsWith
|
||||
|
||||
class IvyTest : JUnit5Minutests {
|
||||
@Tests
|
||||
fun tests() = rootContext("ivy tests") {
|
||||
withFixture("ivy/basic") {
|
||||
test("resolves ivy dependencies") {
|
||||
expectThat(build()) {
|
||||
get("root project dependencies") { rootProject.projectDependencies }.and {
|
||||
ids.containsExactly(
|
||||
"org.opendof.core-java:dof-cipher-sms4:1.0@jar",
|
||||
"org.opendof.core-java:dof-oal:7.0.2@jar"
|
||||
)
|
||||
|
||||
map { it.urls }.all {
|
||||
single().startsWith("https://asset.opendof.org/artifact")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package org.nixos.gradle2nix
|
||||
|
||||
import dev.minutest.Tests
|
||||
import dev.minutest.experimental.FOCUS
|
||||
import dev.minutest.experimental.minus
|
||||
import dev.minutest.junit.JUnit5Minutests
|
||||
import dev.minutest.rootContext
|
||||
import dev.minutest.test
|
||||
import strikt.api.expectThat
|
||||
import strikt.assertions.contains
|
||||
import strikt.assertions.containsExactly
|
||||
|
||||
class PluginTest : JUnit5Minutests {
|
||||
@Tests
|
||||
fun tests() = rootContext("plugin tests") {
|
||||
withFixture("plugin/resolves-from-default-repo") {
|
||||
test("resolves plugin from default repo") {
|
||||
expectThat(build()) {
|
||||
get("plugin dependencies") { pluginDependencies }.ids
|
||||
.contains("org.jetbrains.kotlin.jvm:org.jetbrains.kotlin.jvm.gradle.plugin:1.3.50@pom")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
package org.nixos.gradle2nix
|
||||
|
||||
import dev.minutest.Tests
|
||||
import dev.minutest.junit.JUnit5Minutests
|
||||
import dev.minutest.rootContext
|
||||
import dev.minutest.test
|
||||
import strikt.api.expectThat
|
||||
import strikt.assertions.containsExactly
|
||||
import strikt.assertions.flatMap
|
||||
import strikt.assertions.map
|
||||
|
||||
class S3Test : JUnit5Minutests {
|
||||
@Tests
|
||||
fun tests() = rootContext("s3 tests") {
|
||||
withBucket("repositories") {
|
||||
withFixture("s3/maven") {
|
||||
|
||||
test("dependency from s3 maven repo") {
|
||||
expectThat(build()) {
|
||||
get("root project dependencies") { rootProject.projectDependencies }.and {
|
||||
ids.containsExactly(
|
||||
"org.apache:test:1.0.0@jar",
|
||||
"org.apache:test:1.0.0@pom"
|
||||
)
|
||||
flatMap { it.urls }.containsExactly(
|
||||
"s3://repositories/m2/org/apache/test/1.0.0/test-1.0.0.jar",
|
||||
"s3://repositories/m2/org/apache/test/1.0.0/test-1.0.0.pom"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
withFixture("s3/maven-snapshot") {
|
||||
test("snapshot dependency from s3 maven repo") {
|
||||
expectThat(build()) {
|
||||
get("root project dependencies") { rootProject.projectDependencies }.and {
|
||||
ids.containsExactly(
|
||||
"org.apache:test-SNAPSHOT1:2.0.0-SNAPSHOT@jar",
|
||||
"org.apache:test-SNAPSHOT1:2.0.0-SNAPSHOT@pom"
|
||||
)
|
||||
flatMap { it.urls }.containsExactly(
|
||||
"s3://repositories/m2/org/apache/test-SNAPSHOT1/2.0.0-SNAPSHOT/test-SNAPSHOT1-2.0.0-20070310.181613-3.jar",
|
||||
"s3://repositories/m2/org/apache/test-SNAPSHOT1/2.0.0-SNAPSHOT/test-SNAPSHOT1-2.0.0-20070310.181613-3.pom"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package org.nixos.gradle2nix
|
||||
|
||||
import dev.minutest.Tests
|
||||
import dev.minutest.experimental.minus
|
||||
import dev.minutest.junit.JUnit5Minutests
|
||||
import dev.minutest.rootContext
|
||||
import dev.minutest.test
|
||||
import strikt.api.expectThat
|
||||
import strikt.assertions.containsExactly
|
||||
|
||||
class SettingsTest : JUnit5Minutests {
|
||||
@Tests
|
||||
fun tests() = rootContext("settings tests") {
|
||||
withRepository("m2") {
|
||||
|
||||
withFixture("settings/buildscript") {
|
||||
test("resolves settings plugin in buildscript classpath") {
|
||||
expectThat(build()) {
|
||||
get("settings dependencies") { settingsDependencies }.ids.containsExactly(
|
||||
"org.apache:test:1.0.0@jar",
|
||||
"org.apache:test:1.0.0@pom"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
withFixture("settings/dependency-resolution-management") {
|
||||
GRADLE_MIN("6.8") - test("uses repositories from settings script") {
|
||||
expectThat(build()) {
|
||||
get("root project dependencies") { rootProject.projectDependencies }.ids.containsExactly(
|
||||
"org.apache:test:1.0.0@jar",
|
||||
"org.apache:test:1.0.0@pom"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
package org.nixos.gradle2nix
|
||||
|
||||
import dev.minutest.Tests
|
||||
import dev.minutest.junit.JUnit5Minutests
|
||||
import dev.minutest.rootContext
|
||||
import dev.minutest.test
|
||||
import org.gradle.api.internal.artifacts.dsl.DefaultRepositoryHandler.BINTRAY_JCENTER_URL
|
||||
import strikt.api.expectThat
|
||||
import strikt.assertions.all
|
||||
import strikt.assertions.containsExactly
|
||||
import strikt.assertions.containsExactlyInAnyOrder
|
||||
import strikt.assertions.get
|
||||
import strikt.assertions.hasSize
|
||||
import strikt.assertions.isEqualTo
|
||||
import strikt.assertions.map
|
||||
import strikt.assertions.single
|
||||
import strikt.assertions.startsWith
|
||||
|
||||
class SubprojectsTest : JUnit5Minutests {
|
||||
@Tests
|
||||
fun tests() = rootContext("subproject tests") {
|
||||
withFixture("subprojects/multi-module") {
|
||||
test("builds multi-module project") {
|
||||
expectThat(build().rootProject) {
|
||||
get("root project dependencies") { projectDependencies }.and {
|
||||
ids.containsExactly(
|
||||
"junit:junit:4.12@jar",
|
||||
"junit:junit:4.12@pom",
|
||||
"org.hamcrest:hamcrest-core:1.3@jar",
|
||||
"org.hamcrest:hamcrest-core:1.3@pom",
|
||||
"org.hamcrest:hamcrest-parent:1.3@pom"
|
||||
)
|
||||
all {
|
||||
get("urls") { urls }.single().startsWith(BINTRAY_JCENTER_URL)
|
||||
}
|
||||
}
|
||||
|
||||
get("children") { children }.and {
|
||||
hasSize(2)
|
||||
|
||||
get(0).and {
|
||||
get("name") { name }.isEqualTo("child-a")
|
||||
get("projectDir") { projectDir }.isEqualTo("child-a")
|
||||
|
||||
get("child-a project dependencies") { projectDependencies }.and {
|
||||
ids.containsExactly(
|
||||
"com.squareup.okio:okio:2.2.2@jar",
|
||||
"com.squareup.okio:okio:2.2.2@pom",
|
||||
"org.jetbrains:annotations:13.0@jar",
|
||||
"org.jetbrains:annotations:13.0@pom",
|
||||
"org.jetbrains.kotlin:kotlin-stdlib:1.2.60@jar",
|
||||
"org.jetbrains.kotlin:kotlin-stdlib:1.2.60@pom",
|
||||
"org.jetbrains.kotlin:kotlin-stdlib-common:1.2.60@jar",
|
||||
"org.jetbrains.kotlin:kotlin-stdlib-common:1.2.60@pom"
|
||||
)
|
||||
|
||||
all {
|
||||
get("urls") { urls }.single().startsWith(BINTRAY_JCENTER_URL)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get(1).and {
|
||||
get("name") { name }.isEqualTo("child-b")
|
||||
get("projectDir") { projectDir }.isEqualTo("child-b")
|
||||
|
||||
get("child-b project dependencies") { projectDependencies }.and {
|
||||
ids.containsExactly(
|
||||
"com.squareup.moshi:moshi:1.8.0@jar",
|
||||
"com.squareup.moshi:moshi:1.8.0@pom",
|
||||
"com.squareup.moshi:moshi-parent:1.8.0@pom",
|
||||
"com.squareup.okio:okio:1.16.0@jar", // compileClasspath
|
||||
"com.squareup.okio:okio:1.16.0@pom", // compileClasspath
|
||||
"com.squareup.okio:okio:2.2.2@jar", // runtimeClasspath
|
||||
"com.squareup.okio:okio:2.2.2@pom", // runtimeClasspath
|
||||
"com.squareup.okio:okio-parent:1.16.0@pom", // compileClasspath
|
||||
"org.jetbrains:annotations:13.0@jar",
|
||||
"org.jetbrains:annotations:13.0@pom",
|
||||
"org.jetbrains.kotlin:kotlin-stdlib:1.2.60@jar",
|
||||
"org.jetbrains.kotlin:kotlin-stdlib:1.2.60@pom",
|
||||
"org.jetbrains.kotlin:kotlin-stdlib-common:1.2.60@jar",
|
||||
"org.jetbrains.kotlin:kotlin-stdlib-common:1.2.60@pom",
|
||||
"org.sonatype.oss:oss-parent:7@pom"
|
||||
)
|
||||
|
||||
all {
|
||||
get("urls") { urls }.single().startsWith(BINTRAY_JCENTER_URL)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test("builds single subproject") {
|
||||
expectThat(build(subprojects = listOf(":child-a")).rootProject) {
|
||||
get("root project dependencies") { projectDependencies }.and {
|
||||
ids.containsExactly(
|
||||
"junit:junit:4.12@jar",
|
||||
"junit:junit:4.12@pom",
|
||||
"org.hamcrest:hamcrest-core:1.3@jar",
|
||||
"org.hamcrest:hamcrest-core:1.3@pom",
|
||||
"org.hamcrest:hamcrest-parent:1.3@pom"
|
||||
)
|
||||
|
||||
all {
|
||||
get("urls") { urls }.single().startsWith(BINTRAY_JCENTER_URL)
|
||||
}
|
||||
}
|
||||
|
||||
get("children") { children }.single().and {
|
||||
get("name") { name }.isEqualTo("child-a")
|
||||
get("projectDir") { projectDir }.isEqualTo("child-a")
|
||||
|
||||
get("child-a project dependencies") { projectDependencies }.and {
|
||||
ids.containsExactly(
|
||||
"com.squareup.okio:okio:2.2.2@jar",
|
||||
"com.squareup.okio:okio:2.2.2@pom",
|
||||
"org.jetbrains:annotations:13.0@jar",
|
||||
"org.jetbrains:annotations:13.0@pom",
|
||||
"org.jetbrains.kotlin:kotlin-stdlib:1.2.60@jar",
|
||||
"org.jetbrains.kotlin:kotlin-stdlib:1.2.60@pom",
|
||||
"org.jetbrains.kotlin:kotlin-stdlib-common:1.2.60@jar",
|
||||
"org.jetbrains.kotlin:kotlin-stdlib-common:1.2.60@pom"
|
||||
)
|
||||
|
||||
all {
|
||||
get("urls") { urls }.single().startsWith(BINTRAY_JCENTER_URL)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
withFixture("subprojects/dependent-subprojects") {
|
||||
test("includes dependent subprojects") {
|
||||
expectThat(build(subprojects = listOf(":child-a"))) {
|
||||
get("children") { rootProject.children }
|
||||
.map { it.path }
|
||||
.containsExactlyInAnyOrder(":child-a", ":child-b", ":child-c")
|
||||
}
|
||||
|
||||
expectThat(build(subprojects = listOf(":child-b"))) {
|
||||
get("children") { rootProject.children }
|
||||
.map { it.path }
|
||||
.containsExactlyInAnyOrder(":child-b", ":child-c")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,300 +0,0 @@
|
||||
package org.nixos.gradle2nix
|
||||
|
||||
import com.adobe.testing.s3mock.S3MockApplication
|
||||
import com.adobe.testing.s3mock.junit5.S3MockExtension
|
||||
import com.adobe.testing.s3mock.testsupport.common.S3MockStarter
|
||||
import com.squareup.moshi.Moshi
|
||||
import dev.minutest.ContextBuilder
|
||||
import dev.minutest.MinutestFixture
|
||||
import dev.minutest.Node
|
||||
import dev.minutest.TestContextBuilder
|
||||
import dev.minutest.afterEach
|
||||
import dev.minutest.beforeEach
|
||||
import dev.minutest.experimental.SKIP
|
||||
import dev.minutest.experimental.TransformingAnnotation
|
||||
import dev.minutest.given
|
||||
import dev.minutest.givenClosable
|
||||
import dev.minutest.given_
|
||||
import io.javalin.Javalin
|
||||
import io.javalin.http.staticfiles.Location
|
||||
import okio.buffer
|
||||
import okio.source
|
||||
import org.gradle.internal.classpath.DefaultClassPath
|
||||
import org.gradle.testkit.runner.GradleRunner
|
||||
import org.gradle.testkit.runner.internal.PluginUnderTestMetadataReading
|
||||
import org.gradle.util.GradleVersion
|
||||
import org.junit.jupiter.api.Assumptions.assumeTrue
|
||||
import strikt.api.Assertion
|
||||
import strikt.assertions.map
|
||||
import java.io.Closeable
|
||||
import java.io.File
|
||||
import java.io.StringWriter
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
|
||||
private val moshi = Moshi.Builder().build()
|
||||
|
||||
val fixtureRoot = File(System.getProperty("fixtures"))
|
||||
|
||||
val gradleVersion = System.getProperty("compat.gradle.version")
|
||||
?.let(GradleVersion::version)
|
||||
?: GradleVersion.current()
|
||||
|
||||
val GRADLE_4_5 = GradleVersion.version("4.5")
|
||||
|
||||
fun GRADLE_MIN(version: String) = object : TransformingAnnotation() {
|
||||
override fun <F> transform(node: Node<F>): Node<F> =
|
||||
if (gradleVersion < GradleVersion.version(version)) SKIP.transform(node) else node
|
||||
}
|
||||
|
||||
private fun File.initscript() = resolve("init.gradle").also {
|
||||
it.writer().use { out ->
|
||||
val classpath = DefaultClassPath.of(PluginUnderTestMetadataReading.readImplementationClasspath())
|
||||
.asFiles.joinToString { n -> "'$n'" }
|
||||
out.append("""
|
||||
initscript {
|
||||
dependencies {
|
||||
classpath files($classpath)
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: org.nixos.gradle2nix.Gradle2NixPlugin
|
||||
|
||||
""".trimIndent())
|
||||
}
|
||||
}
|
||||
|
||||
fun File.buildKotlin(
|
||||
script: String,
|
||||
configurations: List<String> = emptyList(),
|
||||
subprojects: List<String> = emptyList()
|
||||
): DefaultBuild {
|
||||
assumeTrue(gradleVersion >= GRADLE_4_5)
|
||||
resolve("build.gradle.kts").writeText(script)
|
||||
return build(configurations, subprojects)
|
||||
}
|
||||
|
||||
private fun File.build(
|
||||
configurations: List<String>,
|
||||
subprojects: List<String>,
|
||||
extraArguments: List<String> = emptyList()
|
||||
): DefaultBuild {
|
||||
val log = StringWriter()
|
||||
|
||||
val result = GradleRunner.create()
|
||||
.withGradleVersion(gradleVersion.version)
|
||||
.withProjectDir(this)
|
||||
.forwardStdOutput(log)
|
||||
.forwardStdError(log)
|
||||
.withArguments(
|
||||
"nixModel",
|
||||
"--init-script=${initscript()}",
|
||||
"--stacktrace",
|
||||
"-Porg.nixos.gradle2nix.configurations=${configurations.joinToString(",")}",
|
||||
"-Porg.nixos.gradle2nix.subprojects=${subprojects.joinToString(",")}",
|
||||
*(extraArguments.toTypedArray())
|
||||
)
|
||||
.runCatching { build() }
|
||||
|
||||
result.onFailure { error ->
|
||||
System.err.print(log)
|
||||
throw error
|
||||
}
|
||||
|
||||
print(log)
|
||||
|
||||
return resolve("build/nix/model.json").run {
|
||||
println(readText())
|
||||
source().buffer().use { src ->
|
||||
checkNotNull(moshi.adapter(DefaultBuild::class.java).fromJson(src))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val <T : Iterable<Artifact>> Assertion.Builder<T>.ids: Assertion.Builder<Iterable<String>>
|
||||
get() = map { it.id.toString() }
|
||||
|
||||
private fun File.parents() = generateSequence(parentFile) { it.parentFile }
|
||||
|
||||
abstract class ArgumentsSupplier(private val parent: ArgumentsSupplier? = null) {
|
||||
open val arguments: List<String> = emptyList()
|
||||
|
||||
val extraArguments: List<String> get() = (parent?.extraArguments ?: emptyList()) + arguments
|
||||
}
|
||||
|
||||
@MinutestFixture
|
||||
class RepositoryFixture(
|
||||
private val server: Javalin,
|
||||
parent: ArgumentsSupplier? = null
|
||||
) : ArgumentsSupplier(parent), Closeable {
|
||||
override fun close() {
|
||||
server.stop()
|
||||
}
|
||||
}
|
||||
|
||||
@MinutestFixture
|
||||
class S3Fixture(
|
||||
private val name: String,
|
||||
parent: ArgumentsSupplier? = null
|
||||
) : ArgumentsSupplier(parent), Closeable {
|
||||
private val s3mock = S3Mock(
|
||||
initialBuckets = listOf(name),
|
||||
secureConnection = false
|
||||
)
|
||||
|
||||
override val arguments: List<String> get() = listOf(
|
||||
"-Dorg.gradle.s3.endpoint=${s3mock.serviceEndpoint}",
|
||||
"-Dorg.nixos.gradle2nix.s3test=true"
|
||||
)
|
||||
|
||||
init {
|
||||
s3mock.startServer()
|
||||
|
||||
val s3root = fixtureRoot.resolve(name)
|
||||
val s3client = s3mock.createS3Client()
|
||||
require(s3root.exists() && s3root.isDirectory) {
|
||||
"$name: S3 fixture not found: $s3root"
|
||||
}
|
||||
s3root.walkTopDown()
|
||||
.filter { it.isFile }
|
||||
.forEach { file ->
|
||||
val key = file.toRelativeString(s3root)
|
||||
s3client.putObject(name, key, file)
|
||||
}
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
s3mock.stopServer()
|
||||
}
|
||||
}
|
||||
|
||||
@MinutestFixture
|
||||
class TestFixture(
|
||||
val name: String,
|
||||
val source: File,
|
||||
parent: ArgumentsSupplier? = null
|
||||
) : ArgumentsSupplier(parent), Closeable {
|
||||
val dest: File
|
||||
|
||||
init {
|
||||
require(source.exists() && source.isDirectory) {
|
||||
"$name: Test fixture not found: $source}"
|
||||
}
|
||||
dest = createTempDir(prefix = name, suffix = "")
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
dest.deleteRecursively()
|
||||
}
|
||||
}
|
||||
|
||||
@MinutestFixture
|
||||
data class ProjectFixture(
|
||||
private val parent: TestFixture,
|
||||
private val source: File
|
||||
) : Closeable {
|
||||
private val dest: File
|
||||
|
||||
init {
|
||||
require(source.exists() && source.isDirectory && parent.source in source.parents()) {
|
||||
"${parent.name}: Test project not found: $source"
|
||||
}
|
||||
val rel = source.toRelativeString(parent.source)
|
||||
dest = parent.dest.resolve(rel)
|
||||
}
|
||||
|
||||
fun copySource() {
|
||||
source.copyRecursively(dest, true)
|
||||
}
|
||||
|
||||
fun build(
|
||||
configurations: List<String> = emptyList(),
|
||||
subprojects: List<String> = emptyList()
|
||||
) = dest.build(configurations, subprojects, parent.extraArguments)
|
||||
|
||||
override fun close() {
|
||||
dest.deleteRecursively()
|
||||
}
|
||||
}
|
||||
|
||||
fun ContextBuilder<*>.withBucket(
|
||||
name: String,
|
||||
block: TestContextBuilder<*, S3Fixture>.() -> Unit
|
||||
) = derivedContext<S3Fixture>("with s3 bucket: $name") {
|
||||
given_ { parent ->
|
||||
S3Fixture(name, parent as? ArgumentsSupplier)
|
||||
}
|
||||
|
||||
afterEach { it.close() }
|
||||
|
||||
block()
|
||||
}
|
||||
|
||||
fun ContextBuilder<*>.withRepository(
|
||||
name: String,
|
||||
block: TestContextBuilder<*, RepositoryFixture>.() -> Unit
|
||||
) = derivedContext<RepositoryFixture>("with repository: $name") {
|
||||
given_ { parent ->
|
||||
RepositoryFixture(
|
||||
server = Javalin.create { config ->
|
||||
config.addStaticFiles("${fixtureRoot}/repositories/$name", Location.EXTERNAL)
|
||||
}.start(9999),
|
||||
parent = parent as? ArgumentsSupplier
|
||||
)
|
||||
}
|
||||
|
||||
afterEach { it.close() }
|
||||
|
||||
block()
|
||||
}
|
||||
|
||||
fun ContextBuilder<*>.withFixture(
|
||||
name: String,
|
||||
block: TestContextBuilder<*, ProjectFixture>.() -> Unit
|
||||
) = derivedContext<TestFixture>(name) {
|
||||
|
||||
val projectRoot = fixtureRoot.resolve(name).also {
|
||||
check(it.exists()) { "$name: project fixture not found: $it" }
|
||||
}
|
||||
|
||||
given_ { parent ->
|
||||
TestFixture(name, projectRoot, parent as? ArgumentsSupplier)
|
||||
}
|
||||
|
||||
val testRoots = projectRoot.listFiles()!!
|
||||
.filter { it.isDirectory }
|
||||
.map { it.absoluteFile }
|
||||
.toList()
|
||||
|
||||
testRoots.forEach { testRoot ->
|
||||
derivedContext<ProjectFixture>(testRoot.name) {
|
||||
given_ { parent -> ProjectFixture(parent, testRoot) }
|
||||
beforeEach { copySource() }
|
||||
afterEach { close() }
|
||||
block()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class S3Mock(
|
||||
initialBuckets: List<String> = emptyList(),
|
||||
secureConnection: Boolean = true
|
||||
) : S3MockStarter(
|
||||
mapOf(
|
||||
S3MockApplication.PROP_INITIAL_BUCKETS to initialBuckets.joinToString(","),
|
||||
S3MockApplication.PROP_SECURE_CONNECTION to secureConnection
|
||||
)
|
||||
) {
|
||||
private val running = AtomicBoolean()
|
||||
|
||||
fun startServer() {
|
||||
if (running.compareAndSet(false, true)) {
|
||||
start()
|
||||
}
|
||||
}
|
||||
|
||||
fun stopServer() {
|
||||
if (running.compareAndSet(true, false)) {
|
||||
stop()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package org.nixos.gradle2nix
|
||||
|
||||
import dev.minutest.Tests
|
||||
import dev.minutest.given
|
||||
import dev.minutest.junit.JUnit5Minutests
|
||||
import dev.minutest.rootContext
|
||||
import dev.minutest.test
|
||||
import strikt.api.expectThat
|
||||
import strikt.assertions.isEqualTo
|
||||
import java.io.File
|
||||
|
||||
class WrapperTest : JUnit5Minutests {
|
||||
@Tests
|
||||
fun tests() = rootContext<File>("wrapper tests") {
|
||||
given { createTempDir("gradle2nix") }
|
||||
|
||||
test("resolves gradle wrapper version") {
|
||||
expectThat(buildKotlin("""
|
||||
tasks.withType<org.gradle.api.tasks.wrapper.Wrapper> {
|
||||
gradleVersion = "5.5.1"
|
||||
}
|
||||
""".trimIndent())) {
|
||||
get("gradle version") { gradle.version }.isEqualTo("5.5.1")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package org.nixos.gradle2nix;
|
||||
|
||||
import org.gradle.api.artifacts.Dependency;
|
||||
import org.gradle.api.internal.artifacts.dependencies.DefaultExternalModuleDependency;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Workarounds for APIs improperly marked with @NonNullApi.
|
||||
*/
|
||||
interface ApiHack {
|
||||
static Dependency defaultExternalModuleDependency(String group, String name, @Nullable String version) {
|
||||
return new DefaultExternalModuleDependency(group, name, version);
|
||||
}
|
||||
}
|
||||
@@ -1,303 +0,0 @@
|
||||
package org.nixos.gradle2nix
|
||||
|
||||
import org.apache.ivy.Ivy
|
||||
import org.apache.ivy.core.settings.IvySettings
|
||||
import org.apache.ivy.plugins.parser.m2.PomReader
|
||||
import org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorParser
|
||||
import org.apache.ivy.plugins.repository.url.URLResource
|
||||
import org.apache.ivy.plugins.resolver.ChainResolver
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.artifacts.Configuration
|
||||
import org.gradle.api.artifacts.ModuleIdentifier
|
||||
import org.gradle.api.artifacts.ResolvedArtifact
|
||||
import org.gradle.api.artifacts.component.ComponentArtifactIdentifier
|
||||
import org.gradle.api.artifacts.component.ModuleComponentIdentifier
|
||||
import org.gradle.api.artifacts.dsl.DependencyHandler
|
||||
import org.gradle.api.artifacts.dsl.RepositoryHandler
|
||||
import org.gradle.api.artifacts.query.ArtifactResolutionQuery
|
||||
import org.gradle.api.artifacts.result.ResolvedArtifactResult
|
||||
import org.gradle.api.internal.artifacts.repositories.ResolutionAwareRepository
|
||||
import org.gradle.ivy.IvyDescriptorArtifact
|
||||
import org.gradle.ivy.IvyModule
|
||||
import org.gradle.kotlin.dsl.getArtifacts
|
||||
import org.gradle.kotlin.dsl.withArtifacts
|
||||
import org.gradle.maven.MavenModule
|
||||
import org.gradle.maven.MavenPomArtifact
|
||||
import org.gradle.util.GradleVersion
|
||||
|
||||
enum class ConfigurationScope {
|
||||
BUILDSCRIPT,
|
||||
PLUGIN,
|
||||
PROJECT,
|
||||
SETTINGS
|
||||
}
|
||||
|
||||
internal class ConfigurationResolverFactory(
|
||||
project: Project,
|
||||
scope: ConfigurationScope,
|
||||
repositories: List<ResolutionAwareRepository>
|
||||
) {
|
||||
private val ivySettings = IvySettings().apply {
|
||||
defaultInit()
|
||||
// This doesn't appear to be used, but it's better to define it explicitly than to introduce
|
||||
// impurities into artifact resolution.
|
||||
setDefaultRepositoryCacheBasedir(project.buildDir.resolve("tmp/gradle2nix/_cache").absolutePath)
|
||||
setDictatorResolver(ChainResolver().also { chain ->
|
||||
chain.settings = this@apply
|
||||
for (resolver in resolvers) chain.add(resolver)
|
||||
})
|
||||
}
|
||||
|
||||
private val resolvers = repositories
|
||||
.filterNot { it.createResolver().isLocal }
|
||||
.mapNotNull { it.repositoryResolver(project, scope, ivySettings) }
|
||||
|
||||
fun create(dependencies: DependencyHandler): ConfigurationResolver =
|
||||
ConfigurationResolver(ivySettings, resolvers, dependencies)
|
||||
}
|
||||
|
||||
internal class ConfigurationResolver(
|
||||
ivySettings: IvySettings,
|
||||
private val resolvers: List<RepositoryResolver>,
|
||||
private val dependencies: DependencyHandler
|
||||
) {
|
||||
private val failed = mutableSetOf<ArtifactIdentifier>()
|
||||
private val ivy = Ivy.newInstance(ivySettings)
|
||||
|
||||
val unresolved: List<ArtifactIdentifier> = failed.toList()
|
||||
|
||||
fun resolve(configuration: Configuration): List<DefaultArtifact> {
|
||||
val resolved = configuration.resolvedConfiguration.lenientConfiguration
|
||||
|
||||
failed.addAll(resolved.unresolvedModuleDependencies.map {
|
||||
DefaultArtifactIdentifier(
|
||||
group = it.selector.group,
|
||||
name = it.selector.name,
|
||||
version = it.selector.version ?: "",
|
||||
type = "module"
|
||||
)
|
||||
})
|
||||
|
||||
val topLevelMetadata = resolved.firstLevelModuleDependencies
|
||||
.flatMap { resolveMetadata(it.moduleGroup, it.moduleName, it.moduleVersion) }
|
||||
|
||||
val allArtifacts = resolved.artifacts
|
||||
.filter { it.id.componentIdentifier is ModuleComponentIdentifier }
|
||||
.flatMap(::resolve)
|
||||
|
||||
return (topLevelMetadata + allArtifacts).filter { it.urls.isNotEmpty() }
|
||||
}
|
||||
|
||||
private fun resolve(resolvedArtifact: ResolvedArtifact): List<DefaultArtifact> {
|
||||
val componentId = resolvedArtifact.id.componentIdentifier as ModuleComponentIdentifier
|
||||
|
||||
val artifactId = DefaultArtifactIdentifier(
|
||||
group = componentId.group,
|
||||
name = componentId.module,
|
||||
version = componentId.version,
|
||||
type = resolvedArtifact.type,
|
||||
extension = resolvedArtifact.extension,
|
||||
classifier = resolvedArtifact.classifier
|
||||
)
|
||||
|
||||
val sha256 = resolvedArtifact.computeHash()
|
||||
val artifacts = resolvers.mapNotNull { it.resolve(artifactId, sha256) }.merge()
|
||||
if (artifacts.isEmpty()) failed.add(artifactId)
|
||||
return artifacts + componentId.run { resolveMetadata(group, module, version) }
|
||||
}
|
||||
|
||||
private fun resolveMetadata(
|
||||
group: String,
|
||||
name: String,
|
||||
version: String
|
||||
): List<DefaultArtifact> {
|
||||
return resolvePoms(group, name, version) +
|
||||
resolveDescriptors(group, name, version) +
|
||||
resolveGradleMetadata(group, name, version)
|
||||
}
|
||||
|
||||
private fun resolvePoms(
|
||||
group: String,
|
||||
name: String,
|
||||
version: String
|
||||
): List<DefaultArtifact> {
|
||||
return dependencies.createArtifactResolutionQuery()
|
||||
.forModuleCompat(group, name, version)
|
||||
.withArtifacts(MavenModule::class, MavenPomArtifact::class)
|
||||
.execute()
|
||||
.resolvedComponents
|
||||
.flatMap { it.getArtifacts(MavenPomArtifact::class) }
|
||||
.filterIsInstance<ResolvedArtifactResult>()
|
||||
.flatMap { it.withParentPoms() }
|
||||
.flatMap { resolvedPom ->
|
||||
val componentId = resolvedPom.id.componentIdentifier as ModuleComponentIdentifier
|
||||
val artifactId = DefaultArtifactIdentifier(
|
||||
group = componentId.group,
|
||||
name = componentId.module,
|
||||
version = componentId.version,
|
||||
type = "pom"
|
||||
)
|
||||
// Intentionally not computing hash from the cached result; see ResolvedArtifact.computeHash() below.
|
||||
val artifacts = resolvers.mapNotNull { it.resolve(artifactId) }.merge()
|
||||
if (artifacts.isEmpty()) failed.add(artifactId)
|
||||
artifacts
|
||||
}
|
||||
}
|
||||
|
||||
private fun resolveDescriptors(
|
||||
group: String,
|
||||
name: String,
|
||||
version: String
|
||||
): List<DefaultArtifact> {
|
||||
return dependencies.createArtifactResolutionQuery()
|
||||
.forModuleCompat(group, name, version)
|
||||
.withArtifacts(IvyModule::class, IvyDescriptorArtifact::class)
|
||||
.execute()
|
||||
.resolvedComponents
|
||||
.flatMap { it.getArtifacts(IvyDescriptorArtifact::class) }
|
||||
.filterIsInstance<ResolvedArtifactResult>()
|
||||
.flatMap { it.withParentDescriptors() }
|
||||
.flatMap { resolvedDesc ->
|
||||
val componentId = resolvedDesc.id.componentIdentifier as ModuleComponentIdentifier
|
||||
val artifactId = DefaultArtifactIdentifier(
|
||||
group = componentId.group,
|
||||
name = componentId.module,
|
||||
version = componentId.version,
|
||||
type = "ivy",
|
||||
extension = "xml"
|
||||
)
|
||||
// Intentionally not computing hash from the cached result; see ResolvedArtifact.computeHash() below.
|
||||
val artifacts = resolvers.mapNotNull { it.resolve(artifactId) }.merge()
|
||||
if (artifacts.isEmpty()) failed.add(artifactId)
|
||||
artifacts
|
||||
}
|
||||
}
|
||||
|
||||
private fun resolveGradleMetadata(
|
||||
group: String,
|
||||
name: String,
|
||||
version: String
|
||||
): List<DefaultArtifact> {
|
||||
val artifactId = DefaultArtifactIdentifier(
|
||||
group = group,
|
||||
name = name,
|
||||
version = version,
|
||||
type = "module"
|
||||
)
|
||||
val artifacts = resolvers.mapNotNull { it.resolve(artifactId) }.merge()
|
||||
if (artifacts.isEmpty()) failed.add(artifactId)
|
||||
return artifacts
|
||||
}
|
||||
|
||||
private fun ResolvedArtifactResult.parentPom(): ResolvedArtifactResult? {
|
||||
val resource = URLResource(file.toURI().toURL())
|
||||
val reader = PomReader(resource.url, resource)
|
||||
|
||||
return if (reader.hasParent()) {
|
||||
dependencies.createArtifactResolutionQuery()
|
||||
.forModuleCompat(reader.parentGroupId, reader.parentArtifactId, reader.parentVersion)
|
||||
.withArtifacts(MavenModule::class, MavenPomArtifact::class)
|
||||
.execute()
|
||||
.resolvedComponents
|
||||
.flatMap { it.getArtifacts(MavenPomArtifact::class) }
|
||||
.filterIsInstance<ResolvedArtifactResult>()
|
||||
.firstOrNull()
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun ResolvedArtifactResult.withParentPoms(): List<ResolvedArtifactResult> =
|
||||
generateSequence(this) { it.parentPom() }.toList()
|
||||
|
||||
private fun ResolvedArtifactResult.parentDescriptors(seen: Set<ComponentArtifactIdentifier>): List<ResolvedArtifactResult> {
|
||||
val url = file.toURI().toURL()
|
||||
val parser = XmlModuleDescriptorParser.getInstance()
|
||||
|
||||
val descriptor = parser.parseDescriptor(ivy.settings, url, false)
|
||||
|
||||
return descriptor.inheritedDescriptors.mapNotNull { desc ->
|
||||
dependencies.createArtifactResolutionQuery()
|
||||
.forModuleCompat(
|
||||
desc.parentRevisionId.organisation,
|
||||
desc.parentRevisionId.name,
|
||||
desc.parentRevisionId.revision
|
||||
)
|
||||
.withArtifacts(IvyModule::class, IvyDescriptorArtifact::class)
|
||||
.execute()
|
||||
.resolvedComponents
|
||||
.flatMap { it.getArtifacts(IvyDescriptorArtifact::class) }
|
||||
.filterIsInstance<ResolvedArtifactResult>()
|
||||
.firstOrNull()
|
||||
}.filter { it.id !in seen }
|
||||
}
|
||||
|
||||
private fun ResolvedArtifactResult.withParentDescriptors(): List<ResolvedArtifactResult> {
|
||||
val seen = mutableSetOf<ComponentArtifactIdentifier>()
|
||||
return generateSequence(listOf(this)) { descs ->
|
||||
val parents = descs.flatMap { it.parentDescriptors(seen) }
|
||||
seen.addAll(parents.map(ResolvedArtifactResult::getId))
|
||||
parents.takeUnless { it.isEmpty() }
|
||||
}.flatten().distinct().toList()
|
||||
}
|
||||
}
|
||||
|
||||
private fun ArtifactResolutionQuery.forModuleCompat(
|
||||
group: String,
|
||||
name: String,
|
||||
version: String
|
||||
): ArtifactResolutionQuery {
|
||||
return if (GradleVersion.current() >= GradleVersion.version("4.5")) {
|
||||
forModule(group, name, version)
|
||||
} else {
|
||||
forComponents(ModuleComponentId(group, name, version))
|
||||
}
|
||||
}
|
||||
|
||||
private data class ModuleComponentId(
|
||||
private val moduleId: ModuleId,
|
||||
private val version: String
|
||||
) : ModuleComponentIdentifier {
|
||||
|
||||
constructor(
|
||||
group: String,
|
||||
name: String,
|
||||
version: String
|
||||
) : this(ModuleId(group, name), version)
|
||||
|
||||
override fun getGroup(): String = moduleId.group
|
||||
override fun getModule(): String = moduleId.name
|
||||
override fun getVersion(): String = version
|
||||
override fun getModuleIdentifier(): ModuleIdentifier = moduleId
|
||||
override fun getDisplayName(): String =
|
||||
arrayOf(group, module, version).joinToString(":")
|
||||
}
|
||||
|
||||
private data class ModuleId(
|
||||
private val group: String,
|
||||
private val name: String
|
||||
) : ModuleIdentifier {
|
||||
override fun getGroup(): String = group
|
||||
override fun getName(): String = name
|
||||
}
|
||||
|
||||
private fun List<DefaultArtifact>.merge(): List<DefaultArtifact> {
|
||||
return groupingBy { it.id }
|
||||
.reduce { _, dest, next -> dest.copy(urls = dest.urls + next.urls) }
|
||||
.values.toList()
|
||||
}
|
||||
|
||||
private fun ResolvedArtifact.computeHash(): String? {
|
||||
// Hack: Some POM files are served with CRLF line endings, e.g. javax.servlet:javax.servlet-api:3.1.0.
|
||||
// Gradle stores these normalized with LF line endings, which will not match the eventual hash
|
||||
// of the fixed-output derivation which produces the POM artifact.
|
||||
//
|
||||
// A similar issue can exist for Apache Ivy; see https://issues.apache.org/jira/browse/IVY-1156.
|
||||
//
|
||||
// Ignore these artifacts, and defer hash calculation to RepositoryResolver.
|
||||
if (type == "pom" || type == "ivy") {
|
||||
return null
|
||||
}
|
||||
|
||||
return file.sha256()
|
||||
}
|
||||
@@ -1,282 +1,23 @@
|
||||
@file:Suppress("UnstableApiUsage")
|
||||
|
||||
package org.nixos.gradle2nix
|
||||
|
||||
import com.squareup.moshi.Moshi
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.artifacts.Configuration
|
||||
import org.gradle.api.artifacts.ProjectDependency
|
||||
import org.gradle.api.internal.GradleInternal
|
||||
import org.gradle.api.internal.artifacts.repositories.ResolutionAwareRepository
|
||||
import org.gradle.api.invocation.Gradle
|
||||
import org.gradle.api.tasks.TaskContainer
|
||||
import org.gradle.api.tasks.wrapper.Wrapper
|
||||
import org.gradle.kotlin.dsl.getByName
|
||||
import org.gradle.kotlin.dsl.newInstance
|
||||
import org.gradle.kotlin.dsl.support.serviceOf
|
||||
import org.gradle.kotlin.dsl.withType
|
||||
import org.gradle.plugin.management.PluginRequest
|
||||
import org.gradle.tooling.provider.model.ToolingModelBuilder
|
||||
import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry
|
||||
import org.gradle.util.GradleVersion
|
||||
import java.net.URL
|
||||
import java.util.*
|
||||
import org.nixos.gradle2nix.dependencygraph.AbstractDependencyExtractorPlugin
|
||||
|
||||
@Suppress("unused")
|
||||
open class Gradle2NixPlugin : Plugin<Gradle> {
|
||||
override fun apply(gradle: Gradle): Unit = gradle.run {
|
||||
val pluginRequests = collectPlugins()
|
||||
|
||||
projectsLoaded {
|
||||
val modelProperties = rootProject.loadModelProperties()
|
||||
rootProject.serviceOf<ToolingModelBuilderRegistry>()
|
||||
.register(NixToolingModelBuilder(modelProperties, pluginRequests))
|
||||
|
||||
rootProject.tasks.registerCompat("nixModel") {
|
||||
doLast {
|
||||
val outFile = project.mkdir(project.buildDir.resolve("nix")).resolve("model.json")
|
||||
val model = project.buildModel(modelProperties, pluginRequests)
|
||||
outFile.bufferedWriter().use { out ->
|
||||
out.write(
|
||||
Moshi.Builder().build()
|
||||
.adapter(DefaultBuild::class.java)
|
||||
.indent(" ")
|
||||
.toJson(model)
|
||||
)
|
||||
out.flush()
|
||||
}
|
||||
}
|
||||
}
|
||||
class Gradle2NixPlugin : Plugin<Gradle> {
|
||||
override fun apply(gradle: Gradle) {
|
||||
// Only apply the dependency extractor to the root build
|
||||
if (gradle.parent == null) {
|
||||
gradle.pluginManager.apply(NixDependencyExtractorPlugin::class.java)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun TaskContainer.registerCompat(name: String, configureAction: Task.() -> Unit) {
|
||||
if (GradleVersion.current() >= GradleVersion.version("4.9")) {
|
||||
register(name, configureAction)
|
||||
} else {
|
||||
create(name, configureAction)
|
||||
}
|
||||
}
|
||||
|
||||
private class NixToolingModelBuilder(
|
||||
private val modelProperties: ModelProperties,
|
||||
private val pluginRequests: List<PluginRequest>
|
||||
) : ToolingModelBuilder {
|
||||
override fun canBuild(modelName: String): Boolean {
|
||||
return modelName == NIX_MODEL_NAME
|
||||
gradle.pluginManager.apply(ForceDependencyResolutionPlugin::class.java)
|
||||
}
|
||||
|
||||
override fun buildAll(modelName: String, project: Project): Build =
|
||||
project.buildModel(modelProperties, pluginRequests)
|
||||
}
|
||||
|
||||
private fun Gradle.collectPlugins(): List<PluginRequest> {
|
||||
val pluginRequests = mutableListOf<PluginRequest>()
|
||||
gradle.settingsEvaluated {
|
||||
pluginManagement.resolutionStrategy.eachPlugin {
|
||||
if (requested.id.namespace != null && requested.id.namespace != "org.gradle") {
|
||||
pluginRequests.add(target)
|
||||
}
|
||||
}
|
||||
}
|
||||
return pluginRequests
|
||||
}
|
||||
|
||||
private fun Project.buildModel(
|
||||
modelProperties: ModelProperties,
|
||||
pluginRequests: List<PluginRequest>
|
||||
): DefaultBuild {
|
||||
val settingsDependencies = settingsDependencies()
|
||||
val plugins = buildPlugins(pluginRequests)
|
||||
|
||||
val subprojects = if (modelProperties.subprojects.isEmpty()) {
|
||||
project.subprojects
|
||||
} else {
|
||||
project.subprojects
|
||||
.filter { it.path in modelProperties.subprojects }
|
||||
// Include dependent subprojects as well
|
||||
.flatMap { setOf(it) + it.dependentSubprojects(modelProperties.configurations) }
|
||||
.toSet()
|
||||
}
|
||||
|
||||
return DefaultBuild(
|
||||
gradle = buildGradle(),
|
||||
settingsDependencies = settingsDependencies,
|
||||
pluginDependencies = plugins,
|
||||
rootProject = buildProject(modelProperties.configurations, subprojects, plugins),
|
||||
includedBuilds = includedBuilds()
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("UnstableApiUsage")
|
||||
private fun Project.buildGradle(): DefaultGradle =
|
||||
with(tasks.getByName<Wrapper>("wrapper")) {
|
||||
DefaultGradle(
|
||||
version = gradleVersion,
|
||||
type = distributionType.name.toLowerCase(Locale.US),
|
||||
url = distributionUrl,
|
||||
sha256 = sha256,
|
||||
nativeVersion = gradle.gradleHomeDir?.resolve("lib")?.listFiles()
|
||||
?.firstOrNull { f -> nativePlatformJarRegex matches f.name }?.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()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun Project.settingsDependencies(): List<DefaultArtifact> {
|
||||
val buildscript = (gradle as GradleInternal).settings.buildscript
|
||||
|
||||
val resolverFactory = ConfigurationResolverFactory(
|
||||
this,
|
||||
ConfigurationScope.SETTINGS,
|
||||
buildscript.repositories.filterIsInstance<ResolutionAwareRepository>()
|
||||
)
|
||||
val resolver = resolverFactory.create(buildscript.dependencies)
|
||||
|
||||
logger.lifecycle(" Settings script")
|
||||
|
||||
val dependencies = buildscript.configurations
|
||||
.flatMap(resolver::resolve)
|
||||
.distinct()
|
||||
.sorted()
|
||||
|
||||
if (resolver.unresolved.isNotEmpty()) {
|
||||
logger.warn(buildString {
|
||||
append(" Failed to resolve settings script dependencies:\n")
|
||||
for (id in resolver.unresolved) {
|
||||
append(" - $id\n")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return dependencies
|
||||
}
|
||||
|
||||
private fun Project.buildPlugins(pluginRequests: List<PluginRequest>): List<DefaultArtifact> {
|
||||
return objects.newInstance<PluginResolver>(this).resolve(pluginRequests).distinct().sorted()
|
||||
}
|
||||
|
||||
private fun Project.includedBuilds(): List<DefaultIncludedBuild> =
|
||||
gradle.includedBuilds.map {
|
||||
DefaultIncludedBuild(it.name, it.projectDir.toRelativeString(project.projectDir))
|
||||
}
|
||||
|
||||
private fun Project.buildProject(
|
||||
explicitConfigurations: List<String>,
|
||||
explicitSubprojects: Collection<Project>,
|
||||
pluginArtifacts: List<DefaultArtifact>
|
||||
): DefaultProject {
|
||||
logger.lifecycle(" Subproject: $path")
|
||||
|
||||
val (buildscriptDependencies, buildscriptUnresolved) = buildscriptDependencies(pluginArtifacts)
|
||||
|
||||
if (buildscriptUnresolved.isNotEmpty()) {
|
||||
logger.warn(buildString {
|
||||
append(" Failed to resolve buildscript dependencies:\n")
|
||||
for (id in buildscriptUnresolved) {
|
||||
append(" - $id\n")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
val (projectDependencies, projectUnresolved) = projectDependencies(explicitConfigurations)
|
||||
|
||||
if (projectUnresolved.isNotEmpty()) {
|
||||
logger.warn(buildString {
|
||||
append(" Failed to resolve project dependencies:\n")
|
||||
for (id in projectUnresolved) {
|
||||
append(" - $id\n")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return DefaultProject(
|
||||
name = name,
|
||||
version = version.toString(),
|
||||
path = path,
|
||||
projectDir = projectDir.toRelativeString(rootProject.projectDir),
|
||||
buildscriptDependencies = buildscriptDependencies,
|
||||
projectDependencies = projectDependencies,
|
||||
children = explicitSubprojects.map {
|
||||
it.buildProject(explicitConfigurations, emptyList(), pluginArtifacts)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun Project.buildscriptDependencies(
|
||||
pluginArtifacts: List<DefaultArtifact>
|
||||
): Pair<List<DefaultArtifact>, List<ArtifactIdentifier>> {
|
||||
val resolverFactory = ConfigurationResolverFactory(
|
||||
this,
|
||||
ConfigurationScope.BUILDSCRIPT,
|
||||
buildscript.repositories.filterIsInstance<ResolutionAwareRepository>()
|
||||
)
|
||||
val resolver = resolverFactory.create(buildscript.dependencies)
|
||||
val pluginIds = pluginArtifacts.map(DefaultArtifact::id)
|
||||
return buildscript.configurations
|
||||
.flatMap(resolver::resolve)
|
||||
.distinct()
|
||||
.filter { it.id !in pluginIds }
|
||||
.sorted() to resolver.unresolved
|
||||
}
|
||||
|
||||
private fun Project.projectDependencies(
|
||||
explicitConfigurations: List<String>
|
||||
): Pair<List<DefaultArtifact>, List<ArtifactIdentifier>> {
|
||||
val resolver = ConfigurationResolverFactory(
|
||||
this,
|
||||
ConfigurationScope.PROJECT,
|
||||
RepositoriesCollector.create(project).collectRepositories()
|
||||
).create(dependencies)
|
||||
return collectConfigurations(explicitConfigurations)
|
||||
.flatMap(resolver::resolve)
|
||||
.distinct()
|
||||
.sorted() to resolver.unresolved
|
||||
}
|
||||
|
||||
private fun Project.dependentSubprojects(explicitConfigurations: List<String>): Set<Project> {
|
||||
return collectConfigurations(explicitConfigurations)
|
||||
.flatMap { it.allDependencies.withType<ProjectDependency>() }
|
||||
.map { it.dependencyProject }
|
||||
.toSet()
|
||||
.flatMap { setOf(it) + it.dependentSubprojects(explicitConfigurations) }
|
||||
.toSet()
|
||||
}
|
||||
|
||||
private fun Project.collectConfigurations(
|
||||
explicitConfigurations: List<String>
|
||||
): Set<Configuration> {
|
||||
return if (explicitConfigurations.isEmpty()) {
|
||||
configurations.filter { it.isCanBeResolved }.toSet()
|
||||
} else {
|
||||
configurations.filter { it.name in explicitConfigurations }.toSet()
|
||||
class NixDependencyExtractorPlugin : AbstractDependencyExtractorPlugin() {
|
||||
override fun getRendererClassName(): String =
|
||||
NixDependencyGraphRenderer::class.java.name
|
||||
}
|
||||
}
|
||||
|
||||
private fun fetchDistSha256(url: String): String {
|
||||
return URL("$url.sha256").openConnection().run {
|
||||
connect()
|
||||
getInputStream().reader().use { it.readText() }
|
||||
}
|
||||
}
|
||||
|
||||
private val nativePlatformJarRegex = Regex("""native-platform-([\d.]+(-(alpha|beta|milestone)-\d+)?)\.jar""")
|
||||
|
||||
private val Wrapper.sha256: String
|
||||
get() {
|
||||
return if (GradleVersion.current() < GradleVersion.version("4.5")) {
|
||||
fetchDistSha256(distributionUrl)
|
||||
} else {
|
||||
@Suppress("UnstableApiUsage")
|
||||
distributionSha256Sum ?: fetchDistSha256(distributionUrl)
|
||||
}
|
||||
}
|
||||
|
||||
private const val NIX_MODEL_NAME = "org.nixos.gradle2nix.Build"
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
package org.nixos.gradle2nix
|
||||
|
||||
import org.gradle.api.Project
|
||||
|
||||
data class ModelProperties(
|
||||
val configurations: List<String>,
|
||||
val subprojects: List<String>
|
||||
)
|
||||
|
||||
internal fun Project.loadModelProperties(): ModelProperties {
|
||||
return ModelProperties(
|
||||
configurations = this["org.nixos.gradle2nix.configurations"]?.split(",") ?: emptyList(),
|
||||
subprojects = this["org.nixos.gradle2nix.subprojects"]?.split(",") ?: emptyList()
|
||||
)
|
||||
}
|
||||
|
||||
private operator fun Project.get(key: String): String? {
|
||||
return System.getProperty(key)?.takeIf { it.isNotEmpty() }
|
||||
?: (properties[key] as? String)?.takeIf { it.isNotEmpty() }
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.nixos.gradle2nix
|
||||
|
||||
import java.io.File
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.encodeToStream
|
||||
import org.nixos.gradle2nix.dependencygraph.DependencyGraphRenderer
|
||||
import org.nixos.gradle2nix.dependencygraph.model.ResolvedConfiguration
|
||||
|
||||
class NixDependencyGraphRenderer : DependencyGraphRenderer {
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
override fun outputDependencyGraph(
|
||||
resolvedConfigurations: List<ResolvedConfiguration>,
|
||||
outputDirectory: File
|
||||
) {
|
||||
val graphOutputFile = File(outputDirectory, "dependency-graph.json")
|
||||
graphOutputFile.outputStream().buffered().use { output ->
|
||||
Json.encodeToStream(resolvedConfigurations, output)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package org.nixos.gradle2nix
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.internal.artifacts.repositories.ResolutionAwareRepository
|
||||
import org.gradle.plugin.management.PluginRequest
|
||||
import org.gradle.plugin.use.internal.PluginDependencyResolutionServices
|
||||
import javax.inject.Inject
|
||||
|
||||
internal open class PluginResolver @Inject constructor(
|
||||
project: Project,
|
||||
pluginDependencyResolutionServices: PluginDependencyResolutionServices
|
||||
) {
|
||||
private val configurations = pluginDependencyResolutionServices.configurationContainer
|
||||
|
||||
private val resolver = ConfigurationResolverFactory(
|
||||
project,
|
||||
ConfigurationScope.PLUGIN,
|
||||
pluginDependencyResolutionServices.resolveRepositoryHandler.filterIsInstance<ResolutionAwareRepository>()
|
||||
).create(pluginDependencyResolutionServices.dependencyHandler)
|
||||
|
||||
fun resolve(pluginRequests: List<PluginRequest>): List<DefaultArtifact> {
|
||||
val markerDependencies = pluginRequests.map { request ->
|
||||
request.module?.let { module ->
|
||||
ApiHack.defaultExternalModuleDependency(module.group, module.name, module.version)
|
||||
} ?: request.id.id.let { id ->
|
||||
ApiHack.defaultExternalModuleDependency(id, "$id.gradle.plugin", request.version)
|
||||
}
|
||||
}
|
||||
return resolver.resolve(configurations.detachedConfiguration(*markerDependencies.toTypedArray()))
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
package org.nixos.gradle2nix
|
||||
|
||||
import org.gradle.api.internal.artifacts.repositories.ResolutionAwareRepository
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.artifacts.dsl.RepositoryHandler
|
||||
import org.gradle.api.initialization.dsl.ScriptHandler
|
||||
import org.gradle.api.internal.artifacts.RepositoriesSupplier
|
||||
import org.gradle.kotlin.dsl.newInstance
|
||||
import org.gradle.util.GradleVersion
|
||||
import javax.inject.Inject
|
||||
|
||||
interface RepositoriesCollector {
|
||||
fun collectRepositories(): List<ResolutionAwareRepository>
|
||||
|
||||
companion object {
|
||||
fun create(project: Project): RepositoriesCollector =
|
||||
if (GradleVersion.current() >= GradleVersion.version("6.8")) {
|
||||
project.objects.newInstance<RepositoriesCollector68>()
|
||||
} else {
|
||||
project.objects.newInstance<RepositoriesCollectorBase>()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
open class RepositoriesCollectorBase @Inject constructor(
|
||||
private val repositories: RepositoryHandler
|
||||
): RepositoriesCollector {
|
||||
override fun collectRepositories(): List<ResolutionAwareRepository> =
|
||||
repositories.filterIsInstance<ResolutionAwareRepository>()
|
||||
}
|
||||
|
||||
open class RepositoriesCollector68 @Inject constructor(
|
||||
private val repositoriesSupplier: RepositoriesSupplier
|
||||
): RepositoriesCollector {
|
||||
override fun collectRepositories(): List<ResolutionAwareRepository> =
|
||||
repositoriesSupplier.get()
|
||||
}
|
||||
@@ -1,317 +0,0 @@
|
||||
package org.nixos.gradle2nix
|
||||
|
||||
import com.amazonaws.auth.BasicAWSCredentials
|
||||
import com.amazonaws.auth.BasicSessionCredentials
|
||||
import org.apache.ivy.core.LogOptions
|
||||
import org.apache.ivy.core.cache.ArtifactOrigin
|
||||
import org.apache.ivy.core.cache.CacheResourceOptions
|
||||
import org.apache.ivy.core.cache.DefaultRepositoryCacheManager
|
||||
import org.apache.ivy.core.cache.RepositoryCacheManager
|
||||
import org.apache.ivy.core.module.id.ArtifactRevisionId
|
||||
import org.apache.ivy.core.module.id.ModuleRevisionId
|
||||
import org.apache.ivy.core.resolve.DownloadOptions
|
||||
import org.apache.ivy.core.settings.IvySettings
|
||||
import org.apache.ivy.core.settings.TimeoutConstraint
|
||||
import org.apache.ivy.plugins.repository.Repository
|
||||
import org.apache.ivy.plugins.repository.Resource
|
||||
import org.apache.ivy.plugins.repository.url.URLRepository
|
||||
import org.apache.ivy.plugins.repository.url.URLResource
|
||||
import org.apache.ivy.plugins.resolver.AbstractResolver
|
||||
import org.apache.ivy.plugins.resolver.IBiblioResolver
|
||||
import org.apache.ivy.plugins.resolver.URLResolver
|
||||
import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Reader
|
||||
import org.codehaus.plexus.util.ReaderFactory
|
||||
import org.codehaus.plexus.util.xml.pull.XmlPullParserException
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.artifacts.repositories.ArtifactRepository
|
||||
import org.gradle.api.artifacts.repositories.AuthenticationContainer
|
||||
import org.gradle.api.artifacts.repositories.AuthenticationSupported
|
||||
import org.gradle.api.artifacts.repositories.IvyArtifactRepository
|
||||
import org.gradle.api.artifacts.repositories.MavenArtifactRepository
|
||||
import org.gradle.api.artifacts.repositories.UrlArtifactRepository
|
||||
import org.gradle.api.credentials.AwsCredentials
|
||||
import org.gradle.api.internal.artifacts.repositories.ResolutionAwareRepository
|
||||
import org.gradle.api.internal.artifacts.repositories.resolver.IvyResolver
|
||||
import org.gradle.api.logging.Logger
|
||||
import org.gradle.api.logging.Logging
|
||||
import org.gradle.authentication.aws.AwsImAuthentication
|
||||
import org.gradle.internal.authentication.AllSchemesAuthentication
|
||||
import org.gradle.kotlin.dsl.getCredentials
|
||||
import java.io.IOException
|
||||
import java.net.URI
|
||||
import org.apache.ivy.core.module.descriptor.Artifact as IvyArtifact
|
||||
import org.apache.ivy.core.module.descriptor.DefaultArtifact as IvyDefaultArtifact
|
||||
import org.apache.ivy.plugins.resolver.RepositoryResolver as IvyRepositoryResolver
|
||||
|
||||
internal fun ResolutionAwareRepository.repositoryResolver(
|
||||
project: Project,
|
||||
scope: ConfigurationScope,
|
||||
ivySettings: IvySettings
|
||||
): RepositoryResolver? =
|
||||
when(this) {
|
||||
is MavenArtifactRepository -> MavenResolver(project, scope, ivySettings, this)
|
||||
is IvyArtifactRepository -> IvyResolver(project, scope, ivySettings, this)
|
||||
else -> null
|
||||
}
|
||||
|
||||
internal sealed class RepositoryResolver {
|
||||
companion object {
|
||||
@JvmStatic
|
||||
protected val log: Logger = Logging.getLogger("gradle2nix")
|
||||
}
|
||||
|
||||
abstract val ivyResolver: IvyRepositoryResolver
|
||||
|
||||
abstract fun resolve(
|
||||
artifactId: DefaultArtifactIdentifier,
|
||||
sha256: String? = null
|
||||
): DefaultArtifact?
|
||||
}
|
||||
|
||||
internal class MavenResolver(
|
||||
project: Project,
|
||||
scope: ConfigurationScope,
|
||||
ivySettings: IvySettings,
|
||||
repository: MavenArtifactRepository
|
||||
) : RepositoryResolver() {
|
||||
|
||||
override val ivyResolver: IBiblioResolver = IBiblioResolver().apply {
|
||||
name = repository.name
|
||||
root = repository.url.toString()
|
||||
isM2compatible = true
|
||||
settings = ivySettings
|
||||
setCache(cacheManager(project, scope, ivySettings, repository).name)
|
||||
setRepository(resolverRepository(repository))
|
||||
}
|
||||
|
||||
override fun resolve(artifactId: DefaultArtifactIdentifier, sha256: String?): DefaultArtifact? {
|
||||
val ivyArtifact: IvyArtifact = artifactId.toArtifact()
|
||||
val origin = ivyResolver.locate(ivyArtifact)
|
||||
if (origin == null || !origin.isExists) return null
|
||||
val hash = if (sha256 != null) sha256 else {
|
||||
val report = ivyResolver.download(origin, downloadOptions)
|
||||
report.localFile?.sha256().also {
|
||||
if (it == null) log.error(report.toString())
|
||||
}
|
||||
}
|
||||
if (hash == null) {
|
||||
log.error("Failed to download '$artifactId' from repository '${ivyResolver.repository.name}'")
|
||||
return null
|
||||
}
|
||||
val snapshotVersion: SnapshotVersion? = artifactId.version.snapshotVersion()?.let {
|
||||
findSnapshotVersion(artifactId, it)
|
||||
}
|
||||
return DefaultArtifact(
|
||||
id = artifactId,
|
||||
name = artifactId.filename(snapshotVersion),
|
||||
path = artifactId.repoPath(),
|
||||
timestamp = snapshotVersion?.timestamp,
|
||||
build = snapshotVersion?.build,
|
||||
urls = listOf(origin.location),
|
||||
sha256 = hash
|
||||
)
|
||||
}
|
||||
|
||||
private fun findSnapshotVersion(
|
||||
artifactId: ArtifactIdentifier,
|
||||
snapshotVersion: SnapshotVersion
|
||||
): SnapshotVersion {
|
||||
if (snapshotVersion.timestamp != null) return snapshotVersion
|
||||
val metadataLocation = "${ivyResolver.root}${artifactId.repoPath()}/maven-metadata.xml"
|
||||
val metadataFile = ivyResolver.repositoryCacheManager.downloadRepositoryResource(
|
||||
ivyResolver.repository.getResource(metadataLocation),
|
||||
"maven-metadata",
|
||||
"maven-metadata",
|
||||
"xml",
|
||||
CacheResourceOptions(),
|
||||
ivyResolver.repository
|
||||
).localFile
|
||||
|
||||
if (metadataFile == null) {
|
||||
log.warn("maven-metadata.xml not found for snapshot dependency: $artifactId")
|
||||
return snapshotVersion
|
||||
}
|
||||
|
||||
fun parseError(e: Throwable): Pair<String?, Int?> {
|
||||
log.error("Failed to parse maven-metadata.xml for artifact: $artifactId")
|
||||
log.error("Error was: ${e.message}", e)
|
||||
return null to null
|
||||
}
|
||||
|
||||
val (timestamp: String?, build: Int?) = try {
|
||||
MetadataXpp3Reader()
|
||||
.read(ReaderFactory.newXmlReader(metadataFile))
|
||||
.versioning?.snapshot?.run { timestamp to buildNumber }
|
||||
?: null to null
|
||||
} catch (e: IOException) {
|
||||
parseError(e)
|
||||
} catch (e: XmlPullParserException) {
|
||||
parseError(e)
|
||||
}
|
||||
|
||||
return snapshotVersion.copy(timestamp = timestamp, build = build)
|
||||
}
|
||||
}
|
||||
|
||||
internal class IvyResolver(
|
||||
project: Project,
|
||||
scope: ConfigurationScope,
|
||||
ivySettings: IvySettings,
|
||||
repository: IvyArtifactRepository
|
||||
) : RepositoryResolver() {
|
||||
|
||||
override val ivyResolver: URLResolver = URLResolver().apply {
|
||||
name = repository.name
|
||||
val ivyResolver = (repository as ResolutionAwareRepository).createResolver() as IvyResolver
|
||||
isM2compatible = ivyResolver.isM2compatible
|
||||
for (p in ivyResolver.ivyPatterns) addIvyPattern(p)
|
||||
for (p in ivyResolver.artifactPatterns) addArtifactPattern(p)
|
||||
settings = ivySettings
|
||||
setCache(cacheManager(project, scope, ivySettings, repository).name)
|
||||
setRepository(resolverRepository(repository))
|
||||
}
|
||||
|
||||
override fun resolve(artifactId: DefaultArtifactIdentifier, sha256: String?): DefaultArtifact? {
|
||||
val ivyArtifact: IvyArtifact = artifactId.toArtifact()
|
||||
val origin = ivyResolver.locate(ivyArtifact)?.takeIf(ArtifactOrigin::isExists) ?: return null
|
||||
val hash = if (sha256 != null) sha256 else {
|
||||
val report = ivyResolver.download(origin, downloadOptions)
|
||||
report.localFile?.sha256().also {
|
||||
if (it == null) log.error(report.toString())
|
||||
}
|
||||
}
|
||||
if (hash == null) {
|
||||
log.error("Failed to download '$artifactId' from repository '${ivyResolver.repository.name}'")
|
||||
return null
|
||||
}
|
||||
return DefaultArtifact(
|
||||
id = DefaultArtifactIdentifier(artifactId),
|
||||
name = artifactId.filename(null),
|
||||
path = artifactId.repoPath(),
|
||||
urls = listOf(origin.location),
|
||||
sha256 = hash
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun cacheManager(
|
||||
project: Project,
|
||||
scope: ConfigurationScope,
|
||||
ivySettings: IvySettings,
|
||||
repository: ArtifactRepository
|
||||
): RepositoryCacheManager {
|
||||
return DefaultRepositoryCacheManager(
|
||||
"${scope.name.toLowerCase()}-${repository.name}-cache",
|
||||
ivySettings,
|
||||
project.buildDir.resolve("tmp/gradle2nix/${repository.name}").also {
|
||||
it.mkdirs()
|
||||
}
|
||||
).also {
|
||||
ivySettings.addRepositoryCacheManager(it)
|
||||
}
|
||||
}
|
||||
|
||||
private val metadataTypes = setOf("pom", "ivy")
|
||||
|
||||
private fun ArtifactIdentifier.toArtifact(): IvyArtifact {
|
||||
val moduleRevisionId = ModuleRevisionId.newInstance(group, name, version)
|
||||
val artifactRevisionId = ArtifactRevisionId.newInstance(
|
||||
moduleRevisionId,
|
||||
name,
|
||||
type,
|
||||
extension,
|
||||
classifier?.let { mapOf("classifier" to it) }
|
||||
)
|
||||
return IvyDefaultArtifact(artifactRevisionId, null, null, type in metadataTypes)
|
||||
}
|
||||
|
||||
private data class SnapshotVersion(
|
||||
val base: String,
|
||||
val timestamp: String?,
|
||||
val build: Int?
|
||||
) {
|
||||
override fun toString(): String {
|
||||
return if (timestamp != null && build != null) {
|
||||
"$base-$timestamp-$build"
|
||||
} else {
|
||||
"$base-SNAPSHOT"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val SNAPSHOT_REGEX = Regex("^(.*)-SNAPSHOT$")
|
||||
private val SNAPSHOT_TIMESTAMPED_REGEX = Regex("^(.*)-([0-9]{8}.[0-9]{6})-([0-9]+)$")
|
||||
|
||||
private fun String.snapshotVersion(): SnapshotVersion? {
|
||||
return SNAPSHOT_REGEX.find(this)?.destructured?.let { (base) ->
|
||||
SnapshotVersion(base, null, null)
|
||||
} ?: SNAPSHOT_TIMESTAMPED_REGEX.find(this)?.destructured?.let { (base, timestamp, build) ->
|
||||
SnapshotVersion(base, timestamp, build.toInt())
|
||||
}
|
||||
}
|
||||
|
||||
private fun ArtifactIdentifier.repoPath(): String =
|
||||
"${group.replace('.', '/')}/$name/$version"
|
||||
|
||||
private fun ArtifactIdentifier.filename(
|
||||
snapshotVersion: SnapshotVersion?
|
||||
): String = buildString {
|
||||
append(name, "-", snapshotVersion ?: version)
|
||||
if (classifier != null) append("-", classifier)
|
||||
append(".", extension)
|
||||
}
|
||||
|
||||
private val downloadOptions = DownloadOptions().apply {
|
||||
log = LogOptions.LOG_DEFAULT
|
||||
}
|
||||
|
||||
private fun <T> AbstractResolver.resolverRepository(
|
||||
repository: T
|
||||
) : Repository
|
||||
where T : ArtifactRepository,
|
||||
T : AuthenticationSupported =
|
||||
when (val scheme = repository.url.scheme) {
|
||||
"s3" -> s3Repository(
|
||||
repository.getCredentials(AwsCredentials::class),
|
||||
LazyTimeoutConstraint(this)
|
||||
)
|
||||
"http", "https" -> URLRepository(LazyTimeoutConstraint(this))
|
||||
else -> throw IllegalStateException("Unknown repository URL scheme: $scheme")
|
||||
}
|
||||
|
||||
private fun s3Repository(
|
||||
credentials: AwsCredentials?,
|
||||
timeoutConstraint: TimeoutConstraint
|
||||
): Repository {
|
||||
val awsCredentials = credentials?.let {
|
||||
if (it.sessionToken == null) {
|
||||
BasicAWSCredentials(it.accessKey, it.secretKey)
|
||||
} else {
|
||||
BasicSessionCredentials(it.accessKey, it.secretKey, it.sessionToken)
|
||||
}
|
||||
}
|
||||
return S3Repository(
|
||||
credentials = awsCredentials,
|
||||
endpoint = System.getProperty("org.gradle.s3.endpoint")?.let { URI(it) },
|
||||
timeoutConstraint = timeoutConstraint
|
||||
).apply {
|
||||
name = "AWS S3"
|
||||
}
|
||||
}
|
||||
|
||||
private class LazyTimeoutConstraint(
|
||||
private val resolver: AbstractResolver
|
||||
) : TimeoutConstraint {
|
||||
override fun getConnectionTimeout(): Int =
|
||||
resolver.timeoutConstraint?.connectionTimeout ?: -1
|
||||
|
||||
override fun getReadTimeout(): Int =
|
||||
resolver.timeoutConstraint?.readTimeout ?: -1
|
||||
}
|
||||
|
||||
// Compatibility shim as UrlArtifactRepository was added in Gradle 6.0
|
||||
private val ArtifactRepository.url: URI get() = when (this) {
|
||||
is MavenArtifactRepository -> url
|
||||
is IvyArtifactRepository -> url
|
||||
else -> throw IllegalStateException("Unhandled repository type: ${this::class.simpleName}")
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package org.nixos.gradle2nix
|
||||
|
||||
import java.io.File
|
||||
import java.net.URI
|
||||
import java.net.URL
|
||||
import java.security.MessageDigest
|
||||
|
||||
private const val HEX = "0123456789abcdef"
|
||||
|
||||
internal fun File.sha256(): String = readBytes().sha256()
|
||||
|
||||
private fun ByteArray.sha256() = buildString {
|
||||
MessageDigest.getInstance("SHA-256").digest(this@sha256)
|
||||
.asSequence()
|
||||
.map(Byte::toInt)
|
||||
.forEach {
|
||||
append(HEX[it shr 4 and 0x0f])
|
||||
append(HEX[it and 0x0f])
|
||||
}
|
||||
}
|
||||
|
||||
internal fun String.toUrl(): URL = URL(this)
|
||||
|
||||
internal fun String.toUri(): URI = URI(this)
|
||||
@@ -0,0 +1,128 @@
|
||||
package org.nixos.gradle2nix.dependencygraph
|
||||
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.invocation.Gradle
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.internal.build.event.BuildEventListenerRegistryInternal
|
||||
import org.gradle.util.GradleVersion
|
||||
import org.nixos.gradle2nix.dependencygraph.extractor.DependencyExtractor
|
||||
import org.nixos.gradle2nix.dependencygraph.extractor.DependencyExtractorBuildService
|
||||
import org.nixos.gradle2nix.dependencygraph.extractor.LegacyDependencyExtractor
|
||||
import org.nixos.gradle2nix.dependencygraph.util.service
|
||||
|
||||
abstract class AbstractDependencyExtractorPlugin : Plugin<Gradle> {
|
||||
// Register extension functions on `Gradle` type
|
||||
private companion object : org.nixos.gradle2nix.dependencygraph.util.GradleExtensions()
|
||||
|
||||
/**
|
||||
* The name of an accessible class that implements `org.gradle.dependencygraph.DependencyGraphRenderer`.
|
||||
*/
|
||||
abstract fun getRendererClassName(): String
|
||||
|
||||
internal lateinit var dependencyExtractorProvider: Provider<out DependencyExtractor>
|
||||
|
||||
override fun apply(gradle: Gradle) {
|
||||
val gradleVersion = GradleVersion.current()
|
||||
// Create the adapter based upon the version of Gradle
|
||||
val applicatorStrategy = when {
|
||||
gradleVersion < GradleVersion.version("8.0") -> PluginApplicatorStrategy.LegacyPluginApplicatorStrategy
|
||||
else -> PluginApplicatorStrategy.DefaultPluginApplicatorStrategy
|
||||
}
|
||||
|
||||
// Create the service
|
||||
dependencyExtractorProvider = applicatorStrategy.createExtractorService(gradle, getRendererClassName())
|
||||
|
||||
gradle.rootProject { project ->
|
||||
dependencyExtractorProvider
|
||||
.get()
|
||||
.rootProjectBuildDirectory = project.buildDir
|
||||
}
|
||||
|
||||
// Register the service to listen for Build Events
|
||||
applicatorStrategy.registerExtractorListener(gradle, dependencyExtractorProvider)
|
||||
|
||||
// Register the shutdown hook that should execute at the completion of the Gradle build.
|
||||
applicatorStrategy.registerExtractorServiceShutdown(gradle, dependencyExtractorProvider)
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapters for creating the [DependencyExtractor] and installing it into [Gradle] based upon the Gradle version.
|
||||
*/
|
||||
private interface PluginApplicatorStrategy {
|
||||
|
||||
fun createExtractorService(
|
||||
gradle: Gradle,
|
||||
rendererClassName: String
|
||||
): Provider<out DependencyExtractor>
|
||||
|
||||
fun registerExtractorListener(
|
||||
gradle: Gradle,
|
||||
extractorServiceProvider: Provider<out DependencyExtractor>
|
||||
)
|
||||
|
||||
fun registerExtractorServiceShutdown(
|
||||
gradle: Gradle,
|
||||
extractorServiceProvider: Provider<out DependencyExtractor>
|
||||
)
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
object LegacyPluginApplicatorStrategy : PluginApplicatorStrategy {
|
||||
|
||||
override fun createExtractorService(
|
||||
gradle: Gradle,
|
||||
rendererClassName: String
|
||||
): Provider<out DependencyExtractor> {
|
||||
val dependencyExtractor = LegacyDependencyExtractor(rendererClassName)
|
||||
return gradle.providerFactory.provider { dependencyExtractor }
|
||||
}
|
||||
|
||||
override fun registerExtractorListener(
|
||||
gradle: Gradle,
|
||||
extractorServiceProvider: Provider<out DependencyExtractor>
|
||||
) {
|
||||
gradle.buildOperationListenerManager
|
||||
.addListener(extractorServiceProvider.get())
|
||||
}
|
||||
|
||||
override fun registerExtractorServiceShutdown(
|
||||
gradle: Gradle,
|
||||
extractorServiceProvider: Provider<out DependencyExtractor>
|
||||
) {
|
||||
gradle.buildFinished {
|
||||
extractorServiceProvider.get().close()
|
||||
gradle.buildOperationListenerManager
|
||||
.removeListener(extractorServiceProvider.get())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object DefaultPluginApplicatorStrategy : PluginApplicatorStrategy {
|
||||
private const val SERVICE_NAME = "dependencyExtractorService"
|
||||
|
||||
override fun createExtractorService(
|
||||
gradle: Gradle,
|
||||
rendererClassName: String
|
||||
): Provider<out DependencyExtractor> {
|
||||
return gradle.sharedServices.registerIfAbsent(
|
||||
SERVICE_NAME,
|
||||
DependencyExtractorBuildService::class.java
|
||||
) { it.parameters.rendererClassName.set(rendererClassName) }
|
||||
}
|
||||
|
||||
override fun registerExtractorListener(
|
||||
gradle: Gradle,
|
||||
extractorServiceProvider: Provider<out DependencyExtractor>
|
||||
) {
|
||||
gradle.service<BuildEventListenerRegistryInternal>()
|
||||
.onOperationCompletion(extractorServiceProvider)
|
||||
}
|
||||
|
||||
override fun registerExtractorServiceShutdown(
|
||||
gradle: Gradle,
|
||||
extractorServiceProvider: Provider<out DependencyExtractor>
|
||||
) {
|
||||
// No-op as DependencyExtractorService is Auto-Closable
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package org.nixos.gradle2nix.dependencygraph
|
||||
|
||||
import java.io.File
|
||||
import org.nixos.gradle2nix.dependencygraph.model.ResolvedConfiguration
|
||||
|
||||
interface DependencyGraphRenderer {
|
||||
fun outputDependencyGraph(
|
||||
resolvedConfigurations: List<ResolvedConfiguration>,
|
||||
outputDirectory: File
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,342 @@
|
||||
package org.nixos.gradle2nix.dependencygraph.extractor
|
||||
|
||||
import java.io.File
|
||||
import java.net.URI
|
||||
import java.util.Collections
|
||||
import org.gradle.api.GradleException
|
||||
import org.gradle.api.artifacts.result.ResolvedComponentResult
|
||||
import org.gradle.api.artifacts.result.ResolvedDependencyResult
|
||||
import org.gradle.api.internal.artifacts.DefaultProjectComponentIdentifier
|
||||
import org.gradle.api.internal.artifacts.configurations.ResolveConfigurationDependenciesBuildOperationType
|
||||
import org.gradle.api.logging.Logging
|
||||
import org.gradle.internal.exceptions.DefaultMultiCauseException
|
||||
import org.gradle.internal.operations.BuildOperationDescriptor
|
||||
import org.gradle.internal.operations.BuildOperationListener
|
||||
import org.gradle.internal.operations.OperationFinishEvent
|
||||
import org.gradle.internal.operations.OperationIdentifier
|
||||
import org.gradle.internal.operations.OperationProgressEvent
|
||||
import org.gradle.internal.operations.OperationStartEvent
|
||||
import org.nixos.gradle2nix.PARAM_INCLUDE_CONFIGURATIONS
|
||||
import org.nixos.gradle2nix.PARAM_INCLUDE_PROJECTS
|
||||
import org.nixos.gradle2nix.PARAM_REPORT_DIR
|
||||
import org.nixos.gradle2nix.dependencygraph.DependencyGraphRenderer
|
||||
import org.nixos.gradle2nix.dependencygraph.model.DependencyCoordinates
|
||||
import org.nixos.gradle2nix.dependencygraph.model.DependencySource
|
||||
import org.nixos.gradle2nix.dependencygraph.model.Repository
|
||||
import org.nixos.gradle2nix.dependencygraph.model.ResolvedConfiguration
|
||||
import org.nixos.gradle2nix.dependencygraph.model.ResolvedDependency
|
||||
import org.nixos.gradle2nix.dependencygraph.util.loadOptionalParam
|
||||
|
||||
abstract class DependencyExtractor :
|
||||
BuildOperationListener,
|
||||
AutoCloseable {
|
||||
|
||||
private val resolvedConfigurations = Collections.synchronizedList(mutableListOf<ResolvedConfiguration>())
|
||||
|
||||
private val thrownExceptions = Collections.synchronizedList(mutableListOf<Throwable>())
|
||||
|
||||
var rootProjectBuildDirectory: File? = null
|
||||
|
||||
// Properties are lazily initialized so that System Properties are initialized by the time
|
||||
// the values are used. This is required due to a bug in older Gradle versions. (https://github.com/gradle/gradle/issues/6825)
|
||||
private val configurationFilter by lazy {
|
||||
ResolvedConfigurationFilter(
|
||||
loadOptionalParam(PARAM_INCLUDE_PROJECTS),
|
||||
loadOptionalParam(PARAM_INCLUDE_CONFIGURATIONS)
|
||||
)
|
||||
}
|
||||
|
||||
private val dependencyGraphReportDir by lazy {
|
||||
loadOptionalParam(PARAM_REPORT_DIR)
|
||||
}
|
||||
|
||||
abstract fun getRendererClassName(): String
|
||||
|
||||
override fun started(buildOperation: BuildOperationDescriptor, startEvent: OperationStartEvent) {
|
||||
// This method will never be called when registered in a `BuildServiceRegistry` (ie. Gradle 6.1 & higher)
|
||||
// No-op
|
||||
}
|
||||
|
||||
override fun progress(operationIdentifier: OperationIdentifier, progressEvent: OperationProgressEvent) {
|
||||
// This method will never be called when registered in a `BuildServiceRegistry` (ie. Gradle 6.1 & higher)
|
||||
// No-op
|
||||
}
|
||||
|
||||
override fun finished(buildOperation: BuildOperationDescriptor, finishEvent: OperationFinishEvent) {
|
||||
handleBuildOperationType<
|
||||
ResolveConfigurationDependenciesBuildOperationType.Details,
|
||||
ResolveConfigurationDependenciesBuildOperationType.Result
|
||||
>(buildOperation, finishEvent) { details, result -> extractConfigurationDependencies(details, result) }
|
||||
}
|
||||
|
||||
private inline fun <reified D, reified R> handleBuildOperationType(
|
||||
buildOperation: BuildOperationDescriptor,
|
||||
finishEvent: OperationFinishEvent,
|
||||
handler: (details: D, result: R) -> Unit
|
||||
) {
|
||||
try {
|
||||
handleBuildOperationTypeRaw<D, R>(buildOperation, finishEvent, handler)
|
||||
} catch (e: Throwable) {
|
||||
thrownExceptions.add(e)
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun <reified D, reified R> handleBuildOperationTypeRaw(
|
||||
buildOperation: BuildOperationDescriptor,
|
||||
finishEvent: OperationFinishEvent,
|
||||
handler: (details: D, result: R) -> Unit
|
||||
) {
|
||||
val details: D? = buildOperation.details.let {
|
||||
if (it is D) it else null
|
||||
}
|
||||
val result: R? = finishEvent.result.let {
|
||||
if (it is R) it else null
|
||||
}
|
||||
if (details == null && result == null) {
|
||||
return
|
||||
} else if (details == null || result == null) {
|
||||
throw IllegalStateException("buildOperation.details & finishedEvent.result were unexpected types")
|
||||
}
|
||||
handler(details, result)
|
||||
}
|
||||
|
||||
private fun extractConfigurationDependencies(
|
||||
details: ResolveConfigurationDependenciesBuildOperationType.Details,
|
||||
result: ResolveConfigurationDependenciesBuildOperationType.Result
|
||||
) {
|
||||
val repositories = details.repositories?.mapNotNull {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
Repository(
|
||||
id = it.id,
|
||||
type = enumValueOf(it.type),
|
||||
name = it.name,
|
||||
m2Compatible = it.type == "MAVEN" || (it.properties["M2_COMPATIBLE"] as? Boolean) ?: false,
|
||||
metadataSources = (it.properties["METADATA_SOURCES"] as? List<String>) ?: emptyList(),
|
||||
metadataResources = metadataResources(it),
|
||||
artifactResources = artifactResources(it),
|
||||
)
|
||||
} ?: emptyList()
|
||||
val rootComponent = result.rootComponent
|
||||
|
||||
if (rootComponent.dependencies.isEmpty()) {
|
||||
// No dependencies to extract: can safely ignore
|
||||
return
|
||||
}
|
||||
val projectIdentityPath = (rootComponent.id as? DefaultProjectComponentIdentifier)?.identityPath?.path
|
||||
|
||||
// TODO: At this point, any resolution not bound to a particular project will be assigned to the root "build :"
|
||||
// This is because `details.buildPath` is always ':', which isn't correct in a composite build.
|
||||
// It is possible to do better. By tracking the current build operation context, we can assign more precisely.
|
||||
// See the Gradle Enterprise Build Scan Plugin: `ConfigurationResolutionCapturer_5_0`
|
||||
val rootPath = projectIdentityPath ?: details.buildPath
|
||||
|
||||
if (!configurationFilter.include(rootPath, details.configurationName)) {
|
||||
LOGGER.debug("Ignoring resolved configuration: $rootPath - ${details.configurationName}")
|
||||
return
|
||||
}
|
||||
|
||||
val rootId = if (projectIdentityPath == null) "build $rootPath" else componentId(rootComponent)
|
||||
val rootSource = DependencySource(rootId, rootPath)
|
||||
val resolvedConfiguration = ResolvedConfiguration(rootSource, details.configurationName, repositories)
|
||||
|
||||
for (directDependency in getResolvedDependencies(rootComponent)) {
|
||||
val directDep = createComponentNode(
|
||||
componentId(directDependency),
|
||||
rootSource,
|
||||
true,
|
||||
directDependency,
|
||||
result.getRepositoryId(directDependency)
|
||||
)
|
||||
resolvedConfiguration.addDependency(directDep)
|
||||
|
||||
walkComponentDependencies(result, directDependency, directDep.source, resolvedConfiguration)
|
||||
}
|
||||
|
||||
resolvedConfigurations.add(resolvedConfiguration)
|
||||
}
|
||||
|
||||
private fun walkComponentDependencies(
|
||||
result: ResolveConfigurationDependenciesBuildOperationType.Result,
|
||||
component: ResolvedComponentResult,
|
||||
parentSource: DependencySource,
|
||||
resolvedConfiguration: ResolvedConfiguration
|
||||
) {
|
||||
val componentSource = getSource(component, parentSource)
|
||||
val direct = componentSource != parentSource
|
||||
|
||||
val dependencyComponents = getResolvedDependencies(component)
|
||||
for (dependencyComponent in dependencyComponents) {
|
||||
val dependencyId = componentId(dependencyComponent)
|
||||
if (!resolvedConfiguration.hasDependency(dependencyId)) {
|
||||
val dependencyNode = createComponentNode(
|
||||
dependencyId,
|
||||
componentSource,
|
||||
direct,
|
||||
dependencyComponent,
|
||||
result.getRepositoryId(component)
|
||||
)
|
||||
resolvedConfiguration.addDependency(dependencyNode)
|
||||
|
||||
walkComponentDependencies(result, dependencyComponent, componentSource, resolvedConfiguration)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getSource(component: ResolvedComponentResult, source: DependencySource): DependencySource {
|
||||
val componentId = component.id
|
||||
if (componentId is DefaultProjectComponentIdentifier) {
|
||||
return DependencySource(componentId(component), componentId.identityPath.path)
|
||||
}
|
||||
return source
|
||||
}
|
||||
|
||||
private fun getResolvedDependencies(component: ResolvedComponentResult): List<ResolvedComponentResult> {
|
||||
return component.dependencies.filterIsInstance<ResolvedDependencyResult>().map { it.selected }.filter { it != component }
|
||||
}
|
||||
|
||||
private fun createComponentNode(componentId: String, source: DependencySource, direct: Boolean, component: ResolvedComponentResult, repositoryId: String?): ResolvedDependency {
|
||||
val componentDependencies = component.dependencies.filterIsInstance<ResolvedDependencyResult>().map { componentId(it.selected) }
|
||||
return ResolvedDependency(
|
||||
componentId,
|
||||
source,
|
||||
direct,
|
||||
coordinates(component),
|
||||
repositoryId,
|
||||
componentDependencies
|
||||
)
|
||||
}
|
||||
|
||||
private fun componentId(component: ResolvedComponentResult): String {
|
||||
return component.id.displayName
|
||||
}
|
||||
|
||||
private fun coordinates(component: ResolvedComponentResult): DependencyCoordinates {
|
||||
// TODO: Consider and handle null moduleVersion
|
||||
val moduleVersionIdentifier = component.moduleVersion!!
|
||||
return DependencyCoordinates(
|
||||
moduleVersionIdentifier.group,
|
||||
moduleVersionIdentifier.name,
|
||||
moduleVersionIdentifier.version
|
||||
)
|
||||
}
|
||||
|
||||
private fun writeDependencyGraph() {
|
||||
val outputDirectory = getOutputDir()
|
||||
outputDirectory.mkdirs()
|
||||
createRenderer().outputDependencyGraph(resolvedConfigurations, outputDirectory)
|
||||
LOGGER.info("Wrote dependency graph to ${getOutputDir()}")
|
||||
}
|
||||
|
||||
private fun createRenderer(): DependencyGraphRenderer {
|
||||
LOGGER.info("Constructing renderer: ${getRendererClassName()}")
|
||||
return Class.forName(getRendererClassName()).getDeclaredConstructor().newInstance() as DependencyGraphRenderer
|
||||
}
|
||||
|
||||
private fun getOutputDir(): File {
|
||||
if (dependencyGraphReportDir != null) {
|
||||
return File(dependencyGraphReportDir!!)
|
||||
}
|
||||
|
||||
if (rootProjectBuildDirectory == null) {
|
||||
throw RuntimeException("Cannot determine report file location")
|
||||
}
|
||||
return File(
|
||||
rootProjectBuildDirectory,
|
||||
"reports/nix-dependency-graph"
|
||||
)
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
if (thrownExceptions.isNotEmpty()) {
|
||||
throw DefaultMultiCauseException(
|
||||
"The Gradle2Nix plugin encountered errors while extracting dependencies. " +
|
||||
"Please report this issue at: https://github.com/tadfisher/gradle2nix/issues",
|
||||
thrownExceptions
|
||||
)
|
||||
}
|
||||
try {
|
||||
writeDependencyGraph()
|
||||
} catch (e: RuntimeException) {
|
||||
throw GradleException(
|
||||
"The Gradle2Nix plugin encountered errors while writing the dependency snapshot json file. " +
|
||||
"Please report this issue at: https://github.com/tadfisher/gradle2nix/issues",
|
||||
e
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOGGER = Logging.getLogger(DependencyExtractor::class.java)
|
||||
|
||||
private const val M2_PATTERN =
|
||||
"[organisation]/[module]/[revision]/[artifact]-[revision](-[classifier])(.[ext])"
|
||||
|
||||
private const val IVY_ARTIFACT_PATTERN = "[organisation]/[module]/[revision]/[type]s/[artifact](.[ext])";
|
||||
|
||||
private fun resources(urls: List<URI>, patterns: List<String>): List<String> {
|
||||
if (urls.isEmpty()) {
|
||||
return patterns
|
||||
}
|
||||
if (patterns.isEmpty()) {
|
||||
return urls.map { it.toString() }
|
||||
}
|
||||
return mutableListOf<String>().apply {
|
||||
for (pattern in patterns) {
|
||||
for (url in urls) {
|
||||
add(
|
||||
url.toString()
|
||||
.removeSuffix("/")
|
||||
.plus("/")
|
||||
.plus(pattern.removePrefix("/"))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun metadataResources(
|
||||
repository: ResolveConfigurationDependenciesBuildOperationType.Repository
|
||||
): List<String> {
|
||||
return when (repository.type) {
|
||||
Repository.Type.MAVEN.name -> {
|
||||
resources(
|
||||
listOfNotNull(repository.properties["URL"] as? URI),
|
||||
listOf(M2_PATTERN)
|
||||
)
|
||||
}
|
||||
Repository.Type.IVY.name -> {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
resources(
|
||||
listOfNotNull(repository.properties["URL"] as? URI),
|
||||
repository.properties["IVY_PATTERNS"] as? List<String> ?: listOf(IVY_ARTIFACT_PATTERN)
|
||||
)
|
||||
}
|
||||
else -> emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
private fun artifactResources(
|
||||
repository: ResolveConfigurationDependenciesBuildOperationType.Repository
|
||||
): List<String> {
|
||||
return when (repository.type) {
|
||||
Repository.Type.MAVEN.name -> {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
resources(
|
||||
listOfNotNull(repository.properties["URL"] as? URI)
|
||||
.plus(repository.properties["ARTIFACT_URLS"] as? List<URI> ?: emptyList()),
|
||||
listOf(M2_PATTERN)
|
||||
)
|
||||
}
|
||||
Repository.Type.IVY.name -> {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
resources(
|
||||
listOfNotNull(repository.properties["URL"] as? URI),
|
||||
repository.properties["ARTIFACT_PATTERNS"] as? List<String> ?: listOf(IVY_ARTIFACT_PATTERN)
|
||||
)
|
||||
}
|
||||
else -> emptyList()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package org.nixos.gradle2nix.dependencygraph.extractor
|
||||
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.services.BuildService
|
||||
import org.gradle.api.services.BuildServiceParameters
|
||||
|
||||
abstract class DependencyExtractorBuildService :
|
||||
DependencyExtractor(),
|
||||
BuildService<DependencyExtractorBuildService.Params>
|
||||
{
|
||||
// Some parameters for the web server
|
||||
internal interface Params : BuildServiceParameters {
|
||||
val rendererClassName: Property<String>
|
||||
}
|
||||
|
||||
override fun getRendererClassName(): String {
|
||||
return parameters.rendererClassName.get()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package org.nixos.gradle2nix.dependencygraph.extractor
|
||||
|
||||
open class LegacyDependencyExtractor(
|
||||
private val rendererClassName: String
|
||||
) : DependencyExtractor() {
|
||||
|
||||
override fun getRendererClassName(): String {
|
||||
return rendererClassName
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package org.nixos.gradle2nix.dependencygraph.extractor
|
||||
|
||||
class ResolvedConfigurationFilter(projectFilter: String?, configurationFilter: String?) {
|
||||
val projectRegex = projectFilter?.toRegex()
|
||||
val configurationRegex = configurationFilter?.toRegex()
|
||||
|
||||
fun include(projectPath: String, configurationName: String): Boolean {
|
||||
if (projectRegex != null && !projectRegex.matches(projectPath)) {
|
||||
return false
|
||||
}
|
||||
if (configurationRegex != null && !configurationRegex.matches(configurationName)) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package org.nixos.gradle2nix.dependencygraph.util
|
||||
|
||||
import org.gradle.api.internal.GradleInternal
|
||||
import org.gradle.api.invocation.Gradle
|
||||
import org.gradle.api.model.ObjectFactory
|
||||
import org.gradle.api.provider.ProviderFactory
|
||||
import org.gradle.internal.operations.BuildOperationListenerManager
|
||||
|
||||
internal abstract class GradleExtensions {
|
||||
|
||||
inline val Gradle.providerFactory: ProviderFactory
|
||||
get() = service()
|
||||
|
||||
inline val Gradle.buildOperationListenerManager: BuildOperationListenerManager
|
||||
get() = service()
|
||||
}
|
||||
|
||||
internal inline fun <reified T> Gradle.service(): T =
|
||||
(this as GradleInternal).services.get(T::class.java)
|
||||
@@ -0,0 +1,6 @@
|
||||
package org.nixos.gradle2nix.dependencygraph.util
|
||||
|
||||
internal fun loadOptionalParam(envName: String): String? {
|
||||
return System.getProperty(envName)
|
||||
?: System.getenv()[envName]
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package org.nixos.gradle2nix
|
||||
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.invocation.Gradle
|
||||
import org.gradle.api.tasks.TaskProvider
|
||||
import org.gradle.util.GradleVersion
|
||||
import org.nixos.gradle2nix.forceresolve.LegacyResolveProjectDependenciesTask
|
||||
import org.nixos.gradle2nix.forceresolve.ResolveProjectDependenciesTask
|
||||
|
||||
// TODO: Rename these
|
||||
|
||||
/**
|
||||
* Adds a task to resolve all dependencies in a Gradle build tree.
|
||||
*/
|
||||
class ForceDependencyResolutionPlugin : Plugin<Gradle> {
|
||||
override fun apply(gradle: Gradle) {
|
||||
gradle.projectsEvaluated {
|
||||
val resolveAllDeps = gradle.rootProject.tasks.register(RESOLVE_ALL_TASK)
|
||||
|
||||
// Depend on "dependencies" task in all projects
|
||||
gradle.allprojects { project ->
|
||||
val projectTaskFactory = getResolveProjectDependenciesTaskFactory()
|
||||
val resolveProjectDeps = projectTaskFactory.create(project)
|
||||
resolveAllDeps.configure {
|
||||
it.dependsOn(resolveProjectDeps)
|
||||
}
|
||||
}
|
||||
|
||||
// Depend on all 'resolveBuildDependencies' task in each included build
|
||||
gradle.includedBuilds.forEach { includedBuild ->
|
||||
resolveAllDeps.configure {
|
||||
it.dependsOn(includedBuild.task(":$RESOLVE_ALL_TASK"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getResolveProjectDependenciesTaskFactory(): ResolveProjectDependenciesTaskFactory {
|
||||
val gradleVersion = GradleVersion.current()
|
||||
val gradle8 = GradleVersion.version("8.0")
|
||||
return if (gradleVersion >= gradle8) {
|
||||
ResolveProjectDependenciesTaskFactory.Current
|
||||
} else {
|
||||
ResolveProjectDependenciesTaskFactory.Legacy
|
||||
}
|
||||
}
|
||||
|
||||
private sealed interface ResolveProjectDependenciesTaskFactory {
|
||||
fun create(project: Project): TaskProvider<out Task>
|
||||
|
||||
data object Current : ResolveProjectDependenciesTaskFactory {
|
||||
override fun create(project: Project): TaskProvider<out Task> {
|
||||
return project.tasks.register(RESOLVE_PROJECT_TASK, ResolveProjectDependenciesTask::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
data object Legacy : ResolveProjectDependenciesTaskFactory {
|
||||
override fun create(project: Project): TaskProvider<out Task> {
|
||||
return project.tasks.register(RESOLVE_PROJECT_TASK, LegacyResolveProjectDependenciesTask::class.java)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package org.nixos.gradle2nix.forceresolve
|
||||
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.artifacts.Configuration
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.gradle.work.DisableCachingByDefault
|
||||
|
||||
@DisableCachingByDefault(because = "Not worth caching")
|
||||
abstract class LegacyResolveProjectDependenciesTask: DefaultTask() {
|
||||
private fun getReportableConfigurations(): List<Configuration> {
|
||||
return project.configurations.filter { it.isCanBeResolved }
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
fun action() {
|
||||
for (configuration in getReportableConfigurations()) {
|
||||
configuration.incoming.resolutionResult.root
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package org.nixos.gradle2nix.forceresolve
|
||||
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.artifacts.Configuration
|
||||
import org.gradle.api.artifacts.result.ResolvedComponentResult
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.gradle.internal.serialization.Cached
|
||||
import org.gradle.work.DisableCachingByDefault
|
||||
|
||||
@DisableCachingByDefault(because = "Not worth caching")
|
||||
abstract class ResolveProjectDependenciesTask: DefaultTask() {
|
||||
private val configurationResolvers = Cached.of { createConfigurationResolvers() }
|
||||
|
||||
private fun createConfigurationResolvers(): List<Provider<ResolvedComponentResult>> {
|
||||
return getReportableConfigurations().map {
|
||||
it.incoming.resolutionResult.rootComponent
|
||||
}
|
||||
}
|
||||
|
||||
private fun getReportableConfigurations(): List<Configuration> {
|
||||
return project.configurations.filter { it.isCanBeResolved }
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
fun action() {
|
||||
for (configuration in configurationResolvers.get()) {
|
||||
configuration.get()
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user