Jenkins插件无法访问slave上的文件

Sté*_*ert 5 java slave jenkins jenkins-plugins

通过我自己的插件,我需要知道Jenkins slave的工作区中是否存在文件.但是文件无法找到,而它确实存在于slave(D:\workspace\JOB_NAME\test.txt)上.

public class MyBuilder extends Builder implements Serializable {

    private static final long serialVersionUID = 1L;

    public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) 
            throws InterruptedException, IOException {

        FilePath fp = new FilePath(build.getWorkspace(), "test.txt");

        String result = fp.act(new FileCallable<String>() {
            private static final long serialVersionUID = 1L;

            @Override
            public String invoke(File file, VirtualChannel channel) throws IOException, InterruptedException {
                if (file.getAbsoluteFile().exists()){
                    return file.getName() + " exists.";
                } else {
                    return file.getName() + " doesn't exist.";
                }
            }
        });

        System.out.println("result: " + result);
Run Code Online (Sandbox Code Playgroud)

结果:

FATAL: remote file operation failed: D:\workspace\JOB_NAME\test.txt at hudson.remoting.Channel@182752b:Slave
hudson.util.IOException2: remote file operation failed: D:\workspace\JOB_NAME\test.txt at hudson.remoting.Channel@182752b:Slave
    at hudson.FilePath.act(FilePath.java:900)
    at hudson.FilePath.act(FilePath.java:877)
    at com.company.tlb.proj.MyBuilder.perform(Unknown Source)
    at hudson.tasks.BuildStepMonitor$1.perform(BuildStepMonitor.java:19)
    at hudson.model.AbstractBuild$AbstractBuildExecution.perform(AbstractBuild.java:804)
    at hudson.model.Build$BuildExecution.build(Build.java:199)
    at hudson.model.Build$BuildExecution.doRun(Build.java:160)
    at hudson.model.AbstractBuild$AbstractBuildExecution.run(AbstractBuild.java:586)
    at hudson.model.Run.execute(Run.java:1575)
    at hudson.model.FreeStyleBuild.run(FreeStyleBuild.java:46)
    at hudson.model.ResourceController.execute(ResourceController.java:88)
    at hudson.model.Executor.run(Executor.java:237)
Caused by: java.io.IOException: Unable to serialize hudson.FilePath$FileCallableWrapper@18b91cb
    at hudson.remoting.UserRequest.serialize(UserRequest.java:166)
    at hudson.remoting.UserRequest.<init>(UserRequest.java:62)
    at hudson.remoting.Channel.call(Channel.java:671)
    at hudson.FilePath.act(FilePath.java:893)
    ... 11 more
Caused by: java.io.NotSerializableException: java.io.PrintStream
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1164)
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1518)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1483)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1400)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1158)
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1518)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1483)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1400)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1158)
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1518)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1483)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1400)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1158)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:330)
    at hudson.remoting.UserRequest._serialize(UserRequest.java:155)
    at hudson.remoting.UserRequest.serialize(UserRequest.java:164)
    ... 14 more
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?

链接:

Dan*_*yMo 10

您正在传递一个匿名内部类,act(...)该内部类具有对其父类的隐式引用MyBuilder.我的猜测是,即使是MyBuilderimplements Serializable,它实际上也不能被序列化,因为有些引用不是另一个对象Serializable(例如,java.io.PrintStream如堆栈跟踪所示).

使您FileCallable<String>的静态内部类的实例摆脱对其父级的隐式引用:

private static class MyFileCallable implements FileCallable<String> {
  private static final long serialVersionUID = 1L;
  @Override
  public String invoke(File file, VirtualChannel channel) throws IOException, InterruptedException {
    if (file.getAbsoluteFile().exists()){
      return file.getName() + " exists.";
    } else {
      return file.getName() + " doesn't exist.";
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

然后使用它:

String result = fp.act(new MyFileCallable());
Run Code Online (Sandbox Code Playgroud)

更新: 这是Java的嵌套类教程的链接,该教程概述了内部类的实例与其封闭的外部类实例之间的关系:

InnerClass的实例只能存在于OuterClass的实例中,并且可以直接访问其封闭实例的方法和字段.

在JLS(第8.1.3节内部类和封闭实例)中更多技术术语也对此进行了解释.

考虑到这一点,该Serializable文档的引用解释了您遇到的原因NotSerializableException:

遍历图形时,可能会遇到不支持Serializable接口的对象.在这种情况下,将抛出NotSerializableException,并将标识非可序列化对象的类.