变量名称包含点 (.) 的 groovy 列表将转换为字符串



我有一个 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 管道。

  1. 为什么根据名称会有所不同?
  2. 我们如何使用带有点 (.( 的变量名称定义列表?

在 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(,值是newValueString.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;
}
}

可以深入研究以了解EnvironmentExpanderCpsThread机制,但最快的方法是检查签名 -public String

这解释了 Jenkins 在管道脚本中使用env变量在幕后做了什么,以及为什么你的迭代发生在String的字符上,而不是像你想象的那样的列表。如果您创建了自己的变量并自己尝试了,您将看到例如MapEnvActionImpl类型之间的行为差异。

final myVar = [:]
myVar.list = ["abc","def"]
env.list = ["abc","def"]
echo "${myVar.list.getClass()}"
echo "${env.list.getClass()}"

最新更新