无法在 Jenkins Pipeline 中使用 Groovy 遍历 Map
Impossibility to iterate over a Map using Groovy within Jenkins Pipeline
我们正在尝试迭代 Map
,但没有成功。我们将我们的问题简化为这个最小的例子:
def map = [
'monday': 'mon',
'tuesday': 'tue',
]
如果我们尝试迭代:
map.each{ k, v -> println "${k}:${v}" }
只输出第一个条目:monday:mon
我们知道的备选方案甚至无法进入循环:
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
。 (这可能与引发 'real' 异常时发生的异常有关,使我们无法知道发生了什么)。
我们使用最新的稳定版 jenkins (2.19.1),所有插件截至今天 (2016/10/20) 都是最新的。
是否有在 Jenkins 管道 Groovy 脚本中迭代 Map
中的元素的解决方案?
我已经有一段时间没玩这个了,但是迭代地图(和其他容器)的最好方法是使用 "classical" for 循环,或者 "for in"。参见 Bug: Mishandling of binary methods accepting Closure
对于您的具体问题,大多数(所有?)管道 DSL 命令都会添加一个序列点,我的意思是可以保存管道的状态并在以后恢复它。例如,考虑等待用户输入,即使重启也希望保持此状态。
结果是每个活动实例都必须序列化——但不幸的是,标准 Map 迭代器不可序列化。 Original Thread
我能想到的最佳解决方案是定义一个函数,将 Map 转换为可序列化的 MapEntries 列表。该函数未使用任何管道步骤,因此无需在其中序列化任何内容。
@NonCPS
def mapToList(depmap) {
def dlist = []
for (def entry2 in depmap) {
dlist.add(new java.util.AbstractMap.SimpleImmutableEntry(entry2.key, entry2.value))
}
dlist
}
这显然必须为每个要迭代的地图调用,但好处是,循环体保持不变。
for (def e in mapToList(map))
{
println "key = ${e.key}, value = ${e.value}"
}
您必须第一次批准 SimpleImmutableEntry
构造函数,或者您很可能可以通过将 mapToList 函数放在工作流库中来解决这个问题。
或者更简单
for (def key in map.keySet()) {
println "key = ${key}, value = ${map[key]}"
}
我们正在尝试迭代 Map
,但没有成功。我们将我们的问题简化为这个最小的例子:
def map = [
'monday': 'mon',
'tuesday': 'tue',
]
如果我们尝试迭代:
map.each{ k, v -> println "${k}:${v}" }
只输出第一个条目:monday:mon
我们知道的备选方案甚至无法进入循环:
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
。 (这可能与引发 'real' 异常时发生的异常有关,使我们无法知道发生了什么)。
我们使用最新的稳定版 jenkins (2.19.1),所有插件截至今天 (2016/10/20) 都是最新的。
是否有在 Jenkins 管道 Groovy 脚本中迭代 Map
中的元素的解决方案?
我已经有一段时间没玩这个了,但是迭代地图(和其他容器)的最好方法是使用 "classical" for 循环,或者 "for in"。参见 Bug: Mishandling of binary methods accepting Closure
对于您的具体问题,大多数(所有?)管道 DSL 命令都会添加一个序列点,我的意思是可以保存管道的状态并在以后恢复它。例如,考虑等待用户输入,即使重启也希望保持此状态。 结果是每个活动实例都必须序列化——但不幸的是,标准 Map 迭代器不可序列化。 Original Thread
我能想到的最佳解决方案是定义一个函数,将 Map 转换为可序列化的 MapEntries 列表。该函数未使用任何管道步骤,因此无需在其中序列化任何内容。
@NonCPS
def mapToList(depmap) {
def dlist = []
for (def entry2 in depmap) {
dlist.add(new java.util.AbstractMap.SimpleImmutableEntry(entry2.key, entry2.value))
}
dlist
}
这显然必须为每个要迭代的地图调用,但好处是,循环体保持不变。
for (def e in mapToList(map))
{
println "key = ${e.key}, value = ${e.value}"
}
您必须第一次批准 SimpleImmutableEntry
构造函数,或者您很可能可以通过将 mapToList 函数放在工作流库中来解决这个问题。
或者更简单
for (def key in map.keySet()) {
println "key = ${key}, value = ${map[key]}"
}