All-in-one env file

This commit is contained in:
Tad Fisher
2019-06-04 15:18:58 -07:00
parent 7b0e167335
commit 987c03604b
6 changed files with 2448 additions and 33 deletions

View File

@@ -2,6 +2,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins { plugins {
kotlin("jvm") kotlin("jvm")
kotlin("kapt")
application application
} }
@@ -24,6 +25,7 @@ dependencies {
implementation("com.squareup.moshi:moshi:latest.release") implementation("com.squareup.moshi:moshi:latest.release")
implementation("com.squareup.moshi:moshi-adapters:latest.release") implementation("com.squareup.moshi:moshi-adapters:latest.release")
implementation("com.squareup.moshi:moshi-kotlin:latest.release") implementation("com.squareup.moshi:moshi-kotlin:latest.release")
kapt("com.squareup.moshi:moshi-kotlin-codegen:latest.release")
implementation("com.squareup.okio:okio:latest.release") implementation("com.squareup.okio:okio:latest.release")
} }

View File

@@ -0,0 +1,77 @@
package org.nixos.gradle2nix
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
data class NixGradleEnv(
val project: String,
val pluginRepo: List<Dependency>,
val projectRepos: Map<String, List<Dependency>>
)
@JsonClass(generateAdapter = true)
data class Dependency(
val name: String,
val filename: String,
val path: String,
val urls: List<String>,
val sha256: String
)
fun buildEnv(builds: Map<String, DefaultBuild>): Map<String, NixGradleEnv> =
builds.mapValues { (path, build) ->
NixGradleEnv(
project = path,
pluginRepo = buildRepo(build.pluginDependencies).values.toList(),
projectRepos = mapOf(
"buildscript" to build.rootProject.collectDependencies(DefaultProject::buildscriptDependencies).values.toList(),
"project" to build.rootProject.collectDependencies(DefaultProject::projectDependencies).values.toList()
))
}
private fun DefaultProject.collectDependencies(chooser: DefaultProject.() -> DefaultDependencies): Map<DefaultArtifact, Dependency> {
val result = mutableMapOf<DefaultArtifact, Dependency>()
mergeRepo(result, buildRepo(chooser()))
for (child in children) {
mergeRepo(result, child.collectDependencies(chooser))
}
return result
}
private fun buildRepo(deps: DefaultDependencies): Map<DefaultArtifact, Dependency> =
deps.artifacts.associate { artifact ->
val name = with(artifact) {
buildString {
append("$groupId-$artifactId-$version")
if (classifier.isNotEmpty()) append("-$classifier")
append("-$extension")
replace(Regex("[^A-Za-z0-9+\\-._?=]"), "_")
}
}
val filename = with(artifact) {
buildString {
append("$artifactId-$version")
if (classifier.isNotEmpty()) append("-$classifier")
append(".$extension")
}
}
val path = with(artifact) { "${groupId.replace(".", "/")}/$artifactId/$version" }
val dep = Dependency(
name = name,
filename = filename,
path = path,
urls = deps.repositories.maven.flatMap { repo ->
repo.urls.map { "${it.removeSuffix("/")}/$path/$filename" }
},
sha256 = artifact.sha256
)
artifact to dep
}
private fun mergeRepo(base: MutableMap<DefaultArtifact, Dependency>, extra: Map<DefaultArtifact, Dependency>) {
extra.forEach { (artifact, dep) ->
base.merge(artifact, dep) { old, new ->
old.copy(urls = old.urls + (new.urls - old.urls))
}
}
}

View File

@@ -30,8 +30,8 @@ fun ProjectConnection.getBuildModel(config: Config, path: String): DefaultBuild
return model(Build::class.java) return model(Build::class.java)
.withArguments(arguments) .withArguments(arguments)
.apply { .apply {
if (config.verbose) { if (!config.quiet) {
setStandardOutput(System.out) setStandardOutput(System.err)
setStandardError(System.err) setStandardError(System.err)
} }
} }

View File

