first functional version
This commit is contained in:
22
LICENSE.md
Normal file
22
LICENSE.md
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
Copyright 2020 Walter Oggioni
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person
|
||||||
|
obtaining a copy of this software and associated documentation
|
||||||
|
files (the "Software"), to deal in the Software without
|
||||||
|
restriction, including without limitation the rights to use,
|
||||||
|
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the
|
||||||
|
Software is furnished to do so, subject to the following
|
||||||
|
conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||||
|
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||||
|
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
OTHER DEALINGS IN THE SOFTWARE.
|
@@ -1,14 +1,15 @@
|
|||||||
repositories {
|
repositories {
|
||||||
jcenter()
|
jcenter()
|
||||||
|
mavenLocal()
|
||||||
}
|
}
|
||||||
|
|
||||||
group = "net.corda"
|
group = "net.woggioni.plugins"
|
||||||
version = 0.1
|
version = 0.1
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
`java-gradle-plugin`
|
`java-gradle-plugin`
|
||||||
`maven-publish`
|
`maven-publish`
|
||||||
id("org.jetbrains.kotlin.jvm") version("1.3.61")
|
id("org.jetbrains.kotlin.jvm") version("1.3.71")
|
||||||
id("com.gradle.plugin-publish") version("0.10.1")
|
id("com.gradle.plugin-publish") version("0.10.1")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,6 +27,7 @@ dependencies {
|
|||||||
|
|
||||||
// Use the Kotlin JDK 8 standard library.
|
// Use the Kotlin JDK 8 standard library.
|
||||||
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
|
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
|
||||||
|
implementation("net.woggioni:worth:1.0")
|
||||||
|
|
||||||
// Use the Kotlin test library.
|
// Use the Kotlin test library.
|
||||||
// testImplementation("org.jetbrains.kotlin:kotlin-test")
|
// testImplementation("org.jetbrains.kotlin:kotlin-test")
|
||||||
@@ -41,8 +43,8 @@ dependencies {
|
|||||||
gradlePlugin {
|
gradlePlugin {
|
||||||
// Define the plugin
|
// Define the plugin
|
||||||
val my_first_plugin by plugins.creating {
|
val my_first_plugin by plugins.creating {
|
||||||
id = "net.corda.my-first-plugin"
|
id = "net.woggioni.plugins.dependency-export"
|
||||||
implementationClass = "my.first.plugin.MyFirstPluginPlugin"
|
implementationClass = "net.woggioni.plugins.DependencyExportPlugin"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,3 +77,7 @@ tasks.withType<Wrapper>().configureEach {
|
|||||||
gradleVersion = "6.1.1"
|
gradleVersion = "6.1.1"
|
||||||
distributionType = Wrapper.DistributionType.ALL
|
distributionType = Wrapper.DistributionType.ALL
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
|
||||||
|
kotlinOptions.jvmTarget = "1.8"
|
||||||
|
}
|
@@ -7,4 +7,4 @@
|
|||||||
* in the user manual at https://docs.gradle.org/6.1.1/userguide/multi_project_builds.html
|
* in the user manual at https://docs.gradle.org/6.1.1/userguide/multi_project_builds.html
|
||||||
*/
|
*/
|
||||||
|
|
||||||
rootProject.name = "my-first-plugin"
|
rootProject.name = "dependency-export"
|
||||||
|
@@ -1,39 +0,0 @@
|
|||||||
/*
|
|
||||||
* This Kotlin source file was generated by the Gradle 'init' task.
|
|
||||||
*/
|
|
||||||
package my.first.plugin
|
|
||||||
|
|
||||||
import org.gradle.api.Project
|
|
||||||
import org.gradle.api.Plugin
|
|
||||||
|
|
||||||
|
|
||||||
///**
|
|
||||||
// * A simple 'hello world' plugin.
|
|
||||||
// */
|
|
||||||
//class MyFirstPluginPlugin: Plugin<Project> {
|
|
||||||
// override fun apply(project: Project) {
|
|
||||||
// // Register a task
|
|
||||||
// project.tasks.register("greeting") { task ->
|
|
||||||
// task.doLast {
|
|
||||||
// println("Hello from plugin 'my.first.plugin.greeting'")
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
open class MyFirstPluginPluginExtension {
|
|
||||||
var message: String? = null
|
|
||||||
var greeter: String? = null
|
|
||||||
}
|
|
||||||
|
|
||||||
class MyFirstPluginPlugin : Plugin<Project> {
|
|
||||||
override fun apply(project: Project) {
|
|
||||||
val extension = MyFirstPluginPluginExtension()
|
|
||||||
project.extensions.add(MyFirstPluginPluginExtension::class.java, "my_first_plugin", MyFirstPluginPluginExtension())
|
|
||||||
project.tasks.register("hello") {
|
|
||||||
it.doLast {
|
|
||||||
println("${extension.message} from ${extension.greeter}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
173
src/main/kotlin/net/woggioni/plugins/DependencyExportPlugin.kt
Normal file
173
src/main/kotlin/net/woggioni/plugins/DependencyExportPlugin.kt
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
/*
|
||||||
|
* This Kotlin source file was generated by the Gradle 'init' task.
|
||||||
|
*/
|
||||||
|
package net.woggioni.plugins
|
||||||
|
|
||||||
|
import net.woggioni.jwo.JWO
|
||||||
|
import net.woggioni.jwo.tree.StackContext
|
||||||
|
import net.woggioni.jwo.tree.TreeNode
|
||||||
|
import net.woggioni.jwo.tree.TreeNodeVisitor
|
||||||
|
import net.woggioni.jwo.tree.TreeWalker
|
||||||
|
import net.woggioni.worth.serialization.json.JSONDumper
|
||||||
|
import net.woggioni.worth.value.ObjectValue
|
||||||
|
import net.woggioni.worth.xface.Value
|
||||||
|
import org.gradle.api.Plugin
|
||||||
|
import org.gradle.api.Project
|
||||||
|
import org.gradle.api.artifacts.component.ModuleComponentIdentifier
|
||||||
|
import org.gradle.api.artifacts.component.ProjectComponentIdentifier
|
||||||
|
import org.gradle.api.artifacts.result.ResolvedComponentResult
|
||||||
|
import org.gradle.api.artifacts.result.ResolvedDependencyResult
|
||||||
|
import org.gradle.api.artifacts.result.UnresolvedDependencyResult
|
||||||
|
import java.io.BufferedWriter
|
||||||
|
import java.io.OutputStreamWriter
|
||||||
|
import java.nio.file.Files
|
||||||
|
import java.nio.file.Paths
|
||||||
|
|
||||||
|
open class DependencyExportPluginExtension {
|
||||||
|
var configurationName: String = "default"
|
||||||
|
}
|
||||||
|
|
||||||
|
object DependencyExporter {
|
||||||
|
|
||||||
|
fun graphviz(project: Project, configurationName : String) {
|
||||||
|
var sequence = 0
|
||||||
|
val map = HashMap<ResolvedComponentResult, Int>()
|
||||||
|
val resolutionResult = project.configurations.single {
|
||||||
|
it.name == configurationName
|
||||||
|
}.incoming.resolutionResult
|
||||||
|
project.buildDir.toPath().let {
|
||||||
|
Files.createDirectories(it)
|
||||||
|
}.let {
|
||||||
|
BufferedWriter(
|
||||||
|
OutputStreamWriter(
|
||||||
|
Files.newOutputStream(project.buildDir.toPath().resolve("dependencies.dot"))))
|
||||||
|
}.use { writer ->
|
||||||
|
writer.write("digraph G {")
|
||||||
|
writer.newLine()
|
||||||
|
writer.write(" #rankdir=\"LR\";")
|
||||||
|
writer.newLine()
|
||||||
|
for (component in resolutionResult.allComponents) {
|
||||||
|
map.computeIfAbsent(component) {
|
||||||
|
sequence++
|
||||||
|
}
|
||||||
|
val (shape, color) = when (component.id) {
|
||||||
|
is ProjectComponentIdentifier -> "box" to "#88ff88"
|
||||||
|
is ModuleComponentIdentifier -> "oval" to "#ffff88"
|
||||||
|
else -> throw NotImplementedError("${component.id::class}")
|
||||||
|
}
|
||||||
|
val attrs = mapOf(
|
||||||
|
"label" to component.id.displayName,
|
||||||
|
"shape" to shape,
|
||||||
|
"style" to "filled",
|
||||||
|
"fillcolor" to color
|
||||||
|
)
|
||||||
|
writer.write(" node_${map[component]} [" +
|
||||||
|
attrs.entries
|
||||||
|
.asSequence()
|
||||||
|
.map { "${it.key}=\"${it.value}\"" }.joinToString(", ") +
|
||||||
|
"];")
|
||||||
|
writer.newLine()
|
||||||
|
}
|
||||||
|
|
||||||
|
for (component in resolutionResult.allComponents) {
|
||||||
|
|
||||||
|
component.dependencies.map { dependency ->
|
||||||
|
when (dependency) {
|
||||||
|
is ResolvedDependencyResult -> dependency
|
||||||
|
is UnresolvedDependencyResult -> {
|
||||||
|
throw dependency.failure
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
throw NotImplementedError("${dependency::class}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.map(ResolvedDependencyResult::getSelected).forEach { child ->
|
||||||
|
writer.write(" node_${map[component]} -> node_${map[child]};")
|
||||||
|
writer.newLine()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writer.write("}")
|
||||||
|
writer.newLine()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DependencyTreeNode(val component: ResolvedComponentResult) : TreeNode<DependencyTreeNode> {
|
||||||
|
override fun children(): Iterator<DependencyTreeNode> {
|
||||||
|
return object : Iterator<DependencyTreeNode> {
|
||||||
|
val it = component.dependencies.iterator()
|
||||||
|
override fun hasNext(): Boolean {
|
||||||
|
return it.hasNext()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun next(): DependencyTreeNode {
|
||||||
|
val dependency = it.next()
|
||||||
|
return when (dependency) {
|
||||||
|
is ResolvedDependencyResult -> {
|
||||||
|
DependencyTreeNode(dependency.selected)
|
||||||
|
}
|
||||||
|
is UnresolvedDependencyResult -> {
|
||||||
|
throw dependency.failure
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
throw NotImplementedError("${dependency::class}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun export(project: Project) {
|
||||||
|
val cfg = Value.Configuration.builder()
|
||||||
|
.serializeReferences(true)
|
||||||
|
.objectValueImplementation(ObjectValue.Implementation.ArrayList)
|
||||||
|
.build()
|
||||||
|
val result = ObjectValue.newInstance(cfg)
|
||||||
|
project.configurations.all { configuration ->
|
||||||
|
if (configuration.isCanBeResolved) {
|
||||||
|
val configDeps = ObjectValue.newInstance(cfg)
|
||||||
|
val visitor = object : TreeNodeVisitor<DependencyTreeNode, ObjectValue> {
|
||||||
|
override fun visitPre(stack: MutableList<StackContext<DependencyTreeNode, ObjectValue>>): TreeNodeVisitor.VisitOutcome {
|
||||||
|
val stackElement = JWO.tail(stack)
|
||||||
|
stackElement.context = ObjectValue.newInstance(cfg)
|
||||||
|
val id = stackElement.node.component.id
|
||||||
|
if (stack.size == 1) {
|
||||||
|
configDeps.put(id.displayName, stackElement.context)
|
||||||
|
} else if (stack.size > 1) {
|
||||||
|
val parentStackElement = JWO.tail(stack, -2)
|
||||||
|
parentStackElement.context.put(id.displayName, stackElement.context)
|
||||||
|
}
|
||||||
|
return TreeNodeVisitor.VisitOutcome.CONTINUE
|
||||||
|
}
|
||||||
|
// override fun visitPost(stack: MutableList<StackContext<DependencyTreeNode, ObjectValue>>?) {
|
||||||
|
// val stackElement = JWO.tail(stack)
|
||||||
|
// if(stack.size > 1) {
|
||||||
|
// val parentStackElement = JWO.tail(stack, -2)
|
||||||
|
// parentStackElement.context.add(StringValue(stackElement.node.component.toString()))
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
TreeWalker(visitor).walk(DependencyTreeNode(configuration.incoming.resolutionResult.root))
|
||||||
|
result.put(configuration.name, configDeps)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BufferedWriter(OutputStreamWriter(Files.newOutputStream(Paths.get("/tmp/dependencies.json")))).use {
|
||||||
|
JSONDumper.newInstance(cfg).dump(result, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DependencyExportPlugin : Plugin<Project> {
|
||||||
|
override fun apply(project: Project) {
|
||||||
|
val extension = DependencyExportPluginExtension()
|
||||||
|
project.extensions.add(DependencyExportPluginExtension::class.java, "exportDependencies", extension)
|
||||||
|
project.tasks.register("exportDependencies") {
|
||||||
|
it.doLast {
|
||||||
|
val propertyKey = "exportDependencies.configurationName"
|
||||||
|
val properties = project.properties
|
||||||
|
val configurationName = properties.getOrDefault(propertyKey, extension.configurationName) as String
|
||||||
|
DependencyExporter.graphviz(project, configurationName = configurationName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,4 +1,4 @@
|
|||||||
package my.first.plugin
|
package net.woggioni.plugins
|
||||||
|
|
||||||
import java.io.FileNotFoundException
|
import java.io.FileNotFoundException
|
||||||
import java.io.IOException
|
import java.io.IOException
|
@@ -1,23 +1,17 @@
|
|||||||
/*
|
/*
|
||||||
* This Kotlin source file was generated by the Gradle 'init' task.
|
* This Kotlin source file was generated by the Gradle 'init' task.
|
||||||
*/
|
*/
|
||||||
package my.first.plugin.test
|
package net.woggioni.plugins
|
||||||
|
|
||||||
import my.first.plugin.installResource
|
import net.woggioni.plugins.installResource
|
||||||
import org.gradle.testfixtures.ProjectBuilder
|
|
||||||
import org.gradle.testkit.runner.GradleRunner
|
import org.gradle.testkit.runner.GradleRunner
|
||||||
import org.junit.jupiter.api.BeforeEach
|
import org.junit.jupiter.api.BeforeEach
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import org.junit.jupiter.api.io.TempDir
|
import org.junit.jupiter.api.io.TempDir
|
||||||
import java.io.File
|
|
||||||
import java.net.URLClassLoader
|
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
|
|
||||||
|
|
||||||
/**
|
class DependencyExportPluginTest {
|
||||||
* A simple unit test for the 'my.first.plugin.greeting' plugin.
|
|
||||||
*/
|
|
||||||
class MyFirstPluginPluginTest {
|
|
||||||
|
|
||||||
@TempDir
|
@TempDir
|
||||||
lateinit var testProjectDir : Path
|
lateinit var testProjectDir : Path
|
||||||
@@ -37,33 +31,20 @@ class MyFirstPluginPluginTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun fooKotlin() {
|
fun testKotlin() {
|
||||||
installResource("build.gradle.kts", testProjectDir)
|
installResource("build.gradle.kts", testProjectDir)
|
||||||
installResource("settings.gradle.kts", testProjectDir)
|
installResource("settings.gradle.kts", testProjectDir)
|
||||||
installResource("gradle.properties", testProjectDir)
|
installResource("gradle.properties", testProjectDir)
|
||||||
val runner = getStandardGradleRunnerFor("hello")
|
val runner = getStandardGradleRunnerFor("exportDependencies")
|
||||||
val result = runner.build()
|
val result = runner.build()
|
||||||
println(result.output)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun fooGroovy() {
|
fun testGroovy() {
|
||||||
installResource("build.gradle", testProjectDir)
|
installResource("build.gradle", testProjectDir)
|
||||||
installResource("settings.gradle.kts", testProjectDir)
|
installResource("settings.gradle.kts", testProjectDir)
|
||||||
installResource("gradle.properties", testProjectDir)
|
installResource("gradle.properties", testProjectDir)
|
||||||
val runner = getStandardGradleRunnerFor("hello")
|
val runner = getStandardGradleRunnerFor("exportDependencies")
|
||||||
val result = runner.build()
|
val result = runner.build()
|
||||||
println(result.output)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Test
|
|
||||||
// fun `plugin registers task`() {
|
|
||||||
// // Create a test project and apply the plugin
|
|
||||||
// val project = ProjectBuilder.builder().build()
|
|
||||||
// project.plugins.apply("my.first.plugin.MyFirstPlugin")
|
|
||||||
//
|
|
||||||
// // Verify the result
|
|
||||||
// val task = project.tasks.findByName("hello")!!
|
|
||||||
// println(task.outputs.hasOutput)
|
|
||||||
// }
|
|
||||||
}
|
}
|
@@ -1,8 +0,0 @@
|
|||||||
plugins {
|
|
||||||
id "net.corda.my-first-plugin"
|
|
||||||
}
|
|
||||||
|
|
||||||
my_first_plugin {
|
|
||||||
message = 'Hi'
|
|
||||||
greeter = 'Gradle'
|
|
||||||
}
|
|
@@ -1,21 +0,0 @@
|
|||||||
//buildscript {
|
|
||||||
// repositories {
|
|
||||||
// mavenLocal()
|
|
||||||
// jcenter()
|
|
||||||
// mavenCentral()
|
|
||||||
// }
|
|
||||||
// dependencies {
|
|
||||||
// classpath("net.corda:my-first-plugin:0.1")
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
plugins {
|
|
||||||
id("net.corda.my-first-plugin")
|
|
||||||
}
|
|
||||||
//apply(plugin = "net.corda.my-first-plugin")
|
|
||||||
import my.first.plugin.MyFirstPluginPluginExtension
|
|
||||||
|
|
||||||
configure<my.first.plugin.MyFirstPluginPluginExtension> {
|
|
||||||
message = "Hi"
|
|
||||||
greeter = "Gradle"
|
|
||||||
}
|
|
17
src/test/resources/net/woggioni/plugins/build.gradle
Normal file
17
src/test/resources/net/woggioni/plugins/build.gradle
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
plugins {
|
||||||
|
id "org.jetbrains.kotlin.jvm" version "1.3.61"
|
||||||
|
id "net.woggioni.plugins.dependency-export"
|
||||||
|
}
|
||||||
|
|
||||||
|
exportDependencies {
|
||||||
|
configurationName = 'runtime'
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
jcenter()
|
||||||
|
mavenLocal()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
runtime("org.hibernate:hibernate-core:5.4.13.Final")
|
||||||
|
}
|
14
src/test/resources/net/woggioni/plugins/build.gradle.kts
Normal file
14
src/test/resources/net/woggioni/plugins/build.gradle.kts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
plugins {
|
||||||
|
kotlin("jvm") version "1.3.71"
|
||||||
|
id("net.woggioni.plugins.dependency-export")
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
jcenter()
|
||||||
|
mavenLocal()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
runtime("org.hibernate:hibernate-core:5.4.13.Final")
|
||||||
|
}
|
||||||
|
|
Reference in New Issue
Block a user