So I have a few tasks that do essentially the same thing but with different values, e.g.,
task tarArtifact (type: Tar) {
compression = Compression.GZIP
from "foobar" into "newfoobar"
extension = "tar.gz"
baseName = "MyArtifact"
version = "${project.artifactVersion}"
}
tarArtifact.dependsOn someBuildTask
It’s being called from maven publish
tasks , e.g.,
publications {
Module1(MavenPublication) {
groupId "..."
artifactId "Module1"
version "..."
artifact tarArtifact{ }
}
Module2(MavenPublication) {
groupId "..."
artifactId "Module2"
version "..."
artifact tarArtifact{ }
}
What I like to do it is pass into tarArtifact
values for from
, to
, baseName
and someBuildTask
, I can’t seem to find a simple way to do this, is this possible?
If I understand you correctly, you basically want to create a bunch of tasks based on a “template”. You could create a method to do this which takes the properties as method arguments.
def tarArtifactTask(fromDir, toDir, baseName, buildTask) {
return tasks.create("tar${baseName}Artifact", Tar) {
compression = Compression.GZIP
from fromDir {
into toDir
}
extension = "tar.gz"
baseName = baseName
version = "${project.artifactVersion}"
dependsOn buildTask
}
}
Mark, thanks for the suggestion, that looks exactly like what I needed but when I tried it, I got the error
Cannot add task ':tarFooBarArtifact' as a task with that name already exists.
I added a StackTraceElement
call to see why it’s being called twice and got this
called by defaultCall
called by tarArtifactTask
Any idea why this is being called twice? I assume one is the actual call but the other is a mystery to me.
Could you post the bit of your build script where you are calling the method?
Sure, here’s the snippet
publications {
Module1(MavenPublication) {
groupId "..."
artifactId "Module1"
version "..."
artifact tarArtifactTask("sourcepath", "destpath", "${project.ArtifactName}", xcodebuildDebug)
}
Let me know if you need something else
That second call sounds like it’s calling itself which doesn’t seem right. I wasn’t able to reproduce this error locally. Can you post your tarArtifactTask()
method implementation?
Yeah, that’s what it looked like to me too, it’s your code verbatim with StackTraceElement code included, here it is
def tarArtifactTask(fromDir, toDir, baseName, buildTask) {
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace()
println "called by " + stackTraceElements[2].getMethodName()
return tasks.create("tar${baseName}Artifact", Tar) {
compression = Compression.GZIP
from fromDir {
into toDir
}
extension = "tar.gz"
baseName = baseName
version = "${project.artifactVersion}"
dependsOn buildTask
}
}
Looks like we’ll have to rename the baseName
argument to something unique. Also, I’m assuming you are configuring multiple publications. In that case you’ll have to pass something unique for baseName
as project.ArtifactName
will create multiple tasks of the same name.
Yeah, that fixed the problem but now I get a new error
A problem occurred configuring root project 'Example'.
> Exception thrown while executing model rule: org.gradle.api.publish.plugins.PublishingPlugin$Rules#publishing(org.gradle.api.plugins.ExtensionContainer)
> Could not find property 'baseName' on root project 'Example'.
Here’s the revised code
def tarArtifactTask(fromDir, toDir, artifactName, buildTask) {
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace()
println "called by " + stackTraceElements[2].getMethodName()
return tasks.create("tar${baseName}Artifact", Tar) {
compression = Compression.GZIP
from fromDir {
into toDir
}
extension = "tar.gz"
baseName = artifactName
version = "${project.artifactVersion}"
dependsOn buildTask
}
}
Yes, you are correct, I have multiple publications and plan on passing in a unique value each time, thanks for all your help.
Your task name should use the new artifactName
argument.
"tar${artifactName}Artifact"
Oops, my bad, I fixed that but now got the same original error where tarArtifactTask
called itself
called by defaultCall
called by tarArtifactTask
> Cannot add task ':tarFooBarArtifact' as a task with that name already exists.
Revised code
def tarArtifactTask(fromDir, toDir, artifactName, buildTask) {
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace()
println "called by " + stackTraceElements[2].getMethodName()
return tasks.create("tar${artifactName}Artifact", Tar) {
compression = Compression.GZIP
from fromDir {
into toDir
}
extension = "tar.gz"
baseName = artifactName
version = "${project.artifactVersion}"
dependsOn buildTask
}
}
And you’re certain you’re passing unique values for the artifactName
argument? I tested this locally with multiple publications and it works. I get the same results from the StackTraceElement
. I would add some println
statements to show what arguments are being passed to the method call to help debug.
Yes I am passing unique values for artifactName
, I commented out all publishing task except for one and it still gave me the same error
called by defaultCall, artifactName = FooBar
called by tarArtifactTask, artifactName = FooBar
Revised code
def tarArtifactTask(fromDir, toDir, artifactName, buildTask) {
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace()
println "called by " + stackTraceElements[2].getMethodName() + ", artifactName = " + artifactName
return tasks.create("tar${artifactName}Artifact", Tar) {
compression = Compression.GZIP
from fromDir {
into toDir
}
extension = "tar.gz"
baseName = artifactName
version = "${project.artifactVersion}"
dependsOn buildTask
}
}
Are you saying that your StackTraceElement
also showed 2 calls, defaultCall
and tarArtifactTask
?
Not sure how relevant this is but here’s the snippet for xcodebuildDebug
gradle.taskGraph.whenReady {graph ->
if (graph.hasTask(xcodebuildRelease)) {
xcodebuild {
scheme = 'MyScheme'
target = 'MyTarget'
arch = 'arm64 armv7'
sdk = 'iphoneos'
configuration = 'Release'
}
}
if (graph.hasTask(xcodebuildDebug)) {
xcodebuild {
scheme = 'MyScheme'
target = 'MyTarget'
arch = 'i386 x86_64'
sdk = 'iphonesimulator'
configuration = 'Debug'
destination {
platform = 'iOS Simulator'
name = 'iPhone 6'
os = '8.2'
}
}
}
}
I am using the gradle-xcodePlugin
for iOS builds
Yes, but only when I have multiple publications configured. If you have only one publication and it’s still getting called twice, that is indeed a mystery to me. If you can provide a standalone test case for this I’d be happy to debug it. Otherwise, as a workaround for now you might just want to put a check in to see if the task exists before attempting to create it.
Ah ok, thank you for the info. Ok, I will try the workaround as suggested and if I have time, create a standalone test case, will keep you posted. Thanks and your help is much appreciated.
So I used maybeCreate
and it only creates if the task doesn’t exist, maybeCreate
returns "The found or created object. Never null."
Got past the 2 calls issue and later it threw this error
> Exception thrown while executing model rule: org.gradle.api.publish.plugins.PublishingPlugin$Rules#publishing(org.gradle.api.plugins.ExtensionContainer)
> Could not find method tarArtifactTask() for arguments [build/sym/Foobar.framework/, Foobar.framework, Foobar, task ':xcodebuildDebug'] on org.gradle.api.publish.maven.internal.publication.DefaultMavenPublication_Decorated@523130fa.
So it successfully calls the method but later it errors saying it can’t find the method?
Yeah, so weird. The error is reported on the same line as when it calls it, i.e., the last line in this code
publications {
Module1(MavenPublication) {
groupId "..."
artifactId "Module1"
version "..."
artifact tarArtifactTask("sourcepath", "destpath", "${project.ArtifactName}", xcodebuildDebug)
}
The log shows that it called it twice just like before.
There is definitely some goofyness going on here, which is hard for me to determine without knowing more about your build. This is the example I’ve been using to test. Running the publishToMavenLocal
task is successful in this example. Perhaps it can help you troubleshoot your problem.
apply plugin: 'java'
apply plugin: 'maven-publish'
group = 'org.gradle.foo'
version = '1.0.0-SNAPSHOT'
publishing {
publications {
module1(MavenPublication) {
artifact myTask("foo")
}
module2(MavenPublication) {
artifact myTask("bar")
}
}
}
def myTask(artifactName) {
return tasks.create("my${artifactName}Task", Zip) {
from 'build.gradle'
baseName = artifactName
}
}
Ok let me look into that tomorrow, gotta run now, will keep you posted. Thanks again for your help.