Gradle模型规则:如何在模型范围中创建/依赖任务

时间:2017-01-24 23:34:57

标签: gradle

我正在尝试使用"基于规则的模型配置中描述的概念" docs,我找不到做我需要的路径。

我正在使用ruleSourcePluginEach示例代码开始,但我需要能够为每个FileItem和/或DirectoryItem创建一个命名任务并将其依赖于某个地方。

基本上我需要做这样的事情:

@Managed interface Item extends Named {}
@Managed interface FileItem extends Item {}
@Managed interface DirectoryItem extends Item {
    ModelMap<Item> getChildren()
}

class PluginRules extends RuleSource {
    @Rules void ApplyRulesForDirectory(DirectoryRules rules, @Each DirectoryItem directory)  {}
}
apply plugin: PluginRules

abstract class DirectoryRules extends RuleSource {
    @Mutate
    void CreateTaskForFiles(ModelMap<Task> tasks, ModelMap<FileItem> children) {
        children.each {
            tasks.create(it.name, Task) {
                // ...
            }
        }
    }
}

model {
    root(DirectoryItem) {
        children {
            dir(DirectoryItem) {
                children {
                    file1(FileItem)
                    file2(FileItem)
                }
            }
            file3(FileItem)
        }
    }
}

但是,在gradle 3.3中运行它会失败:

The following model rules could not be applied due to unbound inputs and/or subjects:

DirectoryRules#CreateTaskForFiles(ModelMap<Task>, ModelMap<FileItem>)
  subject:
    - <no path> ModelMap<Task> (parameter 1) [*]
        scope: root
  inputs:
    - <no path> ModelMap<FileItem> (parameter 2) [*]

[*] - indicates that a model item could not be found for the path or type.

任何想法如何实现这一目标?

干杯,谢谢你的时间!

1 个答案:

答案 0 :(得分:0)

就我对Gradle基于规则的模型的有限知识所知,您的配置存在两个问题:

  1. 由于DirectoryRules规则适用于范围(即未作为插件应用于模型的根目录),您需要为其提供所需的所有模型元素进入。你没有给它ModelMap<Task> tasks,所以这是第一个问题。一个潜在的解决方案是:

    class PluginRules extends RuleSource {
        @Rules
        void ApplyRulesForDirectory(DirectoryRules rules,
                ModelMap<Task> tasks, @Each DirectoryItem directory)  {}
    }
    

    然而,这揭示了第二个问题......

  2. 看起来Gradle的@Each注释只能用于规则的目标(即被修改的东西),而你试图在它上面使用它规则的输入之一(目标是ModelMap<Task> tasks)。我不知道为什么这个限制适用于@Each;大概是与检测到匹配模型对象的时间/方式有关。

  3. 如果不确切知道自己要实现的目标,很难提出理想或惯用的解决方案。然而,天真地,这似乎有效:

    @Managed interface Item extends Named {}
    @Managed interface FileItem extends Item {}
    @Managed interface DirectoryItem extends Item {
        ModelMap<Item> getChildren()
    }
    
    class PluginRules extends RuleSource {
        @Mutate
        void CreateTasksForFiles(ModelMap<Task> tasks, @Path("root") DirectoryItem directory) {
            directory.children.withType(FileItem).each {
                tasks.create(it.name, Task) {
                    // ...
                }
            }
            directory.children.withType(DirectoryItem).each {
                ApplyRulesForDirectory(tasks, it)
            }
        }
    }
    apply plugin: PluginRules
    
    model {
        root(DirectoryItem) {
            children {
                dir(DirectoryItem) {
                    children {
                        file1(FileItem)
                        file2(FileItem)
                    }
                }
                file3(FileItem)
            }
        }
    }