我使用了以下Groovy代码:
// @NonCPS
def printList(params) {
def jobs = [:]
println params
params.split(",").each { param ->
println "Param: ${param}"
}
}
text = "Foo,Bar,Baz,Qux"
printList(text)
从groovy
命令调用时按预期工作:
$ groovy test.groovy
Foo,Bar,Baz,Qux
Param: Foo
Param: Bar
Param: Baz
Param: Qux
虽然在Jenkins的非沙盒作业中进行测试时,我得到了不同的结果:
[Pipeline] echo
Foo,Bar,Baz,Qux
[Pipeline] echo
Param: Foo
[Pipeline] End of Pipeline
问题是只打印了第一个项目,而不是全部。
但是,只有在使用@NonCPS
辅助方法时,代码才能在Jenkins中正常工作。
为了正确迭代项目列表,为什么需要@NonCPS
?没有使用@NonCPS
(特别是在沙盒环境中)有没有解决方法?
答案 0 :(得分:2)
我尽可能地理解CPS如何工作和实现,以及如何通过管道处理它(到目前为止没有潜入其代码),管道试图测试暂停的能力(备份) /..transfer../restore)执行(JVM)状态大多数代码指令虽然序列化接口。考虑到它是JVM< groovy<管道DSL ..为插件开发人员付出了很多努力。
接下来,我自己并不是Groovy或Java大师,尽管我能想到它的实现,但是groovy生成器(例如<a href="https://www.google.com/" target='_system'>...</a>
)与python(yield)或C / C ++生成器中的非常相似(仿函数对象)。
只要可迭代的主题迭代器(例如列表索引或yield表达式状态)是隐式的,那么到目前为止,这些都不能通过管道轻松序列化。 因此,偏好Java风格的循环。
只要执行范围显式包含循环迭代器(&#39; i&#39;索引变量),备用Java风格(经典C)循环就更容易处理。
请不要认为这是一个权威的答案,前面提到的只是我对管道CPS的个人理解
答案 1 :(得分:2)
您还可以使用其他方法来获得相同的效果。例如,以下是可序列化的,不需要@NonCPS迭代名为mylist的列表:
def output(values = None, row_num = None):
res = ""
if not row_num:
res += " " * 2
else:
res += row_num + "|"
for i in values:
res += "{:5}".format(i) #{:5} allows for filler space when string length < 5
return res
def print_overall(rnge):
print(output(rnge))
print(output(["-"*5]*len(rnge)))
for row_num in rnge:
#for every row number, make an list that maps values
#where all the column numbers are added to the current row number
lst = list(map(lambda col_num: row_num + col_num, rnge))
print(output(lst, row_num = str(row_num)))
range_start = int(input("Enter start value:"))
range_end = int(input("Enter end value:"))
input_range = range(range_start, range_end+1) #+1 because range is exclusive at endpoint
print_overall(input_range)