refactor of dependency-export plugin to allow for cli argument configuration
This commit is contained in:
30
build.gradle
Normal file
30
build.gradle
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
allprojects {
|
||||||
|
apply plugin: 'java-library'
|
||||||
|
repositories {
|
||||||
|
mavenLocal()
|
||||||
|
mavenCentral()
|
||||||
|
jcenter()
|
||||||
|
}
|
||||||
|
group = "net.woggioni.gradle"
|
||||||
|
version = 0.1
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
['compileOnly', 'annotationProcessor', 'testCompileOnly', 'testAnnotationProcessor'].each { conf ->
|
||||||
|
add(conf, [group: "org.projectlombok", name: "lombok", version: project['version.lombok']])
|
||||||
|
}
|
||||||
|
add("testImplementation", create(group: "org.junit.jupiter", name:"junit-jupiter-api", version: project["version.junitJupiter"]))
|
||||||
|
add("testRuntimeOnly", create(group: "org.junit.jupiter", name: "junit-jupiter-engine", version: project["version.junitJupiter"]))
|
||||||
|
add("testImplementation", gradleTestKit())
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.named("test", Test) {
|
||||||
|
useJUnitPlatform()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wrapper {
|
||||||
|
gradleVersion = "6.8"
|
||||||
|
distributionType = Wrapper.DistributionType.ALL
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@@ -1,26 +0,0 @@
|
|||||||
allprojects {
|
|
||||||
apply<JavaLibraryPlugin>()
|
|
||||||
repositories {
|
|
||||||
mavenLocal()
|
|
||||||
mavenCentral()
|
|
||||||
jcenter()
|
|
||||||
}
|
|
||||||
group = "net.woggioni.plugins"
|
|
||||||
version = 0.1
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
add("testImplementation", create(group="org.junit.jupiter", name="junit-jupiter-api", version=project["version.junitJupiter"]))
|
|
||||||
add("testRuntimeOnly", create(group="org.junit.jupiter", name="junit-jupiter-engine", version=project["version.junitJupiter"]))
|
|
||||||
add("testImplementation", gradleTestKit())
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.named<Test>("test") {
|
|
||||||
useJUnitPlatform()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.withType<Wrapper>().configureEach {
|
|
||||||
gradleVersion = "6.7"
|
|
||||||
distributionType = Wrapper.DistributionType.ALL
|
|
||||||
}
|
|
||||||
|
|
@@ -36,14 +36,12 @@ plugins {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also enable it globally on your machine just create a `~/.gradle/init.gradle` file with this content
|
You can also enable it globally on your machine, just create a `~/.gradle/init.gradle` file with this content
|
||||||
|
|
||||||
```groovy
|
```groovy
|
||||||
initscript {
|
initscript {
|
||||||
repositories {
|
repositories {
|
||||||
mavenLocal()
|
mavenLocal()
|
||||||
mavenCentral()
|
|
||||||
jcenter()
|
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath "net.woggioni.plugins:dependency-export:0.1"
|
classpath "net.woggioni.plugins:dependency-export:0.1"
|
||||||
@@ -82,18 +80,15 @@ renderDependencies {
|
|||||||
and using Kotlin DSL
|
and using Kotlin DSL
|
||||||
|
|
||||||
```kotlin
|
```kotlin
|
||||||
import net.woggioni.plugins.ExportDependenciesPluginExtension
|
tasks.named<net.woggioni.gradle.dependency.export.ExportDependencies>("exportDependencies") {
|
||||||
import net.woggioni.plugins.RenderDependenciesPluginExtension
|
configurationName.set("compileClasspath")
|
||||||
|
outputFile.set(project.file("dependencies.dot"))
|
||||||
configure<ExportDependenciesPluginExtension> {
|
|
||||||
configurationName = "default"
|
|
||||||
outputFile = "dependencies.dot"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
configure<RenderDependenciesPluginExtension> {
|
tasks.named<net.woggioni.gradle.dependency.export.RenderDependencies>("renderDependencies") {
|
||||||
format = "xlib"
|
format.set("xlib")
|
||||||
outputFile = "renderedDependencies"
|
outputFile.set(project.file("renderedDependencies"))
|
||||||
graphvizExecutable = "graphviz"
|
graphvizExecutable.set("graphviz")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -102,24 +97,30 @@ or using its correspondent Gradle's [project properties](https://docs.gradle.org
|
|||||||
For example to override the output format of the `renderDependencies` task from the CLI:
|
For example to override the output format of the `renderDependencies` task from the CLI:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
gradle -PrenderDependencies.format=svg renderDependencies
|
gradle exportDependencies --configuration=compileClasspath renderDependencies --format=svg
|
||||||
```
|
```
|
||||||
|
|
||||||
### Parameter description
|
### Parameter description
|
||||||
|
|
||||||
- `exportDependencies.configurationName` will select the Gradle's configuration
|
#### Attributes of task `net.woggioni.gradle.dependency.export.ExportDependencies`
|
||||||
(that word you put in the `dependencies` section of your build before `groupId:artifactId:versionId` tuple)
|
- `configurationName` will select the Gradle's configuration
|
||||||
that will be represented in the graph
|
(that word you put in the `dependencies` section of your build before `groupId:artifactId:versionId` tuple)
|
||||||
- `exportDependencies.outputFile` will specify the location of the generated `.dot` file
|
that will be represented in the graph. It can also be specified from CLI using `--configuration`.
|
||||||
(note that if a relative path is provided, it will be interpreted as relative to the project's build directory)
|
- `outputFile` will specify the location of the generated `.dot` file
|
||||||
- `renderDependencies.format` will specify the format of the file generated by Graphviz.
|
(note that if a relative path is provided, it will be interpreted as relative to the project's build directory).
|
||||||
|
It can also be specified from CLI using `--output`.
|
||||||
|
|
||||||
|
#### Attributes of task `net.woggioni.gradle.dependency.export.RenderDependencies`
|
||||||
|
- `format` will specify the format of the file generated by Graphviz.
|
||||||
The default output format is `xlib` which, on a linux machine with a GUI, will open
|
The default output format is `xlib` which, on a linux machine with a GUI, will open
|
||||||
a window with an interactive (with zoom and pan) view of your dependencies (this is a special format that
|
a window with an interactive (with zoom and pan) view of your dependencies (this is a special format that
|
||||||
will not output any file). Otherwise you can choose between any other output format supported by Graphviz,
|
will not output any file). Otherwise you can choose between any other output format supported by Graphviz,
|
||||||
refer to [its official documentation](https://graphviz.gitlab.io/_pages/doc/info/output.html) for more details.
|
refer to [its official documentation](https://graphviz.gitlab.io/_pages/doc/info/output.html) for more details.
|
||||||
- `renderDependencies.outputFile` will specify the location of the generated file (note that if a
|
It can also be specified from CLI using `--format`.
|
||||||
relative path is provided, it will be interpreted as relative to the project's build directory)
|
- `outputFile` will specify the location of the generated file (note that if a
|
||||||
- `renderDependencies.graphvizExecutable` will set the executable that will be launched to invoke
|
relative path is provided, it will be interpreted as relative to the project's build directory).
|
||||||
|
It can also be specified from CLI using `--output`.
|
||||||
|
- `graphvizExecutable` will set the executable that will be launched to invoke
|
||||||
Graphviz so that, if you have it installed in an exotic location outside of your `PATH` or, for
|
Graphviz so that, if you have it installed in an exotic location outside of your `PATH` or, for
|
||||||
any reason, you renamed it in some way, you can configure it here.
|
any reason, you renamed it in some way, you can configure it here.
|
||||||
|
|
||||||
|
@@ -1,16 +1,10 @@
|
|||||||
plugins {
|
plugins {
|
||||||
`java-gradle-plugin`
|
`java-gradle-plugin`
|
||||||
`maven-publish`
|
`maven-publish`
|
||||||
id("org.jetbrains.kotlin.jvm")
|
|
||||||
id("com.gradle.plugin-publish")
|
id("com.gradle.plugin-publish")
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
// Align versions of all Kotlin components
|
|
||||||
implementation(platform("org.jetbrains.kotlin:kotlin-bom"))
|
|
||||||
|
|
||||||
// Use the Kotlin JDK 8 standard library.
|
|
||||||
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
java {
|
java {
|
||||||
@@ -27,19 +21,8 @@ arrayOf("apiElements", "runtimeElements").forEach { name : String ->
|
|||||||
|
|
||||||
|
|
||||||
gradlePlugin {
|
gradlePlugin {
|
||||||
plugins {
|
val dependencyExportPlugin by plugins.creating {
|
||||||
create("DependencyExportPlugin") {
|
id = "net.woggioni.gradle.dependency-export"
|
||||||
id = "net.woggioni.plugins.dependency-export"
|
implementationClass = "net.woggioni.gradle.dependency.export.DependencyExportPlugin"
|
||||||
implementationClass = "net.woggioni.plugins.dependency.export.DependencyExportPlugin"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
|
|
||||||
kotlinOptions {
|
|
||||||
languageVersion = "1.3"
|
|
||||||
apiVersion = "1.3"
|
|
||||||
jvmTarget = "1.8"
|
|
||||||
javaParameters = true // Useful for reflection.
|
|
||||||
}
|
|
||||||
}
|
|
@@ -4,13 +4,12 @@ buildscript {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath "net.woggioni.plugins:dependency-export:0.1"
|
classpath "net.woggioni.gradle:dependency-export:0.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id "org.jetbrains.kotlin.jvm" version "1.3.61"
|
id "net.woggioni.gradle.dependency-export" version "0.1"
|
||||||
id "net.woggioni.plugins.dependency-export" version "0.1"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
@@ -18,9 +17,8 @@ repositories {
|
|||||||
mavenLocal()
|
mavenLocal()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
exportDependencies {
|
exportDependencies {
|
||||||
configurationName = 'runtime'
|
configurationName = 'runtimeCl'
|
||||||
}
|
}
|
||||||
|
|
||||||
renderDependencies {
|
renderDependencies {
|
||||||
|
@@ -5,16 +5,12 @@ buildscript {
|
|||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath("net.woggioni.plugins:dependency-export:0.1")
|
classpath("net.woggioni.gradle:dependency-export:0.1")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
import net.woggioni.plugins.ExportDependenciesPluginExtension
|
|
||||||
import net.woggioni.plugins.RenderDependenciesPluginExtension
|
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
kotlin("jvm") version "1.3.71"
|
id("net.woggioni.gradle.dependency-export") version "0.1"
|
||||||
id("net.woggioni.plugins.dependency-export") version "0.1"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
|
@@ -0,0 +1,32 @@
|
|||||||
|
package net.woggioni.gradle.dependency.export;
|
||||||
|
|
||||||
|
import org.gradle.api.Action;
|
||||||
|
import org.gradle.api.Plugin;
|
||||||
|
import org.gradle.api.Project;
|
||||||
|
import org.gradle.api.plugins.JavaBasePlugin;
|
||||||
|
import org.gradle.api.plugins.ObjectConfigurationAction;
|
||||||
|
import org.gradle.api.provider.Provider;
|
||||||
|
|
||||||
|
public class DependencyExportPlugin implements Plugin<Project> {
|
||||||
|
@Override
|
||||||
|
public void apply(Project project) {
|
||||||
|
project.apply(new Action<ObjectConfigurationAction>() {
|
||||||
|
@Override
|
||||||
|
public void execute(ObjectConfigurationAction objectConfigurationAction) {
|
||||||
|
objectConfigurationAction.plugin(JavaBasePlugin.class);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Provider<ExportDependencies> exportDependenciesTask =
|
||||||
|
project.getTasks().register("exportDependencies", ExportDependencies.class);
|
||||||
|
Provider<RenderDependencies> renderDependenciesTask =
|
||||||
|
project.getTasks().register("renderDependencies", RenderDependencies.class, new Action<RenderDependencies>() {
|
||||||
|
@Override
|
||||||
|
public void execute(RenderDependencies renderDependencies) {
|
||||||
|
renderDependencies.setExportTask(exportDependenciesTask);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// project.getExtensions().getExtraProperties().set(ExportDependencies.class.getSimpleName(), ExportDependencies.class);
|
||||||
|
project.getExtensions().getExtraProperties().set(RenderDependencies.class.getSimpleName(), RenderDependencies.class);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,204 @@
|
|||||||
|
package net.woggioni.gradle.dependency.export;
|
||||||
|
|
||||||
|
import lombok.*;
|
||||||
|
import org.gradle.api.DefaultTask;
|
||||||
|
import org.gradle.api.GradleException;
|
||||||
|
import org.gradle.api.artifacts.Configuration;
|
||||||
|
import org.gradle.api.artifacts.ResolvedArtifact;
|
||||||
|
import org.gradle.api.artifacts.component.ComponentIdentifier;
|
||||||
|
import org.gradle.api.artifacts.component.ModuleComponentIdentifier;
|
||||||
|
import org.gradle.api.artifacts.component.ProjectComponentIdentifier;
|
||||||
|
import org.gradle.api.artifacts.result.*;
|
||||||
|
import org.gradle.api.file.FileCollection;
|
||||||
|
import org.gradle.api.model.ObjectFactory;
|
||||||
|
import org.gradle.api.plugins.JavaPluginConvention;
|
||||||
|
import org.gradle.api.provider.Property;
|
||||||
|
import org.gradle.api.provider.Provider;
|
||||||
|
import org.gradle.api.tasks.Input;
|
||||||
|
import org.gradle.api.tasks.InputFiles;
|
||||||
|
import org.gradle.api.tasks.OutputFile;
|
||||||
|
import org.gradle.api.tasks.TaskAction;
|
||||||
|
import org.gradle.api.tasks.options.Option;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.Writer;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collector;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public class ExportDependencies extends DefaultTask {
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@Input
|
||||||
|
private Property<String> configurationName;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@OutputFile
|
||||||
|
private Property<File> outputFile;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@Input
|
||||||
|
private Property<Boolean> showArtifacts;
|
||||||
|
|
||||||
|
private final JavaPluginConvention javaPluginConvention;
|
||||||
|
|
||||||
|
|
||||||
|
@InputFiles
|
||||||
|
public Provider<FileCollection> getConfigurationFiles() {
|
||||||
|
return configurationName.flatMap(name -> getProject().getConfigurations().named(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Option(option = "configuration", description = "Set the configuration name")
|
||||||
|
public void setConfiguration(String configurationName) {
|
||||||
|
this.configurationName.set(configurationName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Option(option = "output", description = "Set the output file name")
|
||||||
|
public void setOutput(String outputFile) {
|
||||||
|
this.outputFile.set(getProject().file(outputFile));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Option(option = "showArtifacts", description = "Show artifacts")
|
||||||
|
public void setArtifacts(boolean value) {
|
||||||
|
showArtifacts.set(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public ExportDependencies(ObjectFactory objects) {
|
||||||
|
javaPluginConvention = getProject().getConvention().getPlugin(JavaPluginConvention.class);
|
||||||
|
configurationName = objects.property(String.class).convention("runtimeClasspath");
|
||||||
|
outputFile = objects.property(File.class).convention(
|
||||||
|
getProject().provider(() -> new File(javaPluginConvention.getDocsDir(), "dependencies.dot")));
|
||||||
|
showArtifacts = objects.property(Boolean.class).convention(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String quote(String s) {
|
||||||
|
return "\"" + s + "\"";
|
||||||
|
}
|
||||||
|
|
||||||
|
@TaskAction
|
||||||
|
@SneakyThrows
|
||||||
|
void run() {
|
||||||
|
Map<ResolvedComponentResult, Integer> map = new HashMap<>();
|
||||||
|
|
||||||
|
Configuration requestedConfiguration = Optional.ofNullable(getProject().getConfigurations().named(configurationName.get()).getOrNull()).orElseThrow(() -> {
|
||||||
|
String resolvableConfigurations = '[' + getProject().getConfigurations().stream()
|
||||||
|
.filter(Configuration::isCanBeResolved)
|
||||||
|
.map(it -> '\'' + it.getName() + '\'')
|
||||||
|
.collect(Collectors.joining(", ")) + ']';
|
||||||
|
throw new GradleException(String.format("Configuration '%s' doesn't exist or cannot be resolved, " +
|
||||||
|
"resolvable configurations in this project are %s", configurationName.get(), resolvableConfigurations));
|
||||||
|
});
|
||||||
|
ResolutionResult resolutionResult = requestedConfiguration.getIncoming().getResolutionResult();
|
||||||
|
Path destination = outputFile.map(it -> {
|
||||||
|
if (it.isAbsolute()) {
|
||||||
|
return it;
|
||||||
|
} else {
|
||||||
|
return new File(javaPluginConvention.getDocsDir(), it.toString());
|
||||||
|
}
|
||||||
|
}).map(File::toPath).get();
|
||||||
|
Files.createDirectories(destination.getParent());
|
||||||
|
try(Writer writer = Files.newBufferedWriter(destination)) {
|
||||||
|
writer.write("digraph G {");
|
||||||
|
writer.write('\n');
|
||||||
|
writer.write(" #rankdir=\"LR\";");
|
||||||
|
writer.write('\n');
|
||||||
|
Optional<Map<ComponentIdentifier, List<ResolvedArtifact>>> artifactMap = Optional.empty();
|
||||||
|
if(showArtifacts.get()) {
|
||||||
|
artifactMap = Optional.of(requestedConfiguration.getResolvedConfiguration().getResolvedArtifacts().stream().map(it ->
|
||||||
|
new AbstractMap.SimpleEntry<>(it.getId().getComponentIdentifier(), it)
|
||||||
|
).collect(Collectors.groupingBy(Map.Entry::getKey,
|
||||||
|
Collector.of(ArrayList::new,
|
||||||
|
(list, entry) -> list.add(entry.getValue()),
|
||||||
|
(l1, l2) -> { l1.addAll(l2); return l1; }))));
|
||||||
|
}
|
||||||
|
final int[] sequence = new int[1];
|
||||||
|
for (ResolvedComponentResult component : resolutionResult.getAllComponents()) {
|
||||||
|
map.computeIfAbsent(component, it -> sequence[0]++);
|
||||||
|
ComponentIdentifier id = component.getId();
|
||||||
|
Optional<List<ResolvedArtifact>> artifacts = artifactMap
|
||||||
|
.flatMap(it -> Optional.ofNullable(it.get(id)));
|
||||||
|
String componentName = id.getDisplayName();
|
||||||
|
String label = artifacts.map(it -> {
|
||||||
|
String rows = it.stream().map(resolvedArtifact -> {
|
||||||
|
String artifactDescription = Stream.of(
|
||||||
|
new AbstractMap.SimpleEntry<>("type", resolvedArtifact.getType()),
|
||||||
|
new AbstractMap.SimpleEntry<>("classifier", resolvedArtifact.getClassifier()),
|
||||||
|
new AbstractMap.SimpleEntry<>("extension",
|
||||||
|
!Objects.equals(resolvedArtifact.getExtension(), resolvedArtifact.getType()) ?
|
||||||
|
resolvedArtifact.getExtension() : null)
|
||||||
|
).map(entry -> {
|
||||||
|
if (entry.getValue() == null || entry.getValue().isEmpty()) return null;
|
||||||
|
else return entry.getKey() + ": " + entry.getValue();
|
||||||
|
}).collect(Collectors.joining(", "));
|
||||||
|
return "<TR><TD BGCOLOR=\"lightgrey\">" + artifactDescription + "</TD></TR>";
|
||||||
|
}).collect(Collectors.joining());
|
||||||
|
return "<<TABLE BORDER=\"0\" CELLBORDER=\"1\" CELLSPACING=\"0\" CELLPADDING=\"2\">" +
|
||||||
|
" <TR>" +
|
||||||
|
" <TD>" + id.getDisplayName() + "</TD>" +
|
||||||
|
" </TR>" +
|
||||||
|
" " + rows +
|
||||||
|
"</TABLE>>";
|
||||||
|
}).orElse(quote(componentName));
|
||||||
|
|
||||||
|
String shape;
|
||||||
|
String color;
|
||||||
|
if(id instanceof ProjectComponentIdentifier) {
|
||||||
|
shape = artifacts.isEmpty() ? "box" : "none";
|
||||||
|
color = "#88ff88";
|
||||||
|
} else if(id instanceof ModuleComponentIdentifier) {
|
||||||
|
shape = artifacts.isEmpty() ? "oval" : "none";
|
||||||
|
color = "#ffff88";
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException(id.getClass().getName());
|
||||||
|
}
|
||||||
|
Map<String, String> attrs = Stream.of(
|
||||||
|
new AbstractMap.SimpleEntry<>("label", label),
|
||||||
|
new AbstractMap.SimpleEntry<>("shape", quote(shape)),
|
||||||
|
new AbstractMap.SimpleEntry<>("style", quote("filled")),
|
||||||
|
artifacts.map(it -> new AbstractMap.SimpleEntry<>("margin", quote("0"))).orElse(null),
|
||||||
|
new AbstractMap.SimpleEntry<>("fillcolor", quote(color))
|
||||||
|
).filter(Objects::nonNull).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
|
||||||
|
writer.write(" node_" + map.get(component) + " [" +
|
||||||
|
attrs.entrySet().stream()
|
||||||
|
.map(it -> it.getKey() + '=' + it.getValue())
|
||||||
|
.collect(Collectors.joining(", ")) +
|
||||||
|
"];");
|
||||||
|
writer.write('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
@EqualsAndHashCode
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
class Link {
|
||||||
|
final ComponentIdentifier id1;
|
||||||
|
final ComponentIdentifier id2;
|
||||||
|
}
|
||||||
|
Set<Link> linkCache = new HashSet<>();
|
||||||
|
for (ResolvedComponentResult component : resolutionResult.getAllComponents()) {
|
||||||
|
for(DependencyResult dependency : component.getDependencies()) {
|
||||||
|
if(dependency instanceof ResolvedDependencyResult) {
|
||||||
|
ResolvedComponentResult child =
|
||||||
|
((ResolvedDependencyResult) dependency).getSelected();
|
||||||
|
if(linkCache.add(new Link(component.getId(), child.getId()))) {
|
||||||
|
writer.write(" node_" + map.get(component) + " -> node_" + map.get(child) + ";");
|
||||||
|
writer.write('\n');
|
||||||
|
}
|
||||||
|
} else if(dependency instanceof UnresolvedDependencyResult) {
|
||||||
|
throw ((UnresolvedDependencyResult) dependency).getFailure();
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException(dependency.getClass().getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writer.write('}');
|
||||||
|
writer.write('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,87 @@
|
|||||||
|
package net.woggioni.gradle.dependency.export;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import org.gradle.api.DefaultTask;
|
||||||
|
import org.gradle.api.GradleException;
|
||||||
|
import org.gradle.api.model.ObjectFactory;
|
||||||
|
import org.gradle.api.plugins.JavaPluginConvention;
|
||||||
|
import org.gradle.api.provider.Property;
|
||||||
|
import org.gradle.api.provider.Provider;
|
||||||
|
import org.gradle.api.tasks.InputFile;
|
||||||
|
import org.gradle.api.tasks.TaskAction;
|
||||||
|
import org.gradle.api.tasks.options.Option;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import java.io.File;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class RenderDependencies extends DefaultTask {
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@InputFile
|
||||||
|
private Provider<File> sourceFile;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
private Property<String> format;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
private Property<String> graphvizExecutable;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
private Property<File> outputFile;
|
||||||
|
|
||||||
|
private final JavaPluginConvention javaPluginConvention;
|
||||||
|
|
||||||
|
@Option(option = "output", description = "Set the output file name")
|
||||||
|
public void setOutputCli(String outputFile) {
|
||||||
|
this.outputFile.set(getProject().file(outputFile));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Option(option = "format", description = "Set output format (see https://graphviz.org/doc/info/output.html)")
|
||||||
|
public void setFormatCli(String format) {
|
||||||
|
this.format.set(format);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExportTask(Provider<ExportDependencies> taskProvider) {
|
||||||
|
sourceFile = taskProvider.flatMap(ExportDependencies::getOutputFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public RenderDependencies(ObjectFactory objects) {
|
||||||
|
sourceFile = objects.property(File.class);
|
||||||
|
javaPluginConvention = getProject().getConvention().getPlugin(JavaPluginConvention.class);
|
||||||
|
format = objects.property(String.class).convention("xlib");
|
||||||
|
graphvizExecutable = objects.property(String.class).convention("dot");
|
||||||
|
outputFile = objects.property(File.class)
|
||||||
|
.convention(new File(javaPluginConvention.getDocsDir(), "renderedDependencies"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@TaskAction
|
||||||
|
@SneakyThrows
|
||||||
|
void run() {
|
||||||
|
Path destination = outputFile.map(it -> {
|
||||||
|
if (it.isAbsolute()) {
|
||||||
|
return it;
|
||||||
|
} else {
|
||||||
|
return new File(javaPluginConvention.getDocsDir(), it.toString());
|
||||||
|
}
|
||||||
|
}).map(File::toPath).get();
|
||||||
|
List<String> cmd = Arrays.asList(
|
||||||
|
graphvizExecutable.get(),
|
||||||
|
"-T" + format.get(),
|
||||||
|
"-o" + destination.toString(),
|
||||||
|
sourceFile.get().toString()
|
||||||
|
);
|
||||||
|
int returnCode = new ProcessBuilder(cmd).inheritIO().start().waitFor();
|
||||||
|
if (returnCode != 0) {
|
||||||
|
throw new GradleException("Error invoking graphviz");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,220 +0,0 @@
|
|||||||
package net.woggioni.plugins.dependency.export
|
|
||||||
|
|
||||||
import org.gradle.api.GradleException
|
|
||||||
import org.gradle.api.Plugin
|
|
||||||
import org.gradle.api.Project
|
|
||||||
import org.gradle.api.artifacts.ResolvedArtifact
|
|
||||||
import org.gradle.api.artifacts.component.ComponentIdentifier
|
|
||||||
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.Path
|
|
||||||
import java.nio.file.Paths
|
|
||||||
import kotlin.reflect.KMutableProperty0
|
|
||||||
|
|
||||||
|
|
||||||
open class ExportDependenciesPluginExtension(project: Project) {
|
|
||||||
var configurationName: String = "default"
|
|
||||||
var outputFile = project.buildDir.toPath().resolve("dependencies.dot")
|
|
||||||
var showArtifacts = false
|
|
||||||
}
|
|
||||||
|
|
||||||
open class RenderDependenciesPluginExtension(project: Project) {
|
|
||||||
var format: String = "xlib"
|
|
||||||
var outputFile = project.buildDir.toPath().resolve("renderedDependencies")
|
|
||||||
var graphvizExecutable: String = "dot"
|
|
||||||
}
|
|
||||||
|
|
||||||
private class Overrider(private val properties: Map<String, Any?>, private val prefix: String) {
|
|
||||||
inline fun <reified T> identity(arg: T): T {
|
|
||||||
return arg
|
|
||||||
}
|
|
||||||
|
|
||||||
fun overrideProperty(property: KMutableProperty0<String>) {
|
|
||||||
overrideProperty(property, ::identity)
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fun <reified V> overrideProperty(
|
|
||||||
property: KMutableProperty0<V>,
|
|
||||||
valueFactory: (String) -> V) {
|
|
||||||
val propertyKey = prefix + "." + property.name
|
|
||||||
val propertyValue = properties[propertyKey] as String?
|
|
||||||
if (propertyValue != null) {
|
|
||||||
property.set(valueFactory(propertyValue))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
object DependencyExporter {
|
|
||||||
|
|
||||||
private fun quote(s : String) = "\"" + s + "\""
|
|
||||||
|
|
||||||
fun exportDot(project: Project, ext: ExportDependenciesPluginExtension) {
|
|
||||||
val overrider = Overrider(project.properties, "exportDependencies")
|
|
||||||
overrider.overrideProperty(ext::configurationName)
|
|
||||||
overrider.overrideProperty(ext::outputFile) { value -> Paths.get(value) }
|
|
||||||
overrider.overrideProperty(ext::showArtifacts) { value -> value.toBoolean() }
|
|
||||||
|
|
||||||
var sequence = 0
|
|
||||||
val map = HashMap<ResolvedComponentResult, Int>()
|
|
||||||
|
|
||||||
val requestedConfiguration = project.configurations.singleOrNull {
|
|
||||||
it.name == ext.configurationName
|
|
||||||
}?.takeIf { it.isCanBeResolved } ?: let {
|
|
||||||
val resolvableConfigurations = "[" + project.configurations.asSequence()
|
|
||||||
.filter { it.isCanBeResolved }
|
|
||||||
.map { "'${it.name}'" }
|
|
||||||
.joinToString(",") + "]"
|
|
||||||
throw GradleException("Configuration '${ext.configurationName}' doesn't exist or cannot be resolved, " +
|
|
||||||
"resolvable configurations in this project are " + resolvableConfigurations)
|
|
||||||
}
|
|
||||||
|
|
||||||
val resolutionResult = requestedConfiguration.incoming.resolutionResult
|
|
||||||
if (!ext.outputFile.isAbsolute) {
|
|
||||||
ext.outputFile = project.buildDir.toPath().resolve(ext.outputFile)
|
|
||||||
}
|
|
||||||
Files.createDirectories(ext.outputFile.parent)
|
|
||||||
BufferedWriter(
|
|
||||||
OutputStreamWriter(
|
|
||||||
Files.newOutputStream(ext.outputFile))).use { writer ->
|
|
||||||
writer.write("digraph G {")
|
|
||||||
writer.newLine()
|
|
||||||
writer.write(" #rankdir=\"LR\";")
|
|
||||||
writer.newLine()
|
|
||||||
|
|
||||||
val artifactMap = if(ext.showArtifacts) {
|
|
||||||
requestedConfiguration.resolvedConfiguration.resolvedArtifacts.asSequence().map {
|
|
||||||
it.id.componentIdentifier to it
|
|
||||||
}.groupBy(
|
|
||||||
Pair<ComponentIdentifier, ResolvedArtifact>::first,
|
|
||||||
Pair<ComponentIdentifier, ResolvedArtifact>::second
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
|
|
||||||
for (component in resolutionResult.allComponents) {
|
|
||||||
map.computeIfAbsent(component) {
|
|
||||||
sequence++
|
|
||||||
}
|
|
||||||
val artifacts = artifactMap?.let { it[component.id] }
|
|
||||||
val (shape, color) = when (component.id) {
|
|
||||||
is ProjectComponentIdentifier -> (artifacts?.let { "none" } ?: "box") to "#88ff88"
|
|
||||||
is ModuleComponentIdentifier -> (artifacts?.let { "none" } ?: "oval") to "#ffff88"
|
|
||||||
else -> throw NotImplementedError("${component.id::class}")
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
val componentName = component.id.displayName
|
|
||||||
val label = artifacts?.let {
|
|
||||||
val rows = it.asSequence().map { resolvedArtifact ->
|
|
||||||
val artifactDescription = sequenceOf(
|
|
||||||
"type" to resolvedArtifact.type,
|
|
||||||
"classifier" to resolvedArtifact.classifier,
|
|
||||||
"extension" to resolvedArtifact.extension.takeIf {
|
|
||||||
resolvedArtifact.extension != resolvedArtifact.type
|
|
||||||
}
|
|
||||||
).mapNotNull { pair ->
|
|
||||||
when {
|
|
||||||
pair.second == null || pair.second.isEmpty() -> null
|
|
||||||
else -> "${pair.first}: ${pair.second}"
|
|
||||||
}
|
|
||||||
}.joinToString(", ")
|
|
||||||
"<TR><TD BGCOLOR=\"lightgrey\">$artifactDescription</TD></TR>"
|
|
||||||
}.joinToString()
|
|
||||||
"""
|
|
||||||
<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="2">
|
|
||||||
<TR>
|
|
||||||
<TD>${component.id.displayName}</TD>
|
|
||||||
</TR>
|
|
||||||
$rows
|
|
||||||
</TABLE>>
|
|
||||||
""".trimIndent()
|
|
||||||
} ?: quote(componentName)
|
|
||||||
|
|
||||||
val attrs = sequenceOf(
|
|
||||||
"label" to label,
|
|
||||||
"shape" to quote(shape),
|
|
||||||
"style" to quote("filled"),
|
|
||||||
artifacts?.let { "margin" to quote(0.toString()) },
|
|
||||||
"fillcolor" to quote(color)
|
|
||||||
).mapNotNull { it }.toMap()
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
object DependencyRenderer {
|
|
||||||
fun render(project: Project, ext: RenderDependenciesPluginExtension, sourceFile: Path) {
|
|
||||||
val overrider = Overrider(project.properties, "renderDependencies")
|
|
||||||
overrider.overrideProperty(ext::format)
|
|
||||||
overrider.overrideProperty(ext::graphvizExecutable)
|
|
||||||
overrider.overrideProperty(ext::outputFile) { value -> Paths.get(value) }
|
|
||||||
|
|
||||||
if (!ext.outputFile.isAbsolute) {
|
|
||||||
ext.outputFile = project.buildDir.toPath().resolve(ext.outputFile)
|
|
||||||
}
|
|
||||||
val cmd: List<String> = listOf(
|
|
||||||
ext.graphvizExecutable,
|
|
||||||
"-T${ext.format}",
|
|
||||||
"-o${ext.outputFile}",
|
|
||||||
sourceFile.toString()
|
|
||||||
|
|
||||||
)
|
|
||||||
val returnCode = ProcessBuilder(cmd).inheritIO().start().waitFor()
|
|
||||||
if (returnCode != 0) {
|
|
||||||
throw GradleException("Error invoking graphviz")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class DependencyExportPlugin : Plugin<Project> {
|
|
||||||
override fun apply(project: Project) {
|
|
||||||
val dependencyExportExtension = ExportDependenciesPluginExtension(project)
|
|
||||||
project.extensions.add(ExportDependenciesPluginExtension::class.java, "exportDependencies", dependencyExportExtension)
|
|
||||||
val exportDependenciesTask = project.tasks.register("exportDependencies") {
|
|
||||||
it.doLast {
|
|
||||||
DependencyExporter.exportDot(project, dependencyExportExtension)
|
|
||||||
}
|
|
||||||
}.get()
|
|
||||||
|
|
||||||
val renderDependenciesPluginExtension = RenderDependenciesPluginExtension(project)
|
|
||||||
project.extensions.add(RenderDependenciesPluginExtension::class.java, "renderDependencies", renderDependenciesPluginExtension)
|
|
||||||
project.tasks.register("renderDependencies") {
|
|
||||||
it.dependsOn(exportDependenciesTask)
|
|
||||||
it.doLast {
|
|
||||||
DependencyRenderer.render(project, renderDependenciesPluginExtension, dependencyExportExtension.outputFile)
|
|
||||||
}
|
|
||||||
}.get()
|
|
||||||
}
|
|
||||||
}
|
|
@@ -0,0 +1,93 @@
|
|||||||
|
package net.woggioni.gradle.dependency.export;
|
||||||
|
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import org.gradle.testkit.runner.GradleRunner;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.io.TempDir;
|
||||||
|
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.StandardCopyOption;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public class DependencyExportPluginTest {
|
||||||
|
|
||||||
|
private static InputStream resourceFromClass(Class<?> cls, String resourceName) {
|
||||||
|
return cls.getResourceAsStream(resourceName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static InputStream resourceFromClassLoader(Class<?> cls, String resourceName) {
|
||||||
|
return cls.getClassLoader().getResourceAsStream(resourceName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
private static void installResource(Class<?> cls, String resourceName, Path destination) {
|
||||||
|
Path outputFile;
|
||||||
|
Path realDestination;
|
||||||
|
if (Files.isSymbolicLink(destination)) {
|
||||||
|
realDestination = destination.toRealPath();
|
||||||
|
} else {
|
||||||
|
realDestination = destination;
|
||||||
|
}
|
||||||
|
if(!Files.exists(realDestination)) {
|
||||||
|
Files.createDirectories(realDestination.getParent());
|
||||||
|
outputFile = realDestination;
|
||||||
|
} else if(Files.isDirectory(realDestination)) {
|
||||||
|
outputFile = realDestination.resolve(resourceName.substring(1 + resourceName.lastIndexOf('/')));
|
||||||
|
} else if(Files.isRegularFile(realDestination)) {
|
||||||
|
outputFile = realDestination;
|
||||||
|
} else throw new IllegalStateException("Path '${realDestination}' is neither a file nor a directory");
|
||||||
|
Optional<InputStream> inputStreamOptional = Stream.<BiFunction<Class<?>, String, InputStream>>of(
|
||||||
|
DependencyExportPluginTest::resourceFromClass,
|
||||||
|
DependencyExportPluginTest::resourceFromClassLoader
|
||||||
|
).map(f -> f.apply(cls, resourceName)).filter(Objects::nonNull).findFirst();
|
||||||
|
try(InputStream inputStream = inputStreamOptional.orElseThrow(() -> new FileNotFoundException(resourceName))){
|
||||||
|
Files.copy(inputStream, outputFile, StandardCopyOption.REPLACE_EXISTING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@TempDir
|
||||||
|
public Path testGradleHomeDir;
|
||||||
|
|
||||||
|
@TempDir
|
||||||
|
public Path testProjectDir;
|
||||||
|
|
||||||
|
public Path buildFile;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void setup() {
|
||||||
|
buildFile = testProjectDir.resolve("build.gradle.kts");
|
||||||
|
}
|
||||||
|
|
||||||
|
public GradleRunner getStandardGradleRunnerFor(String taskName) {
|
||||||
|
return GradleRunner.create()
|
||||||
|
.withDebug(true)
|
||||||
|
.withProjectDir(testProjectDir.toFile())
|
||||||
|
.withArguments(taskName, "-s", "--info", "-g", testGradleHomeDir.toString())
|
||||||
|
.withPluginClasspath();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testKotlin() {
|
||||||
|
installResource(getClass(), "build.gradle.kts", testProjectDir);
|
||||||
|
installResource(getClass(),"settings.gradle.kts", testProjectDir);
|
||||||
|
installResource(getClass(),"gradle.properties", testProjectDir);
|
||||||
|
GradleRunner runner = getStandardGradleRunnerFor("exportDependencies");
|
||||||
|
runner.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGroovy() {
|
||||||
|
installResource(getClass(),"build.gradle", testProjectDir);
|
||||||
|
installResource(getClass(),"settings.gradle.kts", testProjectDir);
|
||||||
|
installResource(getClass(),"gradle.properties", testProjectDir);
|
||||||
|
GradleRunner runner = getStandardGradleRunnerFor("exportDependencies");
|
||||||
|
runner.build();
|
||||||
|
}
|
||||||
|
}
|
@@ -1,52 +0,0 @@
|
|||||||
/*
|
|
||||||
* This Kotlin source file was generated by the Gradle 'init' task.
|
|
||||||
*/
|
|
||||||
package net.woggioni.plugins.dependency.export
|
|
||||||
|
|
||||||
import org.gradle.testkit.runner.GradleRunner
|
|
||||||
import org.junit.jupiter.api.BeforeEach
|
|
||||||
import org.junit.jupiter.api.Test
|
|
||||||
import org.junit.jupiter.api.io.TempDir
|
|
||||||
import java.nio.file.Path
|
|
||||||
|
|
||||||
|
|
||||||
class DependencyExportPluginTest {
|
|
||||||
|
|
||||||
@TempDir
|
|
||||||
lateinit var testGradleHomeDir : Path
|
|
||||||
|
|
||||||
@TempDir
|
|
||||||
lateinit var testProjectDir : Path
|
|
||||||
lateinit var buildFile : Path
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
fun setup() {
|
|
||||||
buildFile = testProjectDir.resolve("build.gradle.kts")
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getStandardGradleRunnerFor(taskName: String): GradleRunner {
|
|
||||||
return GradleRunner.create()
|
|
||||||
.withDebug(true)
|
|
||||||
.withProjectDir(testProjectDir.toFile())
|
|
||||||
.withArguments(taskName, "-s", "--info", "-g", testGradleHomeDir.toString())
|
|
||||||
.withPluginClasspath()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testKotlin() {
|
|
||||||
installResource("build.gradle.kts", testProjectDir)
|
|
||||||
installResource("settings.gradle.kts", testProjectDir)
|
|
||||||
installResource("gradle.properties", testProjectDir)
|
|
||||||
val runner = getStandardGradleRunnerFor("exportDependencies")
|
|
||||||
runner.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testGroovy() {
|
|
||||||
installResource("build.gradle", testProjectDir)
|
|
||||||
installResource("settings.gradle.kts", testProjectDir)
|
|
||||||
installResource("gradle.properties", testProjectDir)
|
|
||||||
val runner = getStandardGradleRunnerFor("exportDependencies")
|
|
||||||
runner.build()
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,33 +0,0 @@
|
|||||||
package net.woggioni.plugins.dependency.export
|
|
||||||
|
|
||||||
import java.io.FileNotFoundException
|
|
||||||
import java.io.IOException
|
|
||||||
import java.nio.file.Files
|
|
||||||
import java.nio.file.Path
|
|
||||||
import java.nio.file.StandardCopyOption
|
|
||||||
|
|
||||||
|
|
||||||
@Throws(IOException::class)
|
|
||||||
fun Any.installResource(resourceName: String, destination: Path) {
|
|
||||||
val outputFile = run {
|
|
||||||
val realDestination = if (Files.isSymbolicLink(destination)) {
|
|
||||||
destination.toRealPath()
|
|
||||||
} else {
|
|
||||||
destination
|
|
||||||
}
|
|
||||||
when {
|
|
||||||
!Files.exists(realDestination) -> {
|
|
||||||
Files.createDirectories(realDestination.parent)
|
|
||||||
realDestination
|
|
||||||
}
|
|
||||||
Files.isDirectory(realDestination) ->
|
|
||||||
realDestination.resolve(resourceName.substring(1 + resourceName.lastIndexOf('/')))
|
|
||||||
Files.isRegularFile(realDestination) -> realDestination
|
|
||||||
else -> throw IllegalStateException("Path '${realDestination}' is neither a file nor a directory")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(javaClass.getResourceAsStream(resourceName)
|
|
||||||
?: javaClass.classLoader.getResourceAsStream(resourceName))?.use { inputStream ->
|
|
||||||
Files.copy(inputStream, outputFile, StandardCopyOption.REPLACE_EXISTING)
|
|
||||||
} ?: throw FileNotFoundException(resourceName)
|
|
||||||
}
|
|
@@ -0,0 +1,18 @@
|
|||||||
|
plugins {
|
||||||
|
id 'java-library'
|
||||||
|
id "net.woggioni.gradle.dependency-export"
|
||||||
|
}
|
||||||
|
|
||||||
|
exportDependencies {
|
||||||
|
configurationName = 'compileClasspath'
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
jcenter()
|
||||||
|
mavenLocal()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
runtimeOnly("org.hibernate:hibernate-core:5.4.13.Final")
|
||||||
|
}
|
||||||
|
|
@@ -0,0 +1,17 @@
|
|||||||
|
plugins {
|
||||||
|
id("java-library")
|
||||||
|
id("net.woggioni.gradle.dependency-export")
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
jcenter()
|
||||||
|
mavenLocal()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
runtimeOnly("org.hibernate:hibernate-core:5.4.13.Final")
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.named<net.woggioni.gradle.dependency.export.ExportDependencies>("exportDependencies") {
|
||||||
|
configurationName.set("compileClasspath")
|
||||||
|
}
|
@@ -1,17 +0,0 @@
|
|||||||
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")
|
|
||||||
}
|
|
@@ -1,14 +0,0 @@
|
|||||||
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")
|
|
||||||
}
|
|
||||||
|
|
@@ -1,2 +1,6 @@
|
|||||||
|
version.kotlin=1.3.72
|
||||||
|
version.gradlePublish=0.10.1
|
||||||
|
version.lombok=1.18.16
|
||||||
|
version.slf4j=1.7.30
|
||||||
version.junitJupiter=5.7.0
|
version.junitJupiter=5.7.0
|
||||||
version.junitPlatform=1.7.0
|
version.junitPlatform=1.7.0
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,5 +1,5 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.6-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-all.zip
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
2
gradlew
vendored
2
gradlew
vendored
@@ -130,7 +130,7 @@ fi
|
|||||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||||
|
|
||||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||||
|
|
||||||
# We build the pattern for arguments to be converted via cygpath
|
# We build the pattern for arguments to be converted via cygpath
|
||||||
|
21
gradlew.bat
vendored
21
gradlew.bat
vendored
@@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
|
|||||||
|
|
||||||
set JAVA_EXE=java.exe
|
set JAVA_EXE=java.exe
|
||||||
%JAVA_EXE% -version >NUL 2>&1
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
if "%ERRORLEVEL%" == "0" goto init
|
if "%ERRORLEVEL%" == "0" goto execute
|
||||||
|
|
||||||
echo.
|
echo.
|
||||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
@@ -54,7 +54,7 @@ goto fail
|
|||||||
set JAVA_HOME=%JAVA_HOME:"=%
|
set JAVA_HOME=%JAVA_HOME:"=%
|
||||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||||
|
|
||||||
if exist "%JAVA_EXE%" goto init
|
if exist "%JAVA_EXE%" goto execute
|
||||||
|
|
||||||
echo.
|
echo.
|
||||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||||
@@ -64,21 +64,6 @@ echo location of your Java installation.
|
|||||||
|
|
||||||
goto fail
|
goto fail
|
||||||
|
|
||||||
:init
|
|
||||||
@rem Get command-line arguments, handling Windows variants
|
|
||||||
|
|
||||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
|
||||||
|
|
||||||
:win9xME_args
|
|
||||||
@rem Slurp the command line arguments.
|
|
||||||
set CMD_LINE_ARGS=
|
|
||||||
set _SKIP=2
|
|
||||||
|
|
||||||
:win9xME_args_slurp
|
|
||||||
if "x%~1" == "x" goto execute
|
|
||||||
|
|
||||||
set CMD_LINE_ARGS=%*
|
|
||||||
|
|
||||||
:execute
|
:execute
|
||||||
@rem Setup the command line
|
@rem Setup the command line
|
||||||
|
|
||||||
@@ -86,7 +71,7 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
|||||||
|
|
||||||
|
|
||||||
@rem Execute Gradle
|
@rem Execute Gradle
|
||||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||||
|
|
||||||
:end
|
:end
|
||||||
@rem End local scope for the variables with windows NT shell
|
@rem End local scope for the variables with windows NT shell
|
||||||
|
15
settings.gradle
Normal file
15
settings.gradle
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
pluginManagement {
|
||||||
|
repositories {
|
||||||
|
gradlePluginPortal()
|
||||||
|
}
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id 'org.jetbrains.kotlin.jvm' version this['version.kotlin']
|
||||||
|
id 'com.gradle.plugin-publish' version this['version.gradlePublish']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rootProject.name = "my-gradle-plugins"
|
||||||
|
include("dependency-export")
|
||||||
|
include("jpms-check")
|
||||||
|
include("multi-release-jar")
|
@@ -1,11 +0,0 @@
|
|||||||
pluginManagement {
|
|
||||||
plugins {
|
|
||||||
id("org.jetbrains.kotlin.jvm") version "1.3.72" apply false
|
|
||||||
id("com.gradle.plugin-publish") version "0.10.1" apply false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rootProject.name = "my-gradle-plugins"
|
|
||||||
include("dependency-export")
|
|
||||||
include("jpms-check")
|
|
||||||
include("multi-release-jar")
|
|
Reference in New Issue
Block a user