我有一个 groovy 列表,定义为
env.list = ["abc","def"]
如果我尝试在 for 循环中使用它
for (letters in env.list) {
print("Letter is $letters")
}
它将遍历每个字母并打印以下内容 -
Letter is [
Letter is "
Letter is a
.....
如果我定义列表如下 -
list = ["abc","def"]
它会将此视为列表。for 循环将打印以下内容。
Letter is abc
Letter is def
正在使用 groovy 来运行我的 Jenkins 管道。
- 为什么根据名称会有所不同?
- 我们如何使用带有点 (.( 的变量名称定义列表?
在 Jenkins 管道中,env
- 是一个保存环境变量列表的变量:
https://jenkins.io/doc/book/pipeline/jenkinsfile/#using-environment-variables
和环境变量只能容纳一个字符串
因此,当您尝试为环境变量分配列表时 - 它会自动转换为字符串
env.list = ["abc","def"]
相当于
env.list = ["abc","def"].toString()
然后你正在逐个字符迭代字符串...
要解释为什么会发生这种行为,最好求助于 Jenkins 源代码。
全局变量名称是env
这将我们带到org.jenkinsci.plugins.workflow.cps.EnvActionImpl.Binder
.这会将值绑定到脚本,在本例中为管道。
源代码:
@Override public EnvActionImpl getValue(CpsScript script) throws Exception {
Run<?,?> run = script.$build();
if (run != null) {
return EnvActionImpl.forRun(run);
} else {
throw new IllegalStateException("no associated build");
}
}
EnvActionImpl
扩展了Groovy类型GroovyObjectSupport
(源代码(。GroovyObjectSupport
在其文档中有:
一个有用的基类,用于希望成为Groovy对象的Java对象
所以,这是Jenkins允许Java实现允许它为Groovy设置它的行为。你正在使用的方法public java.lang.Object getProperty(java.lang.String property)
和public void setProperty(java.lang.String property, java.lang.Object newValue)
,所以我们将仔细研究EnvActionImpl
对它们的实现。
对于setProperty
,实现在这里:
@Override public void setProperty(String propertyName, Object newValue) {
env.put(propertyName, String.valueOf(newValue));
try {
owner.save();
} catch (IOException x) {
throw new RuntimeException(x);
}
}
在课堂上往上看,我们看到env
的宣言是private final Map<String,String> env;
。属性名称用作键(在您的示例中list
(,值是newValue
的String.valueOf
返回,在您的例子中是字符串化的["abc","def"]
。
看setProperty
:
@Override public String getProperty(String propertyName) {
try {
CpsThread t = CpsThread.current();
return EnvironmentExpander.getEffectiveEnvironment(getEnvironment(), t.getContextVariable(EnvVars.class), t.getContextVariable(EnvironmentExpander.class)).get(propertyName);
} catch (Exception x) {
LOGGER.log(Level.WARNING, null, x);
return null;
}
}
可以深入研究以了解EnvironmentExpander
和CpsThread
机制,但最快的方法是检查签名 -public String
。
这解释了 Jenkins 在管道脚本中使用env
变量在幕后做了什么,以及为什么你的迭代发生在String
的字符上,而不是像你想象的那样的列表。如果您创建了自己的变量并自己尝试了,您将看到例如Map
和EnvActionImpl
类型之间的行为差异。
final myVar = [:]
myVar.list = ["abc","def"]
env.list = ["abc","def"]
echo "${myVar.list.getClass()}"
echo "${env.list.getClass()}"