@@ -2,6 +2,8 @@ package org.nixos.gradle2nix
import com.github.ajalt.clikt.completion.CompletionCandidates import com.github.ajalt.clikt.completion.CompletionCandidates
import com.github.ajalt.clikt.core.CliktCommand import com.github.ajalt.clikt.core.CliktCommand
import com.github.ajalt.clikt.core.context
import com.github.ajalt.clikt.output.CliktHelpFormatter
import com.github.ajalt.clikt.parameters.arguments.ProcessedArgument import com.github.ajalt.clikt.parameters.arguments.ProcessedArgument
import com.github.ajalt.clikt.parameters.arguments.argument import com.github.ajalt.clikt.parameters.arguments.argument
import com.github.ajalt.clikt.parameters.arguments.convert import com.github.ajalt.clikt.parameters.arguments.convert
@@ -9,6 +11,7 @@ import com.github.ajalt.clikt.parameters.arguments.default
import com.github.ajalt.clikt.parameters.options.* import com.github.ajalt.clikt.parameters.options.*
import com.github.ajalt.clikt.parameters.types.file import com.github.ajalt.clikt.parameters.types.file
import com.squareup.moshi.Moshi import com.squareup.moshi.Moshi
import com.squareup.moshi.Types
import okio.buffer import okio.buffer
import okio.sink import okio.sink
import java.io.File import java.io.File
@@ -20,33 +23,30 @@ data class Config(
val projectDir: File, val projectDir: File,
val includes: List<File>, val includes: List<File>,
val buildSrc: Boolean, val buildSrc: Boolean,
val verbose: Boolean val quiet: Boolean
) { ) {
val allProjects = listOf(projectDir) + includes val allProjects = listOf(projectDir) + includes
} }
class Main : CliktCommand() { class Main : CliktCommand(
name = "gradle2nix"
) {
val wrapper: Boolean by option("--gradle-wrapper", "-w", val wrapper: Boolean by option("--gradle-wrapper", "-w",
help = "Use the project's gradle wrapper for building") help = "Use the project's gradle wrapper for building")
.flag() .flag()
val gradleVersion: String? by option("--gradle-version", "-g", val gradleVersion: String? by option("--gradle-version", "-g",
metavar = "VERSION",
help = "Use a specific Gradle version") help = "Use a specific Gradle version")
val configurations: List<String> by option(help = "Project configuration(s)").multiple() val configurations: List<String> by option("--configuration", "-c",
metavar = "NAME",
val projectDir: File by argument(help = "Path to the project root") help = "Add a configuration to resolve (default: all configurations)")
.projectDir() .multiple()
.default(File("."))
val outputDir: File by option("--out", "-o",
help = "Path to write Nix environment files")
.file(fileOkay = false, folderOkay = true)
.default(File("."))
val includes: List<File> by option("--include", "-i", val includes: List<File> by option("--include", "-i",
help = "Path to included build(s)", metavar = "DIR",
metavar = "DIR") help = "Add an additional project to include")
.file(exists = true, fileOkay = false, folderOkay = true, readable = true) .file(exists = true, fileOkay = false, folderOkay = true, readable = true)
.multiple() .multiple()
.validate { files -> .validate { files ->
@@ -58,33 +58,63 @@ class Main : CliktCommand() {
} }
} }
val buildSrc: Boolean by option("--enableBuildSrc", help = "Include buildSrc project") val outDir: File? by option("--out-dir", "-o",
.flag("--disableBuildSrc", default = true) metavar = "DIR",
help = "Path to write generated files (default: PROJECT-DIR)")
.file(fileOkay = false, folderOkay = true)
val verbose: Boolean by option("--verbose", "-v", help = "Enable verbose logging") val envFile: String by option("--env", "-e",
metavar = "FILENAME",
help = "Name of the environment file")
.default("gradle-env.json")
val buildSrc: Boolean by option("--build-src", "-b", help = "Include buildSrc project (default: true)")
.flag("--no-build-src", "-nb", default = true)
val quiet: Boolean by option("--quiet", "-q", help = "Disable logging")
.flag(default = false) .flag(default = false)
override fun run() { val projectDir: File by argument("PROJECT-DIR", help = "Path to the project root (default: .)")
val config = Config(wrapper, gradleVersion, configurations, projectDir, includes, buildSrc, verbose) .projectDir()
val (log, warn, error) = Logger(verbose = config.verbose) .default(File("."))
val json by lazy { Moshi.Builder().build().adapter(DefaultBuild::class.java).indent(" ") } init {
val out by lazy { outputDir.also { it.mkdirs() }} context {
helpFormatter = CliktHelpFormatter(showDefaultValues = true)
}
}
override fun run() {
val config = Config(wrapper, gradleVersion, configurations, projectDir, includes, buildSrc, quiet)
val (log, _, _) = Logger(verbose = !config.quiet)
val paths = resolveProjects(config).map { p -> val paths = resolveProjects(config).map { p ->
p.toRelativeString(config.projectDir) p.toRelativeString(config.projectDir)
} }
connect(config).use { connection -> val models = connect(config).use { connection ->
for (project in paths) { paths.associate { project ->
log("Resolving project model: ${project.takeIf { it.isNotEmpty() } ?: "root project"}") log("Resolving project model: ${project.takeIf { it.isNotEmpty() } ?: "root project"}...")
val build = connection.getBuildModel(config, project) project to connection.getBuildModel(config, project)
val filename = build.rootProject.name + ".json"
val file = out.resolve(filename)
file.sink().buffer().use { sink -> json.toJson(sink, build) }
log(" --> $file")
} }
} }
log("Building environment...")
val nixGradleEnv = buildEnv(models)
val outDir = outDir ?: projectDir
val envFile = outDir.resolve(envFile)
log("Writing environment to $envFile")
envFile.sink().buffer().use { out ->
Moshi.Builder().build()
.adapter<Map<String, NixGradleEnv>>(
Types.newParameterizedType(Map::class.java, String::class.java, NixGradleEnv::class.java)
)
.indent(" ")
.toJson(out, nixGradleEnv)
out.flush()
}
} }
} }

View File

@@ -1,7 +1,6 @@
plugins { plugins {
base base
idea idea
id("com.github.ben-manes.versions") version "0.21.0"
kotlin("jvm") version embeddedKotlinVersion apply false kotlin("jvm") version embeddedKotlinVersion apply false
kotlin("kapt") version embeddedKotlinVersion apply false kotlin("kapt") version embeddedKotlinVersion apply false
id("com.github.johnrengelman.shadow") version "5.0.0" apply false id("com.github.johnrengelman.shadow") version "5.0.0" apply false

2307
gradle-env.json Normal file

File diff suppressed because it is too large Load Diff