Skip to content

Instantly share code, notes, and snippets.

@martinda
Last active June 3, 2016 13:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save martinda/5c46f0da471a446c61cbeac8ef1180e6 to your computer and use it in GitHub Desktop.
Save martinda/5c46f0da471a446c61cbeac8ef1180e6 to your computer and use it in GitHub Desktop.
Cannot access binary.args, why?
@Managed interface JuiceComponent extends GeneralComponentSpec { }
@Managed interface FruitLanguage extends LanguageSourceSet {}
@Managed
interface JuiceBinarySpec extends BinarySpec {
List<String> getArgs()
void setArgs(List<String> args)
}
class JuicerTask extends SourceTask {
@Input
List<String> args
@TaskAction
void makeJuice() {
println('Juicy args: '+args)
}
}
class Juicer extends DefaultTask {
List<String> args
}
class JuicerRules extends RuleSource {
@ComponentType void registerComponent(TypeBuilder<JuiceComponent> builder) { }
@ComponentType void registerFruitLanguage(TypeBuilder<FruitLanguage> builder) { }
@ComponentType void registerJuiceBinarySpec(TypeBuilder<JuiceBinarySpec> builder) { }
@ComponentBinaries
void generateJuiceBinaries(ModelMap<JuiceBinarySpec> binaries, GeneralComponentSpec component) {
binaries.create("builtinJuicer");
}
@BinaryTasks
void generateTasks(ModelMap<Task> tasks, final JuiceBinarySpec binary) {
// Skip the internal built-in binary, this avoid the non-mutable exception
if (binary.name == "builtinJuicer") return
tasks.create("${binary.name}Juicer", Juicer) { task ->
task.args = binary.getArgs()
}
}
}
apply plugin: JuicerRules
model {
components {
juiceComponent(JuiceComponent) {
binaries {
// Describe the distributions
source(JuiceBinarySpec) {
args = ['a', 'b']
}
}
sources {
// Describe the sources
juice(FruitLanguage) {
source {
srcDirs 'src/main/fruit'
}
}
}
}
}
}
@martinda
Copy link
Author

martinda commented May 5, 2016

Change the creation rule source(JuiceBinarySpec) to a mutation rule: juicer
And change the task creation to tasks.create("${binary.name}Juicer", JuicerTask).
Then it "works".

@martinda
Copy link
Author

martinda commented Jun 3, 2016

This is discussed on the gradle forums.

The final answer is that the the @BinaryTasks generateTask(...) method was being called TWICE. It is called a FIRST time for the binary defined internally:

@ComponentBinaries
void generateJuiceBinaries(ModelMap<JuiceBinarySpec> binaries, GeneralComponentSpec component) {
    binaries.create("builtinJuicer");
}

And it is being called a SECOND time for by the binary defined in the DSL:

model {
    components {
        juiceComponent(JuiceComponent) {
            binaries {
                source(JuiceBinarySpec) { // Called due to this line
...

So to avoid the non-mutable exception, the generateTask(...) method has to skip over the internal binary:

@BinaryTasks
void generateTasks(ModelMap<Task> tasks, final JuiceBinarySpec binary) {
    if (binary.name == "builtinJuicer") return
    tasks.create("${binary.name}Juicer", Juicer) { task ->
        task.args = binary.getArgs()
    }
}

It still feels strange to have an exception thrown when a non-mutable is only being read (reading it should not change it).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment