使用嵌套扩展对象编写gradle插件

时间:2013-07-13 03:12:12

标签: plugins gradle

我正在使用与Asgard(来自netflix)集成的gradle插件(我不知道groovy,刚开始使用gradle)。我希望我的扩展对象看起来像这样:

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 "AsgardRegion_Decorated@65087be0", value: "test".
Deprecated dynamic property: "min" on "AsgardRegion_Decorated@65087be0", value: "3".
Deprecated dynamic property: "max" on "AsgardRegion_Decorated@65087be0", value: "6".
Deprecated dynamic property: "availabilityZones" on "AsgardRegion_Decorated@65087be0", value: "[us-east-1a, us-east-1...".
Deprecated dynamic property: "ami" on "AsgardRegion_Decorated@65087be0", value: "Base AMI 2013-07-11".
Deprecated dynamic property: "instanceType" on "AsgardRegion_Decorated@65087be0", value: "m3.xlarge".
Deprecated dynamic property: "securityGroups" on "AsgardRegion_Decorated@65087be0", value: "[base, test-application]".
                devPhase
                devPhase test
                devPhase AsgardRegion_Decorated@14860315('devPhase')

BUILD SUCCESSFUL

Total time: 1.996 secs

我是否认为这一切都错了?如果不是,我如何从动态属性中获取值(尝试获取和值,但这些似乎不起作用)。

感谢您抽出时间阅读本文。

编辑基于@ 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

2 个答案:

答案 0 :(得分:6)

一些提示:

  • 无需向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的实例,并将其添加到列表中。

答案 1 :(得分:0)

之前的回答帮助我解决了我的问题。我想将嵌套扩展对象添加到build.gradle文件中。喜欢这个

family {
   father {
       firstName = "Ivan"
       lastName = "Karamazon"
   }
   children {
       son {
           firstName = "Alesha"
           lastName = "Rakitka"
       }
   }
}

最后,我能够做到并创建了示例项目。但是,要求略有不同,所以在这里分享我的经验。有关详细信息,请参阅https://stackoverflow.com/a/41491729/3223198和Github项目https://github.com/andriipanasiuk/family-gradle-plugin