【问题标题】:Writing gradle plugin with nested extension objects使用嵌套扩展对象编写 gradle 插件
【发布时间】:2013-07-13 03:12:11
【问题描述】:

我正在开发一个与 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 成为一个列表来接近这一点,但是当我尝试从该类中获取一个属性时,它似乎返回一个动态属性而不是值。这是下面的入门插件:

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

【问题讨论】:

    标签: plugins gradle


    【解决方案1】:

    一些提示:

    • 无需为region 添加autoScaling 扩展,因为AsgardRegion 类已经具有autoScaling 属性。您只需要初始化该属性,或许还需要添加一个void autoScaling(Closure closure) { project.configure(autoScaling, closure) } 便利方法来支持autoScaling { ... } 语法。

    • project.container 创建一个NamedDomainObjectContainer。这个容器的文字语法是someName { ... }; otherName { ... }。没有“普通列表”语法。

    • 您的测试代码为不具有这些属性的autoScaling 容器 设置了devPhase 等。这就是您收到 动态属性 警告的原因。最里面的{ ... } 是一个块(不是闭包),是多余的。

    要解决列表问题,请为AsgardAutoScaling 定义name 属性并使用常规NamedDomainObjectContainer 文字语法,或者不使用NamedDomainObjectContainer 并实现自己的语法。例如,您可以在接受闭包的AsgardRegion 上声明autoScaling 方法,创建AsgardAutoScaling 的实例,并将其添加到列表中。

    【讨论】:

    • 感谢您的提示!我想我有一些工作,并且对如何转换我想要编码的语法有了更好的理解。
    • 我参加聚会有点晚了,但是您如何在配置方法中访问项目对象以创建容器?
    【解决方案2】:

    上一个答案对我解决问题有很大帮助。我想将嵌套扩展对象添加到 build.gradle 文件中。像这样

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

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

    【讨论】:

      猜你喜欢
      • 2021-02-19
      • 1970-01-01
      • 2012-09-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多