Написание плагина gradle с вложенными объектами расширения
Я работаю над плагином gradle (я не знаю groovy и просто начал использовать gradle), который интегрируется с Asgard (из netflix). Я хочу, чтобы мой объект расширения выглядел следующим образом:
asgard {
url = "http://asgard"
regions {
"us-east-1" {
autoScaling {
{
devPhase = "test"
min = 3
max = 6
availabilityZones = ["us-east-1a", "us-east-1b", "us-east-1c"]
ami = "Base AMI 2013-07-11"
instanceType = "m3.xlarge"
securityGroups = ["base", "test-application"]
}
}
}
}
}
Или что-то близкое к этому. Мне удалось приблизиться к этому, сделав autoScaling List, но когда я пытаюсь получить свойство из этого класса, он, похоже, возвращает динамическое свойство и никогда не имеет значения. Вот приведенный ниже плагин для начинающих:
import org.gradle.internal.reflect.Instantiator
class AsgardPlugin implements Plugin<Project> {
void apply(Project project) {
project.extensions.create("asgard", AsgardPluginExtension, project)
project.asgard.extensions.regions = project.container(AsgardRegion) {String name ->
AsgardRegion region = project.gradle.services.get(Instantiator).newInstance(AsgardRegion, name)
assert region instanceof ExtensionAware
region.extensions.add("autoScaling", project.container(AsgardAutoScaling))
return region
}
project.task('displayConfigs') << {
if(project.asgard.applicationName == null) project.asgard.applicationName = project.name
println "Asgard URL $project.asgard.url"
println "Application name $project.asgard.applicationName"
println "Runs on regions..."
project.asgard.regions.each() {region ->
println "\tRegion $region.name"
println "\tAutoScaling groups..."
region.autoScaling.each() {asg ->
println "\t\tdevPhase $asg"
println "\t\tdevPhase $asg.devPhase"
println "\t\tdevPhase $asg.get('devPhase')"
}
}
}
}
}
class AsgardPluginExtension {
String url = "http://asgard.sisa.samsung.com"
String applicationName
AsgardPluginExtension(Project project) {
applicationName = project.name
}
}
class AsgardRegion {
def String name
List<AsgardAutoScaling> autoScaling
AsgardRegion(String name) { this.name = name }
}
class AsgardAutoScaling {
String devPhase
int min
int max
List<String> availabilityZones
String ami
String instanceType
String sshKey
List<String> securityGroups
}
Когда я запускаю задачу, это то, что я вижу в журналах:
$ ./gradlew displayConfigs
:displayConfigs
Asgard URL http://asgard
Application name gradle-asgard-plugin
Runs on regions...
Region us-east-1
AutoScaling groups...
Creating properties on demand (a.k.a. dynamic properties) has been deprecated and is scheduled to be removed in Gradle 2.0. Please read http://gradle.org/docs/current/dsl/org.gradle.api.plugins.ExtraPropertiesExtension.html for information on the replacement for dynamic properties.
Deprecated dynamic property: "devPhase" on "[email protected]", value: "test".
Deprecated dynamic property: "min" on "[email protected]", value: "3".
Deprecated dynamic property: "max" on "[email protected]", value: "6".
Deprecated dynamic property: "availabilityZones" on "[email protected]", value: "[us-east-1a, us-east-1...".
Deprecated dynamic property: "ami" on "[email protected]", value: "Base AMI 2013-07-11".
Deprecated dynamic property: "instanceType" on "[email protected]", value: "m3.xlarge".
Deprecated dynamic property: "securityGroups" on "[email protected]", value: "[base, test-application]".
devPhase
devPhase test
devPhase [email protected]('devPhase')
BUILD SUCCESSFUL
Total time: 1.996 secs
Неужели я все это делаю неправильно? Если нет, то как я могу получить значение из динамического свойства (попытался получить и значение, но они, похоже, не работают).
Спасибо, что прочитали это время.
Отредактировано EDIT @Обратная связь peter-niederwieser
Спасибо peter-niederwieser за ваши намеки. После принятия вашего совета и рассмотрения того, как работают закрытие, я думаю, что у меня есть лучшее понимание того, как сделать то, что я хотел попробовать.
Вот синтаксис плагина:
asgard {
url = "http://asgard"
regions {
"us-east-1" {
autoScaling {
devPhase = "test"
min = 3
max = 6
availabilityZones = ["a", "b", "c"]
ami = "Base AMI 2013-07-11"
instanceType = "m3.xlarge"
securityGroups = ["base", "test-application"]
}
autoScaling {
devPhase = "stage"
}
}
"us-west-1" {
autoScaling {
devPhase = "test"
}
autoScaling {
devPhase = "stage"
}
}
}
}
Код для поддержки этого можно найти здесь:
import org.gradle.internal.reflect.Instantiator
class AsgardPlugin implements Plugin<Project> {
void apply(Project project) {
project.extensions.create("asgard", AsgardPluginExtension, project)
project.asgard.extensions.regions = project.container(AsgardRegion) {String name ->
AsgardRegion region = project.gradle.services.get(Instantiator).newInstance(AsgardRegion, name, project)
assert region instanceof ExtensionAware
return region
}
project.task('displayConfigs') << {
if(project.asgard.applicationName == null) project.asgard.applicationName = project.name
println "Asgard URL $project.asgard.url"
println "Application name $project.asgard.applicationName"
println "Runs on regions..."
project.asgard.regions.each() {region ->
println "\tRegion $region.name"
println "\tAutoScaling groups..."
region.autoScaling.each() {asg ->
println "\t\tdevPhase $asg.devPhase"
}
}
}
}
}
class AsgardPluginExtension {
String urlgg
String applicationName
AsgardPluginExtension(Project project) {
applicationName = project.name
}
}
class AsgardRegion {
String name
Project project
List<AsgardAutoScaling> autoScaling = []
AsgardRegion(String name, Project project) {
this.name = name
this.project = project
}
void autoScaling(Closure closure) {
def asg = new AsgardAutoScaling()
project.configure(asg, closure)
autoScaling.add(asg)
}
}
class AsgardAutoScaling {
String devPhase
int min
int max
List<String> availabilityZones
String ami
String instanceType
String sshKey
List<String> securityGroups
}
Вот результат, который я вижу при запуске:
$ ./gradlew displayConfigs
:displayConfigs
Asgard URL http://asgard
Application name gradle-asgard-plugin
Runs on regions...
Region us-east-1
AutoScaling groups...
devPhase test
devPhase stage
Region us-west-1
AutoScaling groups...
devPhase test
devPhase stage
BUILD SUCCESSFUL
Total time: 1.929 secs
Ответы
Ответ 1
Некоторые подсказки:
-
Нет необходимости добавлять расширение autoScaling
к region
, потому что класс AsgardRegion
уже имеет свойство autoScaling
. Вам просто нужно инициализировать это свойство и, возможно, добавить метод void autoScaling(Closure closure) { project.configure(autoScaling, closure) }
для поддержки синтаксиса autoScaling { ... }
.
-
project.container
создает NamedDomainObjectContainer
. Литеральный синтаксис для этого контейнера someName { ... }; otherName { ... }
. Синтаксиса "простого списка" нет.
-
Тестовый код устанавливает devPhase
и т.д. для контейнера autoScaling
, который не имеет этих свойств. Вот почему вы получаете предупреждения о динамических свойствах. Самый внутренний { ... }
является блоком (а не замыканием) и является избыточным.
Чтобы решить проблему с списком, определите свойство name
для AsgardAutoScaling
и используйте регулярный синтаксис литерала NamedDomainObjectContainer
или не используйте NamedDomainObjectContainer
и реализуйте свой собственный синтаксис. Например, вы можете объявить метод autoScaling
на AsgardRegion
, который принимает закрытие, создает экземпляр AsgardAutoScaling
и добавляет его в список.
Ответ 2
Предыдущий ответ помог мне решить мою проблему. Я хотел добавить вложенные объекты расширения в файл build.gradle
. Как этот
family {
father {
firstName = "Ivan"
lastName = "Karamazon"
}
children {
son {
firstName = "Alesha"
lastName = "Rakitka"
}
}
}
Наконец, я смог сделать это и создал образец проекта. Однако требования были несколько разными, поэтому я рассказываю об этом здесь. Подробности см. В разделе "Ответ" fooobar.com/info/378322/... и проект Github https://github.com/andriipanasiuk/family-gradle-plugin