using System;
using System.ComponentModel;
using System.Diagnostics;
using Debug = UnityEngine.Debug;
namespace SingularityGroup.HotReload.Editor {
internal static class GitUtil {
///
/// Fallback is PatchServerInfo.UnknownCommitHash
///
public static string GetShortCommitHashOrFallback(int timeoutAfterMillis = 5000) {
var shortCommitHash = PatchServerInfo.UnknownCommitHash;
var commitHash = GetShortCommitHashSafe(timeoutAfterMillis);
// On MacOS GetShortCommitHash() returns 7 characters, on Windows it returns 8 characters.
// When git command produced an unexpected result, use a fallback string
if (commitHash != null && commitHash.Length >= 6) {
shortCommitHash = commitHash.Length < 8 ? commitHash : commitHash.Substring(0, 8);
}
return shortCommitHash;
}
// only log exception once per domain reload, to prevent spamming the console
private static bool loggedExceptionInGetShortCommitHashSafe = false;
///
/// Get the git commit hash, returning null if it takes too long.
///
///
///
///
/// This method is 'better safe than sorry' because we must not break the user's build.
/// It is better to not know the commit hash than to fail the build.
///
private static string GetShortCommitHashSafe(int timeoutAfterMillis) {
Process process = null;
// Note: don't use ReadToEndAsync because waiting on that task blocks forever.
try {
process = StartGitCommand("log", " -n 1 --pretty=format:%h");
var stdout = process.StandardOutput;
if (process.WaitForExit(timeoutAfterMillis)) {
return stdout.ReadToEnd();
} else {
// In a git repo with git lfs, git log can be blocked by waiting for switch branches / download lfs objects
// For that reason I disabled this warning log until a better solution is implemented (e.g. cache the commit and use cached if timeout).
// Log.Warning(
// $"[{CodePatcher.TAG}] Timed out trying to get the git commit hash, HotReload will not warn you about" +
// " a build connecting to a server running on a different commit (which is not supported)");
return null;
}
} catch (Win32Exception ex) {
if (ex.NativeErrorCode == 2) {
// git not found, ignore because user doesn't use git for version control
return null;
} else if (!loggedExceptionInGetShortCommitHashSafe) {
loggedExceptionInGetShortCommitHashSafe = true;
Debug.LogException(ex);
}
} catch (Exception ex) {
if (!loggedExceptionInGetShortCommitHashSafe) {
loggedExceptionInGetShortCommitHashSafe = true;
Log.Exception(ex);
}
} finally {
if (process != null) {
process.Dispose();
}
}
return null;
}
static Process StartGitCommand(string command, string arguments, Action modifySettings = null) {
var startInfo = new ProcessStartInfo("git", command + " " + arguments) {
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true,
};
if (modifySettings != null) {
modifySettings(startInfo);
}
return Process.Start(startInfo);
}
}
}