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の参照を返すメソッドについてはスレーブで実行してもファイルパスはマスターのものとなり、 実際にスレーブでビルドが動いても、ファイルはマスタのサーバに出力されるようになっています。 こうみると、ワークスペースはスレーブにも存在するが、ビルドのディレクトリはマスターにしか存在しないってことになりますね。。スレーブで処理されてワークスペースになんかを出力した場合、それはスレーブに出力されるので、スレーブのワークスペースからビルドディレクトリにコピーする必要がありそうです。 この記事は 現在のアクセス:2591 |