How to configure a DSL style gradle plugin from a plugin extension - gradle

I have implemented a Gradle plugin using the Gradle DSL style. The plugin is adding multiple aspects such as a adding a custom task, and configuring more other tasks. Overall, the plugin is generating some metadata property file in a source folder that must be configured by a plugin extension.
apply plugin: 'artifactMetadata'
// configure the path for the metadata
artifactMetadata {
destinationDirectory = "src/main/generated/otherlocation/resources"
}
I have been able to figure out how to configure the task using the extension properties, however it's tricking me with the remaining stuff. What is a good approach to configure the source set, the clean task and the idea plugin (see the #n: TODO comments in the plugin code below)? The implementation below will always use the default value, not the one injected through the plugin extension.
class ArtifactMetadataPlugin implements Plugin<Project> {
public static final String EXTENSION_NAME = 'artifactMetadata'
public static final String TASK_NAME = 'generateArtifactMetadata'
void apply(Project project) {
createExtension(project)
project.configure (project) {
task (TASK_NAME, type: GenerateArtifactMetadata) {
group = project.group
artifact = project.name
version = project.version.toString()
}
sourceSets {
main {
// #1:TODO to get the plugin extension property current value here output.dir(project.artifactMetadata.destinationDirectory, builtBy: TASK_NAME)
resources.srcDirs += file(project.artifactMetadata.destinationDirectory)
}
}
clean {
// #2:TODO get the plugin extension property here
delete file(project.artifactMetadata.destinationDirectory)
}
if (project.plugins.hasPlugin(IdeaPlugin)) {
idea {
module {
// #3:TODO get the plugin extension property here
sourceDirs += file(project.artifactMetadata.destinationDirectory)
}
}
}
}
project.afterEvaluate {
def extension = project.extensions.findByName(EXTENSION_NAME)
project.tasks.withType(GenerateArtifactMetadata).all { task ->
task.destinationDirectory = project.file(extension.destinationDirectory)
}
}
}
private static void createExtension(Project project) {
def extension = project.extensions.create(EXTENSION_NAME, ArtifactMetadataPluginExtension)
extension.with {
destinationDirectory = "src/main/generated/artifactinfo/resources"
}
}
}

Related

How to use SettingsScriptApi API in Gradle Setting Plugin

files() API can use in setting.gradle.kt, but I cant use it in Setting Plugin.
class MyPlugin : Plugin<Settings> {
override fun apply(settings: Settings) {
// files() is not found
val file = settings.files("xx/xx")
}
}

Gradle plugin read configuration

