Cannot assign reason to dependency - gradle

I try to add a reason to a dependency like:
implementation("foo:bar:0.1.0") { reason = "test" }
But get an error, stating that "val cannot be reassigned".
I can't find the source I got this from, but from my memory this was the way. What am I doing wrong?

Based on the example at https://docs.gradle.org/current/userguide/declaring_dependencies.html#sec:documenting-dependencies it looks like it should be
implementation("foo:bar:0.1.0") { because("test") }

Related

Configuring a custom Gradle sourceSet using a closure

I'm trying to develop a Gradle plugin for a language I use (SystemVerilog). I'm still experimenting and figuring things out. Before I write the entire thing as a plugin, I thought it would be best to try out the different parts I need inside a build script, to get a feel of how things should work.
I'm trying to define a container of source sets, similar to how the Java plugin does it. I'd like to be able to use a closure when configuring a source set. Concretely, I'd like to be able to do the following:
sourceSets {
main {
sv {
include '*.sv'
}
}
}
I defined my own sourceSet class:
class SourceSet implements Named {
final String name
final ObjectFactory objectFactory
#Inject
SourceSet(String name, ObjectFactory objectFactory) {
this.name = name
this.objectFactory = objectFactory
}
SourceDirectorySet getSv() {
SourceDirectorySet sv = objectFactory.sourceDirectorySet('sv',
'SystemVerilog source')
sv.srcDir("src/${name}/sv")
return sv
}
SourceDirectorySet sv(#Nullable Closure configureClosure) {
configure(configureClosure, getSv());
return this;
}
}
I'm using org.gradle.api.file.SourceDirectorySet because that already implements PatternFilterable, so it should give me access to include, exclude, etc.
If I understand the concept correctly, the sv(#Nullable Closure configureClosure) method is the one that gives me the ability to write sv { ... } to configure via a closure.
To add the sourceSets property to the project, I did the following:
project.extensions.add("sourceSets",
project.objects.domainObjectContainer(SourceSet.class))
As per the Gradle docs, this should give me the possibility to configure sourceSets using a closure. This site, which details using custom types, states that by using NamedDomainObjectContainer, Gradle will provide a DSL that build scripts can use to define and configure elements. This would be the sourceSets { ... } part. This should also be the sourceSets { main { ... } } part.
If I create a sourceSet for main and use it in a task, then everything works fine:
project.sourceSets.create('main')
task compile(type: Task) {
println 'Compiling source files'
println project.sourceSets.main.sv.files
}
If I try to configure the main source set to only include files with the .sv extension, then I get an error:
sourceSets {
main {
sv {
include '*.sv'
}
}
}
I get the following error:
No signature of method: build_47mnuak4y5k86udjcp7v5dkwm.sourceSets() is applicable for argument types: (build_47mnuak4y5k86udjcp7v5dkwm$_run_closure1) values: [build_47mnuak4y5k86udjcp7v5dkwm$_run_closure1#effb286]
I don't know what I'm doing wrong. I'm sure it's just a simple thing that I'm forgetting. Does anyone have an idea of what that might be?
I figured out what was going wrong. It was a combination of poor copy/paste skills and the fact that Groovy is a dynamic language.
First, let's look at the definition of the sv(Closure) function again:
SourceDirectorySet sv(#Nullable Closure configureClosure) {
configure(configureClosure, getSv());
return this;
}
Once I moved this code to an own Groovy file and used the IDE to show me what is getting called, I noticed that it wasn't calling the function I expected. I was expecting a call to org.gradle.util.ConfigureUtil.configure. Since this is part of the public API, I expected it to be imported by default in the build script. As this page states, this is not the case.
To solve the issue, it's enough to add the following import:
import static org.gradle.util.ConfigureUtil.configure
This will get rid of the cryptic closure related error. It is replaced by the following error, though:
Cannot cast object 'SourceSet_Decorated#a6abab9' with class 'SourceSet_Decorated' to class 'org.gradle.api.file.SourceDirectorySet'
This is caused by the copy/paste error I mentioned. When I wrote the SourceSet class, I drew heavily from org.gradle.api.tasks.SourceSet (and org.gradle.api.internal.tasks.DefaultSourceSet). If we look at the java(Closure) method there, we'll see it has the following signature:
SourceSet java(#Nullable Closure configureClosure);
Notice that it returns SourceSet and not SourceDirectorySet like in my code. Using the proper return type fixes the issue:
SourceSet sv(#Nullable Closure configureClosure)
With this new return type, let's look again at the configuration code for the source set:
sourceSets {
main {
sv {
include '*.sv'
}
}
}
Initially, I thought it was supposed to work as follows: pass main { ... } as a Closure to sourceSets, pass sv { ... } as a Closure to main, and handle the include ... part inside sourceDirectorySet. I banged my head against the wall for a while, because I couldn't find any code in that class hierarchy that takes closures like this.
Now, I think the flow is slightly different: pass main { ... } as a Closure to sourceSets (as initially thought), but call the sv(Closure) function on main (of type sourceSet), passing it { include ... } as the argument.
Bonus: There was one more issue that wasn't related to the "compile" errors I was having.
Even after getting the code to run without errors, it still wasn't behaving as expected. I had some files with the *.svh extension that were still getting picked up. This is because, when calling getSv(), it was creating a new SourceDirectorySet each time. Any configuration that was done previously was getting thrown away each time that this function was called.
Making the sourceDirectorySet a class member and moving its creation to the constructor fixed the issue:
private SourceDirectorySet sv
SourceSet(String name, ObjectFactory objectFactory) {
// ...
sv = objectFactory.sourceDirectorySet('sv',
'SystemVerilog source')
sv.srcDir("src/${name}/sv")
}
SourceDirectorySet getSv() {
return sv
}

Gradle reject snapshot if not explicitly requested

I am using gradle with dynamic versioning , i.e. something like this
dependencies {
compile("myGroup:myModule:1.9.+")
}
I would like to reject any SNAPSHOT canidates, such that the above example would match 1.9.1 but would reject 1.9.2-SNAPSHOT, except for the case that somebody explicitly required it.
So far, we worked with something like
resolutionStrategy.componentSelection {
all { ComponentSelection selection ->
if (selection.candidate.version.endsWith("-SNAPSHOT")){
selection.reject("Rejecting changing version (SNAPSHOT)'")
}
}
}
This rejects all canididates ending in SNAPSHOT.
I learned that one can also access requested version using something like this
resolutionStrategy.eachDependency { details ->
if (details.requested.version.endsWith("-SNAPSHOT")) {
...
}
}
Is there a way to combine the two into something like this?
if (selection.candidate.version.endsWith("-SNAPSHOT") && ! details.requested.version.endsWith("-SNAPSHOT")) {
selection.reject("Rejecting changing version (SNAPSHOT)'")
}

Accessing dependent jars during evaluation/configuration stage

I am trying to extract a resource from a dependent jar file but it seems that I am missing something regarding the time when this code is evaluated.
I would like to do the following:
distributions {
main {
contents {
into("etc") {
from zipTree(configurations.runtime.filter { it.name.startsWith('myLib') }.singleFile)
include "logback.xml"
}
}
}
}
However on this I get:
A problem occurred evaluating script.
Expected configuration ':runtime' to contain exactly one file, however, it contains no files
Can this section be delayed to execution?
I doubt it is related to the execution order. The line
configurations.runtime.filter { it.name.startsWith('myLib') }
is not returning any results. Maybe you should try configurations.runtime.files.filter ....

How can I use a block to change the execution context in ruby?

I'm creating a factory for an account object and I'm setting the name like this:
name { "#{Faker::Hacker.ingverb} #{Faker::Hacker.adjective} #{Faker::Hacker.noun}" }
Is there a way to use a block to change the execution context to eliminate the redundant Faker::Hacker calls? I'd like to end up with something like this:
name { Faker::Hacker { "#{ingverb} #{adjective} #{noun}" } }
Thanks!
It looks like you are sending methods to a class/module, so your example may be simply rewritten with use of Module#class_eval method:
name { Faker::Hacker.class_eval { "#{ingverb} #{adjective} #{noun}" } }
would invoke methods in the block passed to class_eval on Faker::Hacker class.
Not a total solution according to your problem, but a lot less to type:
h = Faker::Hacker
name { "#{h.ingverb} #{h.adjective} #{h.noun}" }

Namespaces and modules in the Swift language

I've been experimenting with Swift on my way home from WWDC. One of the most compelling new features of Swift, in my opinion, was namespacing. I haven't managed to get it to work as I expected it should though. Please see the attached screenshot and let me know if you have an idea of what I'm doing wrong.
EDIT: I have of course tried to remove the import statement.
Turns out that this is a known bug: https://devforums.apple.com/message/976286#976286
I am sorry, if I search for "namespace" or "namespacing" in the Swift-eBook there are no results. Maybe you can give me a link to an additional resource?
I would solve your problem simply with a struct and static functions.
ClassA
struct ClassA {
static func localize() {
println("Localized String")
}
}
ClassB
You can drop the import and execute the ClassA-function as follows:
ClassA.localize()
The second way
In your case you can also just make an extension of String like so:
extension String {
func localize() -> String {
return self+"-localized"
}
}
println("Test".localize()) // prints "Test-localized"

Resources