How to use a dependency as file object? - gradle

Is there an elegant way to use a specific dependency as a file object (cast dependency to file object).
It is often needed to pass a file as an argument to a task/ant task etc.
I helped me with
configurations.myDependency.files.iterator().next()
But this looks not very intuitive.

I think you mean configuration not dependency. Assuming you have something like:
configurations{
myConf
}
dependencies{
myConf 'mydep:mydep:1.0'
}
Then, if you are confident there is going to be only one file in all of your dependencies for myConf then you can do configurations.myConf.singleFile (return type is File).
However, since configuration can contain multiple files, in order to make your code more robust you should iterate over all files in configurations.myConf.files (return type is Set<File>).
If you need to extract specific dependency jar from a configuration you can do something like:
configurations.myConf.files { dep -> dep.name == 'mydep' }
where dep is of type Dependency and the return type is Set<File>.
For more details see Configuration javadoc.

Related

How to create a build.gradle file that allows me to debug into my dependency

I've got a kotlin module that takes in a core dependency. I also own that dependency. I'm unique in that I own this dependency, and everyone else in my company just uses this dependency. I'd like to make a build.gradle file that will allow me to open the user module in intellij, but allow me to debug all the way down into the dependency I own. Nobody else needs to do this, so I can't just change things so they affect everybody. But I still feel there's a way I can stick both projects into one folder and have an extra build.gradle file in that parent folder that will only work for me.
Let me try and outline how I would like things to look
Module that everyone uses = MOD_A
Module that is a dependency but only I use it = MOD_B
Parent folder:
|> private build.gradle.kts file that only I use
|> MOD_A:
|> build.gradle
|> MOD_B:
|> build.gradle
How do I achieve this?
Stretch goal: how would I create gradle tasks in MOD_B that automatically become available in MOD_A?
I did try and create my own build.gradle.kts file in the parent folder, and pointed intellij at that. This did not work :(
plugins {
id("application")
}
dependencies {
implementation("MOD_A")
implementation("MOD_B")
}
I don't use IntelliJ, but this is how I would do it in general. (It works for NetBeans.)
On your system edit the settings.gradle file to add the "owned" module as an included build. You could also use a property to have this done dynamically, so the settings file can be the same for everyone, but your user gradle.properties file will define a property to enable this. See https://docs.gradle.org/current/userguide/composite_builds.html
This will automatically cause the dependency to come from your own local build and you should be able to step into the code.
e.g. settings.gradle
if (System.getProperty('USE_LOCAL_MOD_A') != null) {
includeBuild '../MOD_A'
}
then in ~/.gradle/gradle.properties you can add
systemProp.USE_LOCAL_MOD_A=true

Gradle: Project dependencies from file

I'm fairly new to Gradle, and am enamored by its task-driven approach and customizability. So I have a question that hopefully helps me understand how to do something beyond the basics.
Suppose I have a simple text file that contains information about a project's dependencies. For example, something like
- dependency1
from: 'foobar'
version: '1'
- dependency2
from: 'foobaz'
version: '1'
Note that these are not I have some code that would, from this file, generate a file along the lines as follows:
compile 'commons-lang:commons-lang 2.6'
testCompile 'org.spockframework:spock-core:1.1-groovy-2.4'
Is there a way to configure my project so that my project's dependencies are taken from this file (not exclusively)?
Do note that the text file is also used to generate other artifacts that are used by other tasks (for example, a file to be added to a Docker container), so while it may be possible to, say, declare the dependencies normally and generate the text file instead, it is not a trivial process to do so at this time.
Yes, you can write your own groovy function that parses the file and creates a List. Then you can pass this map to the dependencies closures:
List<String> compileLibraries() {
// ... parse yaml and return list
}
dependencies {
compile compileLibraries()
}
Also, to use a yaml-parsing library, consider setting up a custom gradle subproject in the special buildSrc subfolder and writing your helper function there.
See this old post for more details: https://discuss.gradle.org/t/programmatically-adding-dependencies/7575/12
And here for buildSrc projects:
https://docs.gradle.org/current/userguide/organizing_build_logic.html#sec:build_sources

What is the difference between the configuration.files and configuration.copy methods in Gradle?

In Gradle User Guide Chapter 23. Dependency Management , an example show the difference between Configuration.copy and Configuration.files method :
build.gradle
task copyVsFiles << {
configurations.sealife.copyRecursive { dep -> dep.name == 'orca' }
.each { file -> println file.name }
println()
configurations.sealife.files { dep -> dep.name == 'orca' }
.each { file -> println file.name }
}
Output of gradle -q copyVsFiles
> gradle -q copyVsFiles
orca-1.0.jar
seal-1.0.jar
orca-1.0.jar
seal-2.0.jar
the below explanation confused me. I still don't know the difference. Can anyone help me with this ?
The answer to your question is in the paragraph just after example 23.24 in the Gradle API documentation Chapter 23 Section 24.
Note how the configurations.files method returns version 2 of the seal jar.
In the example above, orca has a dependency on seal-1.0 whereas shark
has a dependency onseal-2.0. The original configuration has therefore
a version conflict which is resolved to the newer seal-2.0 version.
The files method therefore returns seal-2.0 as a transitive dependency
of orca. The copied configuration only has orca as a dependency and
therefore there is no version conflict and seal-1.0 is returned as a
transitive dependency.
To really understand why this happens spend some time looking at the Configuration method in the Gradle docs.
Files does the following:
Resolves this configuration. This locates and downloads the files
which make up this configuration. But only the resulting set of files
belonging to the subset of dependencies specified by the
dependencySpec is returned.
Copy does the following:
Creates a copy of this configuration that only contains the
dependencies directly in this configuration (without contributions
from superconfigurations). The new configuration will be in the
UNRESOLVED state, but will retain all other attributes of this
configuration except superconfigurations. Configuration.getHierarchy()
for the copy will not include any superconfigurations.
How does this apply to the documentation example? Configuration.files resolves the configuration which, as shown by the output in the example, handles the version conflict introduced by shark which depends on seal-2.0.jar. Configuration.copy creates a copy of the configuration and is not yet resolved meaning it does not yet have a version conflict.

Gradle file rename causes circular dependency error - Why?

I want to store an input file in a JAR created with a subclass of the Jar task in Gradle. The input file shall be stored under a different name.
Here is my build.gradle (complete working example; just create dir1/file1.txt first):
task myjar(type: MyJarTask);
class MyJarTask extends Jar {
#InputFile
File file1 = new File('dir1/file1.txt');
public MyJarTask() {
configure {
baseName 'foo'
from {
file1;
// comment out the next line to eliminate the error:
rename { String fileName -> fileName.replace('file1.txt', 'file2.txt'); }
}
}
}
}
Running this via gradle myjar gives the following error:
* What went wrong:
Circular dependency between the following tasks:
:myjar
\--- :myjar (*)
(*) - details omitted (listed previously)
When I comment out the line with the rename, everything works! (Of course the file is not renamed.)
What is the reason for this surprising behavior? Are we witnessing a Gradle bug?
Please do not suggest alternative solutions; I solved the original problem by avoiding the need for the rename. But I would like to learn; I feel I am missing something important.
I got an answer on the Gradle forum by Sterling Greene of Gradleware. Basically, the cause of the circular dependency is this (in my own words):
Closures always return the last value, so the from {} closure returns the value of rename. Incidentally, rename returns a reference to the task itself (why it would do that, I don't know, but that's what its docs say). So the task itself is added to its list of things to copy, and we have a circular dependency.
The solution would be to modify the closure slightly:
from(file1) {
//file1;
rename { String fileName -> fileName.replace('file1.txt', 'file2.txt'); }
}
This runs with no problems, because it uses an overloaded variant of the from() method which always adds the given file to the list of things to copy, not the result of the closure. All in all, that's not exactly intuitive, but there it is.
Well i also got same error I thought error was due to renaming of files but in my case error was due to dual dependency on module(:backend)and java library dependency on android module(:app) I got it sorted by following steps:
Press Ctrl+Shift+Alt+S or Go to File->Project Structure this will open project Structure Dialog box.
On left side PANEL ,under modules section choose java library (e.g jjLibrary) there was two compile dependency :app and :backend just have to remove both of these dependencies.As :backend already have compile dependency on java library and :app is android module which cannot have dependency on java library.Press Ok.
Save and Sync gradle files ..
And the error has gone..Hope this helps!!!Cheers

Including a second jar file that's not a dependency into a fat onejar

I have a project that only builds the fat onejar file for testing purposes. Thus, there's a separate testing class that I don't want as a dependency to the main source, but I do want it included into the onejar. Odd scenario, I know.
I'm using the com.smokejumperit.gradle.OneJarPlugin plugin (source here), and clearly it gets the list of files to include in the onejar here:
project.task('oneJar', dependsOn:[project.tasks.jar, project.tasks.typedefOneJar]) {
...
inputs.files([jar.outputs.files, project.configurations.getByName("compile"), project.configurations.getByName("runtime")])
jar.output.files is used for publishing, so I don't want a this second jar file being published, and the two project.configurations would define dependencies for the main source jar, and I don't want this second jar to be a dependency of that either.
This second jar file is built with a task:
task integrationJar(type: Jar) {
from sourceSets.integrationTest.output
classifier = 'integration'
}
... so I can access the resulting FileCollection via integrationJar.outputs.files. If there was a clear way to add that to oneJar.input.files, I'd be golden, but I can't figure out how to do that. I've tried something like this:
oneJar {
dependsOn 'integrationJar'
println integrationJar.outputs.files.getAsPath()
inputs.files.add(integrationJar.outputs.files)
println inputs.files.getAsPath()
}
... but the result for the last print is still missing the integration jar file.
Ideas?
I'm not familiar with the implementation of that plugin, but I'd be surprised if inputs.files determined what gets included. (Usually, inputs is just consumed by Gradle's up-to-date check.) I recommend to try the gradle-one-jar plugin, which appears to be more flexible.

Resources