I write a plugin for Gradle and I need to create dynamic tasks based on my extension configuration.
Example from build.gradle file:
exampleext {
t1 {
}
t2 {
}
}
So I want to create tasks like sometask#t1 and sometask#t2 and so on.
I could not find any info, how could I read this Closure configuration and use it for building these tasks? It's read in tasks only, but I want to use it before executing tasks.
Thanks in advance.
You could use Groovy's dynamic features:
class ExamplePlugin implements Plugin<Project> {
void apply(Project project) {
project.extensions.create("exampleext", ExampleExt, project)
}
}
class ExampleExt {
Project project
ExampleExt(Project project) {
this.project = project
}
def methodMissing(String name, Object args) {
def configClosure = args ? args[0] : {}
project.tasks.create(name: "sometask#$name", type: Copy, configClosure)
}
}
apply plugin: ExamplePlugin
exampleext {
t1 {
from "src/main/java"
into "$buildDir/tmp/main"
}
t2 {
from "src/test/java"
into "$buildDir/tmp/test"
}
}
You can have a look at https://github.com/tschulte/gradle-jnlp-plugin/blob/374360c118e2a7373ee2fa5be7d1b784240bb1aa/gradle-jnlp-plugin/src/main/groovy/de/gliderpilot/gradle/jnlp/war/GradleJnlpWarPluginExtension.groovy, where I allow dynamic task creation plus some more nesting. E.g.
jnlpWar {
versions {
"1.0"('org.example:application:1.0:webstart#zip')
}
}
is made possible by
void versions(Closure closure) {
closure.delegate = new Versions()
closure()
}
private class Versions {
#Override
Object invokeMethod(String name, Object args) {
project.configurations.maybeCreate(name)
return project.dependencies.invokeMethod(name, args)
}
}
However, maybe you should have a look at the incubating gradle model (https://docs.gradle.org/current/userguide/software_model.html).

Gradle - publish all project's dependencies to another artifactory

As a software house, we are being asked, to deliver the software with all of its dependencies. The dependencies should be published to another artifactory. In another words - we would like to take all of the project's dependencies from our artifactory and publish them into another artifactory in a way that would enable the client to build the software.
Is there a way to do that in Gradle?
Adapted from this gist
public class MavenArtifactCopyTask extends DefaultTask {
#Input
List<Configuration> configurations;
#OutputDirectory
File repoDir
#TaskAction
void build() {
for (Configuration configuration : configurations) {
copyJars(configuration)
copyPoms(configuration)
}
}
private void copyJars(Configuration configuration) {
configuration.resolvedConfiguration.resolvedArtifacts.each { artifact ->
def moduleVersionId = artifact.moduleVersion.id
File moduleDir = new File(repoDir, "${moduleVersionId.group.replace('.','/')}/${moduleVersionId.name}/${moduleVersionId.version}")
GFileUtils.mkdirs(moduleDir)
GFileUtils.copyFile(artifact.file, new File(moduleDir, artifact.file.name))
}
}
private void copyPoms(Configuration configuration) {
def componentIds = configuration.incoming.resolutionResult.allDependencies.collect { it.selected.id }
def result = project.dependencies.createArtifactResolutionQuery()
.forComponents(componentIds)
.withArtifacts(MavenModule, MavenPomArtifact)
.execute()
for(component in result.resolvedComponents) {
def componentId = component.id
if(componentId instanceof ModuleComponentIdentifier) {
File moduleDir = new File(repoDir, "${componentId.group.replace('.','/')}/${componentId.module}/${componentId.version}")
GFileUtils.mkdirs(moduleDir)
File pomFile = component.getArtifacts(MavenPomArtifact)[0].file
GFileUtils.copyFile(pomFile, new File(moduleDir, pomFile.name))
}
}
}
}
Usage
task copyMavenArtifacts(type: MavenArtifactCopyTask) {
configurations = [project.configurations.all, project.buildScript.configurations.classpath]
repoDir = file("$buildDir/mavenArtifacts")
}
Once all the jars & poms are in a local folder in a maven directory structure you can
Upload them all to another repository
Use the folder as a maven repository
You can use repository replication https://www.jfrog.com/confluence/display/RTF/Repository+Replication

Gradle get dependency programatically without configuration

Is there an option to get Maven dependency in Gradle without using custom configuration for it? For example in custom plugin to just obtain dependency provided from extension? Something like
class DependencyPlugin implements Plugin<Project> {
void apply(Project project) {
project.extensions.create("deps", DepsExtension)
project.task('useDependency') {
doLast {
//use Gradle api to resolve dependency without custom configuration
project.resolve(project.deps.dependency)
}
}
}
}
class DepsExtension {
def dependency = 'custom:maven:1.0'
}
Something like this:
Configuration config = project.configurations.create('myPrivateConfig')
Dependency dep = project.dependencies.create('custom:maven:1.0') {
exclude group: 'foo', module: 'bar'
}
config.dependencies.add(dep)
Set<File> files = config.files
I do a similar thing in a gradle plugin here
References
https://docs.gradle.org/current/javadoc/org/gradle/api/artifacts/Configuration.html
https://docs.gradle.org/current/javadoc/org/gradle/api/artifacts/DependencySet.html
https://docs.gradle.org/current/javadoc/org/gradle/api/artifacts/dsl/DependencyHandler.html

Gradle plugin for custom language

I have a custom language (let's say it is MyLang but it can be any language) and I would like to make a plugin for it. The plugin needs to
be able to recognize the sourcesets for the language given with DSL
be able to compile them using an executable (the compiler)
I was able to create a plugin with a compile task (empty yet) and annotate a function with #LanguageType setting the language name to "mylang".
How can I modify the plugin to be possible to add sourcesets from build.gradle files using DSL like sourceSets { mylang { ... } }?
How can I modify the build task to be able to build the files of the source set?
class MylangBuildPlugin implements Plugin<Project> {
static final String COMPILE_TASK_NAME = 'compileMylang'
void apply(Project project) {
project.getPluginManager().apply(ComponentModelBasePlugin.class);
createCompileTask(project)
}
#LanguageType
void registerLanguage(LanguageTypeBuilder<BaseLanguageSourceSet> builder) {
builder.setLanguageName("mylang");
builder.defaultImplementation(BaseLanguageSourceSet.class);
}
private void createCompileTask(Project project) {
project.task(COMPILE_TASK_NAME) {
}
}
}

Resources