まめ - たんたんめん

備忘録 C# / WPF 多め

(C#)gitのブランチ情報をアプリに埋め込むツールを作った

こんにちは、gitのブランチ情報をApplicationに埋め込むツールを作成しました。
ビルド前イベントに今回紹介するツールを仕込むことで仕込むみます。
f:id:at12k313:20180428135927p:plain

こうすることでビルド直前のソースコードにブランチ情報とコミットハッシュを静的な値として入れることができます。

ツール事態はC#で作りましたが、C++でも問題なく使用できます。
f:id:at12k313:20180428135535p:plain

プロジェクトに今回作ったツールとテンプレートファイルを入れておきます。
f:id:at12k313:20180428140312p:plain
f:id:at12k313:20180428140353p:plain


ツールのソースコードを載せておきます。

エントリポイント

    public class Program
    {
        public static void Main(string[] args)
        {
            var inputFile  = string.Empty;
            var outputFile = string.Empty;

            if (args.Length == 0)
            {
                Console.WriteLine("入力が不正です。置換するファイルを指定してください。");
                return ;
            }

            if (args.Length >= 1)
            {
                if (File.Exists(args[0]))
                {
                    inputFile = args[0];
                }
                else
                {
                    Console.WriteLine("入力が不正です。置換するファイルを指定してください。");
                    return;
                }
            }

            if (args.Length >= 2)
            {
                outputFile = args[1];
            }

            var gitSystem = new GitSystem();
            var replaceSystem = new ReplaceSystem();
            replaceSystem.Register("$Branch",gitSystem.GetBranch());
            replaceSystem.Register("$CommitHash", gitSystem.GetCommitHash());
            replaceSystem.ExecuteReplacement(inputFile,outputFile);
        }
    }

gitから情報を取得する部分

public class GitSystem
    {
        //! 環境変数のPathが通ってる場合は fileパスはいらない
        internal string ExeFilePath { get; set; } = "git";

        public GitSystem()
        {
            Initialize();
        }

        internal void Initialize()
        {
            //! 基本はどちらかにgit.exeがある。
            const string x86Bin = @"C:\Program Files (x86)\Git\bin\git.exe";
            const string x64Bin = @"C:\Program Files\Git\bin\git.exe";

            //! ソースツリーでgitをインストールした人は以下のパスに格納されいるケースがあったので対応
            var sourceTreeBin = Environment.ExpandEnvironmentVariables(@"%USERPROFILE%\AppData\Local\Atlassian\SourceTree\git_local\bin\git.exe");

            if (File.Exists(x86Bin))
                ExeFilePath = x86Bin;

            else if (File.Exists(x64Bin))
                ExeFilePath = x64Bin;

            else if (File.Exists(sourceTreeBin))
                ExeFilePath = sourceTreeBin;
        }

        public string ExecuteCommand(string args)
        {
            try
            {
                using (var process = new Process())
                {
                    process.StartInfo.FileName = ExeFilePath;
                    process.StartInfo.Arguments = args;
                    process.StartInfo.RedirectStandardOutput = true;
                    process.StartInfo.UseShellExecute = false;
                    process.StartInfo.StandardOutputEncoding = Encoding.UTF8;

                    if (process.Start())
                    {
                        return process.StandardOutput.ReadToEnd().Trim();
                    }
                }
            }
            catch (Exception)
            {
                // ignored
            }
            return "Unknown";
        }

        public string GetBranch()
        {
            return ExecuteCommand("rev-parse --abbrev-ref HEAD");
        }

        public string GetCommitHash()
        {
            return ExecuteCommand("rev-parse HEAD");
        }
    }

ソースコードにgitの情報を埋め込む

    public class ReplaceSystem
    {
        private Dictionary<string,string> ReplaceMap { get; set; } = new Dictionary<string, string>();

        public void Register( string key ,string name )
        {
            ReplaceMap.Add(key,name);
        }

        public void ExecuteReplacement(string input, string output = "")
        {
            if (output == string.Empty)
            {
                if (input.EndsWith(".template"))
                {
                    output = input.Replace(".template", "");
                }
                else
                {
                    output = $"{input}.replace";
                }
            }
            else if (output == input)
            {
                output = $"{input}.replace";
            }

            string buffer;
            Encoding encoding;
            {
                using (var reader = new StreamReader(input))
                {
                    buffer = reader.ReadToEnd();
                    encoding = reader.CurrentEncoding;
                }

                buffer = ReplaceMap.Aggregate(buffer, (current, pair) => current.Replace(pair.Key, pair.Value));
            }
            using (var writer = new StreamWriter(output, false, encoding))
            {
                writer.Write(buffer);
            }
        }
    }

githubでも公開しています。
github.com