Jenkinsの抽象化されたjava.io.Fileである FilePath? †ビルドのジョブが動くノード*1によって、ワークスペースのパスは異なっていたりします。なのでJenkinsのファイルシステムはjava.io.Fileに似た FilePath?というパスが抽象化されたクラスを使用します。以下サンプルコード。 @Override
public boolean perform(AbstractBuild build, Launcher launcher,
BuildListener listener) throws InterruptedException, IOException {
FilePath root = build.getModuleRoot(); // ワークスペースのルート.スレーブでビルドが動くと、他サーバのディレクトリだったりする。
FilePath fromFile = new FilePath(root, "from.txt");
System.out.println(fromFile);
FilePath toFile = new FilePath(new FilePath(build.getRootDir()),
"to.txt"); // ココはビルドのルートで、必ずMasterサーバ上にある
System.out.println(toFile);
fromFile.copyTo(toFile); // こんな感じにノード間でコピーできる。
// (このビルドがスレーブで動く場合、スレーブのワークスペースのファイルが、マスターサーバにコピーされたりする。)
return true;
}
このように動いているサーバを抽象化し、ノード間のコピーもシームレスにできたりします。便利ですね。。 実行結果は [省略]/workspace/hoge/work/jobs/Test/workspace/from.txt [省略]/workspace/hoge/work/jobs/Test/builds/2015-09-25_13-12-45/to.txt となります。これはマスタで動いてしまいましたが、一行目はワークスペースなので場合によっては別ノードのパスになります。逆に二行目はビルドパスなので必ずマスターサーバのパスになります。 ファイル出力すると †プラグインからファイルを出力したいときがありますが、たとえば File file = new File("/tmp/fullpath.txt");
file.createNewFile();
などと書くと、ファイルの書き出し先は、マスターサーバの上記のディレクトリになります。 そのビルドがスレーブで実行されていても、です。これを、スレーブで実行されたらファイルはスレーブに書き出したいケースでは、先のFilePath?と FileCallable?インタフェースを使用します。 ファイルシステムを抽象化した仕組みである FilePath? クラスですが、これは FilePath moduleRoot = build.getModuleRoot(); ←そのプロジェクトのWorkSpaceのRoot などとして参照を得ることができますが、ここにはそのプロジェクトが実行されたときのワークスペースへのパスが格納されています。 マスターで実行したときとスレーブで実行したときに違う値が格納されているというわけですね。。 FileCallable?インタフェースは 環境に応じたFileクラスへの参照を持っていて、そのインタフェース経由でファイル操作を行うことができる仕組みです。 実際にファイル出力するサンプルプログラムを作ってみました。FileCallable?インタフェースの public String[] invoke(File f, VirtualChannel channel); メソッドに渡されてくる引数 f がFilePath?が指している場所への参照になっているわけですね。。 サンプルコード †サンプルコード: FilePath moduleRoot = build.getModuleRoot();
File rootDir = build.getRootDir();
FilePath rootDirPath = new FilePath(rootDir);
FilePath workspace = build.getWorkspace();
File artifactsDir = build.getArtifactsDir();
FilePath artifactsDirPath = new FilePath(artifactsDir);
listener.getLogger().println(moduleRoot);
listener.getLogger().println(rootDir);
listener.getLogger().println(rootDirPath);
listener.getLogger().println(workspace);
listener.getLogger().println(artifactsDir);
listener.getLogger().println(artifactsDirPath);
try {
// Fileを返すメソッドなので、マスターのディレクトリと予測
File file = new File(build.getRootDir(), "buildDir.txt");
listener.getLogger().println(file.getAbsolutePath());
file.createNewFile();
// おなじくFileを操作しているので、マスターのディレクトリと予測
File file2 = new File("/tmp/fullpath.txt");
listener.getLogger().println(file2.getAbsolutePath());
file2.createNewFile();
moduleRoot = build.getModuleRoot();
String[] result = moduleRoot.act(new F());
listener.getLogger().println(result[0]);
listener.getLogger().println(result[1]);
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
private static class F implements FileCallable<String[]> {
private static final long serialVersionUID = 1L;
public String[] invoke(File f, VirtualChannel channel)
throws IOException, InterruptedException {
File file = new File(f, "root.txt"); // f はFilePathから生成されるので場合によってスレーブのパスとなると予測
file.createNewFile();
File file2 = new File("/tmp/fullpath2.txt"); // このメソッド内はスレーブのパスになると予測
file2.createNewFile();
return new String[] { file.getAbsolutePath(),
file2.getAbsolutePath() };
}
}
について、マスターとスレーブで実行した結果は以下のようになります。 マスター: Started by user anonymous Building on master in workspace /var/lib/jenkins/workspace/Test3 /var/lib/jenkins/workspace/Test3/var/lib/jenkins/workspace/Test3 /var/lib/jenkins/jobs/Test3/builds/5 /var/lib/jenkins/jobs/Test3/builds/5 /var/lib/jenkins/workspace/Test3 /var/lib/jenkins/jobs/Test3/builds/5/archive /var/lib/jenkins/jobs/Test3/builds/5/archive /var/lib/jenkins/jobs/Test3/builds/5/buildDir.txt /tmp/fullpath.txt /var/lib/jenkins/workspace/Test3/root.txt /tmp/fullpath2.txt Finished: SUCCESS スレーブ: Started by user anonymous Building remotely on www (Linux) in workspace /opt/jenkins/workspace/Test3 /opt/jenkins/workspace/Test3/opt/jenkins/workspace/Test3 <- slave /var/lib/jenkins/jobs/Test3/builds/4 /var/lib/jenkins/jobs/Test3/builds/4 /opt/jenkins/workspace/Test3 <- slave /var/lib/jenkins/jobs/Test3/builds/4/archive /var/lib/jenkins/jobs/Test3/builds/4/archive /var/lib/jenkins/jobs/Test3/builds/4/buildDir.txt <- slaveで実行されたがマスタに出力 /tmp/fullpath.txt <- slaveで実行されたがマスタに出力 /opt/jenkins/workspace/Test3/root.txt <- slaveに出力 /tmp/fullpath2.txt <- slaveに出力 Finished: SUCCESS このようにFileの参照を返すメソッドについてはスレーブで実行してもファイルパスはマスターのものとなり、 実際にスレーブでビルドが動いても、ファイルはマスタのサーバに出力されるようになっています。 こうみると、ワークスペースはスレーブにも存在するが、ビルドのディレクトリはマスターにしか存在しないってことになりますね。。スレーブで処理されてワークスペースになんかを出力した場合、それはスレーブに出力されるので、スレーブのワークスペースからビルドディレクトリにコピーする必要がありそうです。 この記事は 現在のアクセス:2934 |