无法在 Jenkins Pipeline 中使用 Groovy 迭代 Map [英] Impossibility to iterate over a Map using Groovy within Jenkins Pipeline

查看:18
本文介绍了无法在 Jenkins Pipeline 中使用 Groovy 迭代 Map的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们正在尝试迭代 Map,但没有成功.我们将问题简化为这个最小示例:

We are trying to iterate over a Map, but without any success. We reduced our issue to this minimal example:

def map = [
           'monday': 'mon',
           'tuesday': 'tue',
           ]

如果我们尝试迭代:

map.each{ k, v -> println "${k}:${v}" }

只输出第一个条目:monday:mon

我们知道的替代方案甚至无法进入循环:

The alternatives we know of are not even able to enter the loop:

for (e in map)
{
    println "key = ${e.key}, value = ${e.value}"
}

for (Map.Entry<String, String> e: map.entrySet())
{
    println "key = ${e.key}, value = ${e.value}"
}

都失败了,两者都只显示异常java.io.NotSerializableException: java.util.LinkedHashMap$Entry.(这可能与引发真正"异常时发生的异常有关,使我们无法知道发生了什么).

Are failing, both only showing the exception java.io.NotSerializableException: java.util.LinkedHashMap$Entry. (which could be related to an exception occurring while raising the 'real' exception, preventing us from knowing what happened).

我们使用最新的稳定 jenkins (2.19.1),所有插件截至今天(2016 年 10 月 20 日)都是最新的.

We are using latest stable jenkins (2.19.1) with all plugins up-to-date as of today (2016/10/20).

是否有在 Jenkins 管道 Groovy 脚本中迭代 Map 中的元素的解决方案?

Is there a solution to iterate over elements in a Map within a Jenkins pipeline Groovy script ?

推荐答案

我已经有一段时间没有玩这个了,但是遍历地图(和其他容器)的最佳方法是使用经典"的 for 循环,或者为了".参见 错误:错误处理接受闭包的二进制方法

Its been some time since I played with this, but the best way to iterate through maps (and other containers) was with "classical" for loops, or the "for in". See Bug: Mishandling of binary methods accepting Closure

对于您的具体问题,大多数(所有?)管道 DSL 命令都会添加一个序列点,我的意思是可以保存管道的状态并在以后恢复它.例如,考虑等待用户输入,您希望即使重启也能保持此状态.结果是每个实时实例都必须被序列化——但遗憾的是标准 Map 迭代器是不可序列化的.原始主题

To your specific problem, most (all?) pipeline DSL commands will add a sequence point, with that I mean its possible to save the state of the pipeline and resume it at a later time. Think of waiting for user input for example, you want to keep this state even through a restart. The result is that every live instance has to be serialized - but the standard Map iterator is unfortunately not serializable. Original Thread

我能想到的最佳解决方案是定义一个函数来将 Map 转换为可序列化 MapEntries 的列表.该函数未使用任何管道步骤,因此无需在其中进行任何可序列化.

The best solution I can come up with is defining a Function to convert a Map into a list of serializable MapEntries. The function is not using any pipeline steps, so nothing has to be serializable within it.

@NonCPS
def mapToList(depmap) {
    def dlist = []
    for (def entry2 in depmap) {
        dlist.add(new java.util.AbstractMap.SimpleImmutableEntry(entry2.key, entry2.value))
    }
    dlist
}

显然必须为要迭代的每个地图调用此方法,但好处是循环体保持不变.

This has to be obviously called for each map you want to iterate, but the upside it, that the body of the loop stays the same.

for (def e in mapToList(map))
{
    println "key = ${e.key}, value = ${e.value}"
}

您必须在第一次批准 SimpleImmutableEntry 构造函数,或者很可能您可以通过将 mapToList 函数放在工作流库中来解决这个问题.

You will have to approve the SimpleImmutableEntry constructor the first time, or quite possibly you could work around that by placing the mapToList function in the workflow library.

这篇关于无法在 Jenkins Pipeline 中使用 Groovy 迭代 Map的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