最近GitBucketでTomcatにデプロイするとエラーになるというレポートがあり、調べていたのですが、
どうやらwar内のファイルのタイムスタンプが負の値になっており、warの展開時にその値をファイルの更新日時として設定しようとしてエラーになっているようで、sbt 1.4.0での以下の修正が原因であるらしいことがわかりました。
以下のような感じで環境変数SOURCE_DATE_EPOCH
で明示的にタイムスタンプを設定するようにすれば回避できます。
envVars := Map(
"SOURCE_DATE_EPOCH" -> System.currentTimeMillis().toString
)
GitBucketではsbt-ioのAPIを直接使用して、warファイルをいったん展開して内容を変更してからwarファイルを作り直すということを行っているのですが、その際に引数でタイムスタンプを指定することもできます。
IO jar (
sources = contentMappings.map { case (file, path) => (file, path.toString) },
outputJar = outputFile,
manifest = manifestFile,
time = Some(System.currentTimeMillis())
)
とりあえずはこれで問題を回避できたのですが、なんでこんな動きをするのか不思議だったのでもう少し詳しく調べてみました。
sbt 1.4.0以降では前述の修正により、package
タスクでjarファイルやwarファイル*1を作成する際にデフォルトでが各エントリのタイムスタンプに0を設定するようになっているのですが、sbt-io側の以下のタイムゾーン調整*2により、タイムゾーンによってはセットする値が負の値になってしまっているようです。
さらにJDKのZipEntry
のコードを見ると、どうやらzipファイルの各エントリはxdostime
という値に加えてextraフィールドにmtime
というミリ秒単位のタイムスタンプを持っており、xdostime
の方には想定通りの値(= 0)がセットされるものの、mtime
の方には負の値がセットされてしまうようです。
というわけで最終的にsbtに以下のプルリクエストを送ってマージしていただきました。
修正は1行だけですし、実際にこれが原因で困るというケースはほとんどないような気もするのですが、原因を調べるのがなかなか大変だったので記事を書いてみました。*3