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

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

问题描述

我们正在尝试遍历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).

我们正在使用最新的稳定的詹金斯(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列表的Function.该函数不使用任何流水线步骤,因此其中的任何内容都无需序列化.

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在地图上进行迭代的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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