I have a Gradle script in which I need to copy a bunch of files from srcPath to tgtPath while specifying include and exclude patterns.
Normaly I would do this with Gradle's built-in copy task but here I also need to convert the character encoding while doing so. I thus am trying to use the ant.copy method because it supports "encoding" and "outputEncoding" arguments, which are supposed to support exactly such conversions.
So I defined me a method as follows:
private void copy(String srcPath, String tgtPath, includePatterns = ['**/*'], excludePatterns = []) {
println "copying from '${srcPath}' to '${tgtPath}' (incl:'${includePatterns}' / excl:'${excludePatterns}'):"
new AntBuilder().copy(todir: tgtPath,
encoding: StandardCharsets.ISO_8859_1,
outputEncoding: StandardCharsets.UTF_8) {
fileset(dir: srcPath,
includes: includePatterns,
excludes: excludePatterns)
}
}
When I execute this as part of my Gradle build (actually within a .groovy file which is why I am using "new AntBuilder.copy(...)" here instead of just "ant.copy(...)" I get the following exception:
java.lang.ClassCastException: org.apache.xerces.parsers.XIncludeAwareParserConfiguration cannot be cast to org.apache.xerces.xni.parser.XMLParserConfiguration
??? What has this to do with XML-parsing? I don't understand at all why I am getting this error.
I only found a couple of examples but no real documentation on how to use this method from Groovy. Ant's documentation claims that "includes" and "excludes" accepts lists of arguments which is what I am passing here. Any idea, what am I doing wrong here or why this doesn't work?
Or any other suggestion on how to convert character encodings while copying files over in Gradle?
I suggest that you use Gradle's built in ant integration.
Eg:
project.ant.copy(todir: tgtPath,
encoding: StandardCharsets.ISO_8859_1,
outputEncoding: StandardCharsets.UTF_8) {
fileset(dir: srcPath,
includes: includePatterns,
excludes: excludePatterns)
}
Related
I need to generate FlatBuffers files from *.fbs file before the build.
So i'm using gradle.plugin.io.netifi:gradle-flatbuffers-plugin:1.0.7 to do it for me.
It works as expected for 1 task:
def generatedSourcePathJava = "$buildDir/generated/source/flatbuffers/java"
def generatedSourcePathCpp = "$buildDir/generated/source/flatbuffers/cpp"
...
task createFlatBuffersJava(type: io.netifi.flatbuffers.plugin.tasks.FlatBuffers) {
outputDir = file(generatedSourcePathJava)
language = "kotlin"
}
build.dependsOn createFlatBuffersJava
But if i add the 2nd one (to generate C++ files for JNI):
task createFlatBuffersJava(type: io.netifi.flatbuffers.plugin.tasks.FlatBuffers) {
outputDir = file(generatedSourcePathJava)
language = "kotlin"
}
task createFlatBuffersCpp(type: io.netifi.flatbuffers.plugin.tasks.FlatBuffers) {
outputDir = file(generatedSourcePathCpp)
language = "cpp"
}
assemble.dependsOn createFlatBuffersJava, createFlatBuffersCpp
Gradle build (../gradlew :engine-flatbuffers:clean :engine-flatbuffers:build) fails with the following:
What went wrong:
A problem occurred configuring project ':engine-flatbuffers'.
java.util.ConcurrentModificationException (no error message)
I think the question can be generalized to "How to add multiple tasks of the same type in Gradle?".
PS. "gradle-5.6-all"
That's a known plugin bug/feature reported at https://github.com/gregwhitaker/gradle-flatbuffers-plugin/issues/7.
It works in 1.0.5 but kotlin [argument] is sadly not supported there at that point. java works and it's compatible.
I've got a Java project build with Gradle and a property file that contains custom configuration for my testing framework (amount of thread to use, test environment url, custom username & password for those environments, etc...).
I'm facing an issue related to using properties from that file that I can't figure out:
if my Test task include '**/*Test.class', all tests are running as expected.
if my Test task include '**/MyTest.class', only that test is running as expected.
if my Test task include readProperty(), the task is skipped as NO-SOURCE. <- this is the part I can't understand - as the readProperty return the correct value.
Let's get into details:
This is how the property is defined in a my.property file:
testng.class.includes='**/MyTest.class'
This is what the build.gradle file looks like:
Properties props = new Properties()
props.load(new FileInputStream(projectDir.toString() + '/common.properties'))
def testsToRunWorking(p) {
String t = 'MyTest.class'
println "Tests = $t"
return t ? t : '**/*Test.class'
}
def testsToRunNotWorking(p) {
String t = getProperty(p, "testng.class.includes")
println "Tests = $t"
return t ? t : '**/*Test.class'
}
task testCustom(type: Test) {
outputs.upToDateWhen { false }
testLogging.showStandardStreams = true
classpath = configurations.customTest + sourceSets.customTest.output
include testsToRunNotWorking(props) ///< Does not work!
// include testsToRunWorking(props) ///< Works!
useTestNG()
}
In terms of debugging:
The println properly return the value I expect, even when the testCustom task doesn't do what I would expect.
I tried adding a dependsOn task just to print the content of testCustom.configure { println $includes } which looks correct as well.
--info
Tests = '**/MyTest.class'
:clean
:compileCustomTestJava - is not incremental (e.g. outputs have changed, no previous execution, etc.).
Note: Some input files use or override a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
Note: Some input files use unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
:processCustomTestResources
:customTestClasses
:testCustom NO-SOURCE
The core of the issue seems to be coming from the fact that I'm reading that value from property. I hard coded inside the build.gradle everything works as expected. If read from a property file - build stops with a NO-SOURCE statement.
Any idea?
Thanks!
You are using quotation marks in the values of your property files. Everything that comes after the assignment sign in a property file is used as value, so the quotation marks remain in the string. They are printed in your output Tests = '**/MyTest.class'. On the other hand, if you define a string in your (Groovy) code with quotation marks, they are not included in the string. Therefor, the passed strings are not the same.
Remove the quotation marks from your property file(s) and everything should work, since the class files will match your string without the quotation marks.
First, there are some common scripts deployed in private maven repo:
http://domain/repo/com/d/build/script/java-project/1.0/java-project-1.0.gradle
http://domain/repo/com/d/build/script/maven/1.0/maven-1.0.gradle
In the target project, build.gradle
subprojects {
apply from: 'http://domain/repo/com/d/build/script/java-project/1.0/java-project-1.0.gradle'
apply from: 'http://domain/repo/com/d/build/script/maven/1.0/maven-1.0.gradle'
}
it's OK!
but,
ext.applyScript = { script, version ->
apply from: "http://domain/repo/com/d/build/script/${script}/${version}/${script}-${version}.gradle"
}
subprojects {
applyScript('java-project', '1.0')
applyScript('maven', '1.0')
}
it will fail, with message:
"Error:Cannot add task ':javadocJar' as a task with that name already exists."
task ':javadocJar' is defined in script 'java-project-1.0.gradle'
and we have several sub projects.
why ?
BTW: anyone can give me a lead of source location of "apply from:"?
It's hard to location it by myself.
The problem is that in the latte case you are applying the scripts multiple times to the same root project.
How is that possible? It is quite interesting and a little bit tricky:
you are defining applyScript as a Closure on the extension container ext of the current Gradle project,
generally the apply from: ... is handled as a method call apply(Map) on the org.gradle.api.plugins.PluginAware interface which is one of the super interfaces of the org.gradle.api.Project interface
this means every time you write apply ... you are calling the apply method on the current Gradle project (the one where the apply ... is specified)
as you defined the apply ... as part of the closure, the standard delegation applies
it is semantically the same as this.apply ...
this by default points to the enclosing class/object which is the root project (here it cannot be anything else)
So even if it looks like you are applying the 2 scripts to all the subprojects, you are actually applying the 2 scripts N times to the root project (N is the number of subprojects).
What you need to do is to change the delegate to the correct Project instance.:
you can do it very easily by adding one additional argument to the closure and explicitly calling the apply method on that argument:
ext.applyScript = { project, script, version ->
project.apply from: "..."
}
subprojects {
applyScript(it, 'java-project', '1.0')
applyScript(it, 'maven', '1.0')
}
or you can set the delegate explicitly:
ext.applyScript = { script, version ->
apply from: "..."
}
subprojects {
applyScript.resolveStrategy = Closure.DELEGATE_FIRST
applyScript.delegate = it
applyScript('java-project', '1.0')
applyScript('maven', '1.0')
}
The error message:
* What went wrong:
A problem occurred evaluating root project 'telescope-master'.
> Cannot get property 'dir' on null object
gradle.properties file
classes.dir = WebContent/WEB-INF/classes
webContent.dir = WebContent
template.dir = hdm/template
javascript.dir = hdm/function
javascript4.0.2.dir = hdm/function/4.0.2
datamodel.dir = hdm/datamodel
certificate.dir = certificate
build.gradle file
Properties extFile = new Properties()
extFile.load(new FileInputStream('gradle.properties'))
task FirmwareMatch(type: Zip) {
from ("${extFile.javascript.dir}")
include 'factoryResetOnFirmwareMatch.*'
archiveName 'factoryResetOnFirmwareMatch.zip'
destinationDir file('dist/hdm/function')
}
So basically if I remove the "." from .dir on both files it would work. But is there any way to over ride it?
Also how can I display actual date when using ${TODAY} in gradle.
So your problematic expression is:
extFile.javascript.dir
If we break that into how Groovy will interpret it:
extFile.getProperty('javascript').getProperty('dir')
You want Groovy to interpret it as:
extFile.getProperty('javascript.dir')
Besides directly calling getProperty, here are a couple Groovy options:
extFile.'javascript.dir'
extFile['javascript.dir']
Additionally, assuming your gradle.properties file is either in your project root (generally as a sibling to the build.gradle) or in your GRADLE_HOME directory (i.e. ~/.gradle/gradle.properties) it will be automatically loaded by Gradle and all properties available as project properties.
So you can remove all of your properties parsing code and just do the following:
project.getProperty('javascript.dir')
// or
project.'javascript.dir'
// or
project['javascript.dir']
If you want to protect against those properties not being set, and are on Gradle 2.13 or higher, you can use findProperty instead of getProperty which will return null instead of throwing an exception.
is there a better way to declare multiple packages (e.g. 'appcompat-v7') from the same group (e.g. 'com.android.support') with the same version (e.g. '23.4.0')?
actual declaration:
...
def androidSupport = '23.4.0'
def rxBinding = '0.4.0'
dependencies {
...
// android support
compile "com.android.support:appcompat-v7:$androidSupport"
compile "com.android.support:design:$androidSupport"
compile "com.android.support:percent:$androidSupport"
// rxJava
compile "com.jakewharton.rxbinding:rxbinding:$rxBinding"
compile "com.jakewharton.rxbinding:rxbinding-support-v4:$rxBinding"
compile "com.jakewharton.rxbinding:rxbinding-appcompat-v7:$rxBinding"
compile "com.jakewharton.rxbinding:rxbinding-design:$rxBinding"
compile "com.jakewharton.rxbinding:rxbinding-recyclerview-v7:$rxBinding"
...
is it possible to do something like that?:
...
compile(group: 'com.android.support', version: '23.4.0') {
modules: "appcompat-v7", "design", "percent"
}
...
Once you realize that a Gradle build script is just a Groovy script, which means that each of those "compile" lines are just method calls, you start to see many possibilities.
For instance, specify an "inline" array of artifact names, call "each()" on that, and pass a closure that specifies "compile group:$it:$version" (or something like that).
def multiArtifactDependency = { String group, String version, List<String> artifacts -> artifacts.each { compile "${group}:${it}:${version}" } }
multiArtifactDependency('com.android.support', '23.3.0', ['appcompat-v7', 'design'])
multiArtifactDependency('com.squareup.retrofit2', '2.0.2', ['retrofit', 'converter-gson', 'adapter-rxjava'])