// Copyright (c) 2014, Thomas Goyne // // Permission to use, copy, modify, and distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice appear in all copies. // // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. // // Aegisub Project http://www.aegisub.org/ using LibGit2Sharp; using System; using System.IO; using System.Linq; using System.Text.RegularExpressions; namespace BuildTasks { public class GitVersion : Microsoft.Build.Utilities.Task { public string Root { get; set; } private static ObjectId LastSVNCommit = new ObjectId("16cd907fe7482cb54a7374cd28b8501f138116be"); private const string versionHTemplate = @"#define BUILD_GIT_VERSION_NUMBER {0} #define BUILD_GIT_VERSION_STRING ""{1}"" #define TAGGED_RELEASE {2} #define INSTALLER_VERSION ""{3}"" #define RESOURCE_BASE_VERSION {4} "; private const string versionXmlTemplate = @" {0} {1} "; private string UniqueAbbreviation(Repository repo, string full) { for (int len = 7; len < 40; ++len) { try { repo.Lookup(full.Substring(0, len)); return full.Substring(0, len); } catch (AmbiguousSpecificationException) { continue; } } return full; } private void WriteIfChanged(string path, string template, params object[] args) { var body = string.Format(template, args).Replace("\r\n", "\n"); try { var oldBody = File.ReadAllText(path); if (body != oldBody) File.WriteAllText(path, body); } catch (IOException) { File.WriteAllText(path, body); } } public override bool Execute() { string versionHPath = Root + "build/git_version.h"; string versionXmlPath = Root + "build/git_version.xml"; if (!Directory.Exists(Root + ".git")) { if (File.Exists(versionHPath)) { Log.LogMessage("Using cached version.h"); return true; } Log.LogError("git repo not found and no cached git_version.h"); return false; } int commits = 6962; // Rev ID when we switched away from SVN string installerVersion = "0.0.0"; string resourceVersion = "0, 0, 0"; string versionStr = null; bool taggedRelease = false; using (var repo = new Repository(Root + ".git")) { commits += repo.Commits.TakeWhile(c => !c.Id.Equals(LastSVNCommit)).Count(); foreach (var tag in repo.Tags) { if (!tag.Target.Id.Equals(repo.Head.Tip.Id)) continue; taggedRelease = true; versionStr = tag.Name; if (versionStr.StartsWith("v")) versionStr = versionStr.Substring(1); if (Regex.Match(versionStr, @"(\d)\.(\d)\.(\d)").Success) { installerVersion = versionStr; resourceVersion = versionStr.Replace(".", ", "); } break; } if (versionStr == null) { string branch = repo.Head.Name ?? "(unnamed branch)"; versionStr = string.Format("{0}-{1}-{2}", commits, branch, UniqueAbbreviation(repo, repo.Head.Tip.Sha.ToString())); } } WriteIfChanged(versionHPath, versionHTemplate, commits, versionStr, taggedRelease ? "1" : "0", installerVersion, resourceVersion); WriteIfChanged(versionXmlPath, versionXmlTemplate, commits, versionStr); return true; } } }