LoginSignup
0
0

More than 1 year has passed since last update.

GitHub Actionsで、Windows上でもBazelの出力をキャッシュする

Last updated at Posted at 2022-07-05

意外と情報がない(Remote Cachingを除く)のでメモ。
Linux上ではキャッシュを有効にしているものの、Windows上では1時間以上かけてビルドしているプロジェクトがままある(ただし、キャッシュを有効にすれば速くなるとも言えないので、意図的かもしれない)。

Linuxでの例

setup-bazeliskのページに書かれている通りで、キャッシュディレクトリをそのまま @actions/cache でキャッシュすれば良い。
https://github.com/bazelbuild/setup-bazelisk#usage

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      ...
      - name: Mount bazel cache
        uses: actions/cache@v3
        with:
          path: "~/.cache/bazel"
          key: bazel-v1-cache

Windowsでの問題の所在

ところが、Windowsだと上記の方法でうまく行かない。

jobs:
  build:
    runs-on: windows-latest
    steps:
      # ...
      - name: Mount bazel cache
        uses: actions/cache@v3
        with:
          path: C:\_bzl
          key: bazel-v1-cache
      - run: |
          bazel --output_user_root=C:\_bzl build ..

output_user_rootC:\_bzl だとして、pathC:\_bzl を指定すると、以下のようにキャッシュ作成処理(Post Mount bazel cache)に失敗する。

Post job cleanup.
C:\Windows\System32\tar.exe --posix -z -cf cache.tgz --exclude cache.tgz -P -C D:/a/repository/repository --files-from manifest.txt
tar.exe: Couldn't open C:/_bzl/l2nyujfy/java.log.fv-az455-530.runneradmin.log.java.20220701-105515.2912: Permission denied
tar.exe: Error exit delayed from previous errors.
Warning: Tar failed with error: The process 'C:\Windows\System32\tar.exe' failed with exit code 1

Job自体はエラーにならないものの、キャッシュがアップロードされていないので、次の実行時にもキャッシュが見つかることはない。

 Cache not found for input keys: bazel-v1-cache

これを解決する方法として、MSYS2でインストールされているGNUのtarを使う方法がある。

jobs:
  build:
    runs-on: windows-latest
    steps:
      # ...

      # Restoreする前に実行しないと、Keyがヒットしているにもかかわらず、Cache not foundになるので注意
      - run: echo "C:\msys64\usr\bin" >> $env:GITHUB_PATH

      - name: Mount bazel cache
        uses: actions/cache@v3
        with:
          path: C:\_bzl
          key: bazel-v1-cache
      - run: |
          bazel --output_user_root=C:\_bzl build ..

GNUのtarを使うと、キャッシュの作成・アップロードに成功するようになる。

Post job cleanup.
C:\msys64\usr\bin\tar.exe --posix --use-compress-program "zstd -T0" -cf cache.tzst --exclude cache.tzst -P -C D:/a/repository/repository --files-from manifest.txt --force-local
Cache Size: ~1833 MB (1922026652 B)
Cache saved successfully
Cache saved with key: bazel-v1-cache

しかし、次の実行時、キャッシュのリストアに失敗してしまう(Jobの実行自体はエラーにならない。後ほど、bazel buildが失敗する可能性はあるが……)。

/usr/bin/tar: C\:/_bzl/l2nyujfy/external/androidsdk/ndk-bundle: Cannot create symlink to '/c/Android/android-sdk/ndk-bundle': Permission denied
/usr/bin/tar: C\:/_bzl/l2nyujfy/external/llvm-raw/libcxx/test/std/pstl: Cannot create symlink to '/c/_bzl/l2nyujfy/external/llvm-raw/pstl/test/std': No such file or directory
/usr/bin/tar: C:/_bzl/l2nyujfy/external/local_config_cc/windows_cc_toolchain_config.bzl: time stamp 2032-06-29 04:38:53.9788293 is 315262677.9849176 s in the future
/usr/bin/tar: Exiting with failure status due to previous errors
Warning: Tar failed with error: The process 'C:\msys64\usr\bin\tar.exe' failed with exit code 2

解決策

本質的には、read権限があるはずのファイルでなぜか発生する Permission denied (tar.exe: Couldn't open C:/_bzl/l2nyujfy/java.log.fv-az455-530.runneradmin.log.java.20220701-105515.2912: Permission denied) と、symlinkに関する問題の2つを解決する必要がある。

実は、前者の問題は、 bazel shutdown するだけで解決する(Bazelがlogファイルを開いているのが原因と思われる)。
後者のsymlinkは bazel が実行時に自動で作成するので、キャッシュ対象から外しておけば十分。

なお、bazeliskを使う場合は、bazeliskのキャッシュ自体も保存しておく必要がある。

jobs:
  build:
    runs-on: windows-2019
    steps:
      # ...

      # bazeliskがダウンロードしてくる `bazel.exe` をキャッシュする
      - name: Mount bazelisk cache
        uses: actions/cache@v3
        with:
          path: C:\Users\runneradmin\AppData\Local\bazelisk
          key: windows-bazelisk

      - name: Mount bazel cache
        uses: actions/cache@v3
        with:
          path: C:\_bzl
          key: bazel-v1-cache

      - run: |
          bazel --output_user_root=C:\_bzl build ..
          bazel --output_user_root=C:\_bzl shutdown
        shell: cmd

      # symlinkは `C:\_bzl\*\install` の1つ。これを削除しておく。
      # 端的に、actions/cacheのpathで除外しても良いはず。
      - run: |
          (Get-Item C:\_bzl\*\install).Delete()

注意

弊プロジェクトだと、キャッシュなしのビルドに1時間程かかり、その間、キャッシュ対象が9GBまで膨れ上がり、tarにしてアップロードするのに40分前後かかります……(つまり、初回実行にかかる時間が、60分->100分に増える)。
キャッシュありだとビルドは瞬間的に終わりますが、キャッシュには保存期限があるので、頻繁に実行するのでなければキャッシュを有効にする意味はないです。

ただ、個人プロジェクトで、たまにしか作業しない時も、ブランチ切ってpushしてから作業に入れば、作業内容をpushした時にキャッシュが生きていて嬉しいかも。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0