【问题标题】:Groovy Nested Closures - how to pass a hash?Groovy 嵌套闭包 - 如何传递哈希?
【发布时间】:2019-02-03 16:13:57
【问题描述】:

我想为我的 Jenkins 构建加载一个闭包,但将一些变量传递给它,这些变量对于我们系统上正在进行的任何类型的构建(Go、Java、Docker)都是通用的。由于我从一个单独的 groovy 文件加载特定的闭包,它看不到这些变量。为了制作一个更简单的示例,我已将负载注释掉并包含该闭包。

我有点不确定如何执行此操作 - 如何将配置从 buildProject 传递到 buildSpecificProject?我是不是指错了?

#!/usr/bin/groovy

//def buildSpecificProject = load 'buildSpecificProject.groovy'

def buildSpecificProject = {  body->  

   def config = [:]
   body.resolveStrategy = Closure.DELEGATE_FIRST
   body.delegate = config
   body()

   println config.name
   println config.builddirectory
}

def buildProject = { projbody -> 
   def config = [:]
   projbody.resolveStrategy = Closure.DELEGATE_FIRST
   projbody.delegate = config
   projbody()

   config.builddirectory = "/bar"

   return config
}

try {
    def newProjectVersion =  buildSpecificProject { body ->
      buildProject { projbody ->
         name = 'projectname'
         versionPrefix = "4.2.0"
         fetchFromURL = 'git@github.com:myorg/myproject.git'
      }
    }
    println "New Project Version = ${newProjectVersion}\n"
} catch (err) {
    println err
}

【问题讨论】:

    标签: jenkins groovy closures


    【解决方案1】:

    我真的没有在 Jenkins 中构建脚本的经验,所以也许我的回答不适用,但从 Groovy 的角度来看,情况如下:

    buildSpecificProject 中的 config 变量是一个局部变量,您无法访问它本身,除非您公开它或其值。现在,您实际上是通过设置委托来做到这一点的。

    如果我们说 buildProject 仅在给定给 buildSpecificProject 的块中调用,那么给定给 buildProject 的块是嵌套在给定给 buildSpecificProject 的闭包中的闭包。这个闭包对象将有一个属性所有者,在这种情况下它将引用封闭的闭包实例(参见http://groovy-lang.org/closures.html#_owner_of_a_closure)。其中我们知道它已将配置设置为委托,因此您可以通过 projbody.owner.delegate 访问由 buildSpecificProject 设置的配置。

    但实际上我会考虑做这样的事情:

    def buildSpecificProject = {  body ->  
      def config = [:]
      body.resolveStrategy = Closure.DELEGATE_FIRST
      body.delegate = [config: config]  // expose config
      body()
    
      println config.name
      println config.builddirectory
      return config
    }
    
    def buildProject = { config, projbody -> 
       projbody()
       config.builddirectory = "/bar"
    }
    
    try {
        def newProjectVersion =  buildSpecificProject { body ->
          // make config accessible to buildProject by providing it as parameter
          buildProject(config) { projbody ->  
             config.name = 'projectname'
             config.versionPrefix = "4.2.0"
             config.fetchFromURL = 'git@github.com:myorg/myproject.git'
          }
        }
        println "New Project Version = ${newProjectVersion}\n"
    } catch (err) {
        println err
    }
    

    正如您所见,实际上 buildSpecificProject 设置委托就足够了,我将委托设置为一个带有一个名为 config 的键的映射,其中包含实际配置。缺点当然是,你现在必须做 config.name。还要注意调用“buildProject(config) { projbody ->”,它将配置提供给 buildProject。当然,我们可以将这两种想法结合起来:

    def buildSpecificProject = {  body ->  
      def config = [:]
      body.resolveStrategy = Closure.DELEGATE_FIRST
      body.delegate = config
      body()
    
      println config.name
      println config.builddirectory
      return config
    }
    
    def buildProject = { config, projbody ->
       projbody()
       config.builddirectory = "/bar"
    }
    
    try {
        def newProjectVersion =  buildSpecificProject {
          buildProject(delegate) { projbody ->
             name = 'projectname'
             versionPrefix = "4.2.0"
             fetchFromURL = 'git@github.com:myorg/myproject.git'
          }
        }
        println "New Project Version = ${newProjectVersion}\n"
    } catch (err) {
        println err
    }
    

    但我不建议这样做,因为我不喜欢以这种方式依赖委托。我太容易坏了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-08
      • 1970-01-01
      • 2017-04-16
      • 2013-04-30
      • 2015-04-16
      相关资源
      最近更新 更多