Windows で Unity のビルドログを標準出力に出す

Last updated 5 months ago

Unity のコマンドラインビルドは、Windows 以外の環境では -logFile を無引数で与えることでログが標準出力に出てきます。しかし、Windows の環境ではなぜか対応していません。そのため、ログを tail -f して標準出力にリダイレクトするツールを作りました。

ログの上では失敗になっているのに、Exit Code が 0 になる場合への簡易的な対応も入れてあります。

使い方

Unity.exe <args>

と書くところを

UnityBuildLogRedirector.exe Unity.exe <args>

と書くだけです。

コード

適当に C# のソリューションを作って以下のコードを突っ込んでビルドしてください。

UnityBuildLogRedirector.cs
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
namespace UnityBuildLogRedirector
{
class Program
{
const int MaxLogFileDetectionTrial = 1000;
const int LogFileDetectionIntervalMs = 100;
const int LogReadingIntervalMs = 100;
static void Main(string[] args)
{
if (args.Any(a => a.ToLower() == "-logfile"))
{
throw new InvalidOperationException("-logFile オプションは使用しないでください");
}
if (args.All(a => a.ToLower() != "-quit"))
{
throw new InvalidOperationException("-quit オプションが必要です");
}
var unityExecutable = new FileInfo(args.First());
var logFile = new FileInfo(Path.GetTempFileName());
var unityArguments = args.Skip(1).ToList();
unityArguments.Add("-logFile");
unityArguments.Add("\"" + logFile.FullName + "\"");
var unityProcessInfo = new ProcessStartInfo()
{
FileName = unityExecutable.FullName,
Arguments = string.Join(" ", unityArguments),
CreateNoWindow = true,
UseShellExecute = false,
};
var unityProcess = Process.Start(unityProcessInfo);
try
{
var logFileDetectionTrialCount = 0;
while (!logFile.Exists || logFile.Length == 0)
{
logFileDetectionTrialCount++;
if (logFileDetectionTrialCount > MaxLogFileDetectionTrial)
{
throw new Exception("ログファイルへの書き込みが検出できませんでした");
}
Thread.Sleep(LogFileDetectionIntervalMs);
logFile.Refresh();
}
var failureDetectedByLog = false;
using (var fs = new FileStream(logFile.FullName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (var reader = new StreamReader(fs))
{
while (!unityProcess.HasExited)
{
ReadAllAndRedirectAndHandleError(reader, ref failureDetectedByLog);
Thread.Sleep(LogReadingIntervalMs);
}
ReadAllAndRedirectAndHandleError(reader, ref failureDetectedByLog);
}
if (failureDetectedByLog)
{
Environment.ExitCode = 1;
}
else
{
Environment.ExitCode = unityProcess.ExitCode;
}
}
finally
{
if (!unityProcess.HasExited)
{
Console.WriteLine("Unity のプロセスが正しく終了しませんでした");
Environment.ExitCode = 1;
unityProcess.Kill();
}
unityProcess.Dispose();
}
}
static void ReadAllAndRedirectAndHandleError(StreamReader reader, ref bool failure)
{
var output = reader.ReadToEnd();
if (output.Contains("Aborting batchmode due to failure"))
{
failure = true;
}
Console.Write(output);
}
}
}

おわりに

Jenkins で Windows 環境の Unity のビルドのログがリアルタイムに出てきてくれなくて困っていた方は是非参考にしてください!