Java Jenkins CI插件在从机上运行
我正在为Jenkins CI开发一个插件。现在,当插件在从机上运行时,我遇到了一个问题。在从机上,我需要记录到主机,从主机传递参数并在从机上启动进程。因此,我编写了以下代码:Java Jenkins CI插件在从机上运行,java,jenkins,continuous-integration,hudson,jenkins-plugins,Java,Jenkins,Continuous Integration,Hudson,Jenkins Plugins,我正在为Jenkins CI开发一个插件。现在,当插件在从机上运行时,我遇到了一个问题。在从机上,我需要记录到主机,从主机传递参数并在从机上启动进程。因此,我编写了以下代码: private static class LauncherCallable implements FilePath.FileCallable<String> { private BuildListener listener; private SetupConfig config; private String
private static class LauncherCallable implements FilePath.FileCallable<String>
{
private BuildListener listener;
private SetupConfig config;
private String nsisVersion;
private Launcher launcher;
public LauncherCallable(BuildListener listener, SetupConfig config, String nsisVersion, Launcher launcher)
{
this.listener = listener;
this.config = config;
this.nsisVersion = nsisVersion;
this.launcher = launcher;
}
@Override
public String invoke(File file, VirtualChannel vc) throws IOException, InterruptedException
{
try
{
final RemoteOutputStream ros = new RemoteOutputStream(listener.getLogger());
ScriptGenerator scriptGenerator = new ScriptGenerator(config);
listener.getLogger().println("Downloading NSIS...");
String nsisPath = Downloader.getNsisPath(listener, nsisVersion);
listener.getLogger().println("Derteming version from AssembyInfo...");
String assemblyVersion = AssemblyVersionParser.determineVersion(new File(file + "/" + config.getAssemblyInfoPath()));
listener.getLogger().println(" -> Version: " + assemblyVersion);
listener.getLogger().println("Generating .nsi file...");
String nsiString = scriptGenerator.generateScript();
nsiString = nsiString.replace("$VERSION", assemblyVersion);
listener.getLogger().println("Checking NSIS installation...");
File nsisExecutable = new File(new File(nsisPath).getAbsolutePath() + "/makensis.exe");
if (!nsisExecutable.exists())
throw new Exception("Could not find NSIS executable: " + nsisExecutable);
listener.getLogger().println("Writing .nsi file...");
String scriptGuid = UUID.randomUUID().toString();
File scriptFile = new File(file + "/" + scriptGuid + ".nsi");
PrintStream scriptOutStream = new PrintStream(new FileOutputStream(scriptFile, false));
scriptOutStream.print(nsiString);
scriptOutStream.close();
listener.getLogger().println("Launching NSIS...");
ProcStarter ps = launcher.new ProcStarter();
ArgumentListBuilder command = new ArgumentListBuilder();
command.addTokenized(nsisExecutable.toString() + " " + scriptFile.getAbsolutePath());
ps.cmds(command); //.stdout(listener)
Proc proc = launcher.launch(ps);
int nsisReturn = proc.join();
listener.getLogger().println("NSIS returned: " + nsisReturn);
listener.getLogger().println("Deleting temp file...");
if (!scriptFile.delete())
throw new Exception("Could not delete script file " + scriptFile.getAbsolutePath() + " !");
return (nsisReturn == 0) ? "SUCCESS" : "FAIL";
} catch (Exception ex)
{
ex.printStackTrace();
ex.printStackTrace(listener.getLogger());
return "FAIL";
}
}
@Override
public void checkRoles(RoleChecker rc) throws SecurityException
{
}
}
通过这样做,我得到以下异常:
java.io.IOException: remote file operation failed: C:\\[...] at hudson.remoting.Channel@4cf8aa7c:CIAgent:
java.io.IOException: Unable to serialize hudson.FilePath$FileCallableWrapper@3b712782
at hudson.FilePath.act(FilePath.java:987)
at hudson.FilePath.act(FilePath.java:969)
at jenkinsnsis.JenkinsNsisPlugin.NsisPlugin.perform(NsisPlugin.java:136)
at hudson.tasks.BuildStepMonitor$1.perform(BuildStepMonitor.java:20)
at hudson.model.AbstractBuild$AbstractBuildExecution.perform(AbstractBuild.java:779)
at hudson.model.Build$BuildExecution.build(Build.java:205)
at hudson.model.Build$BuildExecution.doRun(Build.java:162)
at hudson.model.AbstractBuild$AbstractBuildExecution.run(AbstractBuild.java:537)
at hudson.model.Run.execute(Run.java:1741)
at hudson.model.FreeStyleBuild.run(FreeStyleBuild.java:43)
at hudson.model.ResourceController.execute(ResourceController.java:98)
at hudson.model.Executor.run(Executor.java:408)
Caused by: java.io.IOException: Unable to serialize hudson.FilePath$FileCallableWrapper@3b712782
at hudson.remoting.UserRequest.serialize(UserRequest.java:169)
at hudson.remoting.UserRequest.<init>(UserRequest.java:63)
at hudson.remoting.Channel.call(Channel.java:776)
at hudson.FilePath.act(FilePath.java:980)
... 11 more
Caused by: java.io.NotSerializableException: hudson.Launcher$RemoteLauncher
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.defaultWriteFields(Unknown Source)
...
java.io.IOException:远程文件操作失败:C:\\[…]位于hudson.remoting。Channel@4cf8aa7c:CIAgent:
java.io.IOException:无法序列化hudson.FilePath$FileCallableWrapper@3b712782
在hudson.FilePath.act(FilePath.java:987)
在hudson.FilePath.act(FilePath.java:969)
位于jenkinssis.jenkinsisplugin.NsisPlugin.perform(NsisPlugin.java:136)
在hudson.tasks.BuildStepMonitor$1.perform(BuildStepMonitor.java:20)
位于hudson.model.AbstractBuild$AbstractBuildExecution.perform(AbstractBuild.java:779)
位于hudson.model.Build$BuildExecution.Build(Build.java:205)
位于hudson.model.Build$BuildExecution.doRun(Build.java:162)
位于hudson.model.AbstractBuild$AbstractBuildExecution.run(AbstractBuild.java:537)
位于hudson.model.Run.execute(Run.java:1741)
运行(FreeStyleBuild.java:43)
在hudson.model.ResourceController.execute(ResourceController.java:98)
运行(Executor.java:408)
原因:java.io.IOException:无法序列化hudson.FilePath$FileCallableWrapper@3b712782
位于hudson.remoting.UserRequest.serialize(UserRequest.java:169)
位于hudson.remoting.UserRequest.(UserRequest.java:63)
在hudson.remoting.Channel.call(Channel.java:776)
在hudson.FilePath.act(FilePath.java:980)
…还有11个
原因:java.io.NotSerializableException:hudson.Launcher$RemoteLauncher
位于java.io.ObjectOutputStream.WriteObject 0(未知源)
位于java.io.ObjectOutputStream.defaultWriteFields(未知源)
...
我做错了什么?不幸的是,我没有发现任何使用日志和启动进程的例子。谢谢!为了将
FileCallable
对象传递到远程机器,Jenkins需要能够序列化整个对象。这意味着所有字段都需要实现java.io.Serializable
在这种情况下,我猜您的SetupConfig
类型不可序列化
如果您拥有此类型,并且可以将其标记为可序列化的并确保其所有字段都可以序列化,则应将其修复。如果这是第三方类,则可能需要在invoke
方法中构造SetupConfig
实例
编辑:现在您已经发布了完整的stacktrace,我们可以看到实际上Launcher
是无法序列化的类(java.io.NotSerializableException:hudson.Launcher$RemoteLauncher
)
您不需要将Launcher
传递给您的可调用对象-您可以像刚才一样使用ArgumentListBuilder
,但您可以使用而不是ProcStarter
来执行NSIS
(invoke
方法中的所有内容都已经存在,因此您不需要做任何特殊的事情)
例如:
ArgumentListBuilder args = ...;
ProcessBuilder proc = new ProcessBuilder(args.toList());
proc.start().waitFor();
您好。谢谢您的回复。SetupConfig是一个自定义类,对吗?我已经将Serializable添加到此类及其使用的所有其他自定义类中。@C.M.好的,如果您仍然存在问题,假设fc
是LaunchCallable
的一个实例,您可能需要显示更多无法序列化的stacktrace、 CIAgent
涉及到类吗?CIAgent是从属的名称。我已经添加了ste stack trace作为对我的初始问题的注释。已经感谢您的帮助!感谢您的回答!现在它似乎工作了!我不再收到任何可序列化的错误!太好了!;-)我现在唯一的问题是makensis.exe没有正常运行。我得到以下错误:java.io.IOException:无法运行程序“C:\Users\…\Downloads\nsis\u download\nsis-2.42\makensis.exe C:\Users\…\Downloads\workspace\nsist\5254581d-2843-4746-ac8c-06b01544b28c.nsi”:CreateProcess error=2,系统找不到指定的文件我将stacktrace编辑成问题;您可以删除注释:)
ArgumentListBuilder args = ...;
ProcessBuilder proc = new ProcessBuilder(args.toList());
proc.start().waitFor();