ビルド前イベントを活用する、その11

ビルド前イベントで、現在開発中の Git ハッシュやブランチ名を取得して、それを C# のソースコードに埋め込んでみましょう。

埋め込むソースコードのファイル名は GitInfo.cs とし、下記の内容をビルド前に動的に生成するツールを製作します。

public static class GitInfo
{
    public const string HASH    = "af7e6ffaf569f183349265fe3fd501f29a62178e";
    public const string HASH_N7 = "af7e6ff";
    public const string BRANCH  = "master";
}

ファイル生成ツールのソースコードは下記です。第一引数に「Gitコマンドを実行したいディレクトリ」、第二引数に「ファイルを配置したいディレクトリ」を指定します。

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.IO;

namespace tool
{
	internal class Program
	{

		const String FILE_NAME_OUT_CS = "GitInfo.cs";

		static int Main( string [] args )
		{

			if ( args.Length < 2  )
			{
				// ビルドしない.
				return -1;
			}

			try
			{

				String dir_work = args[0]; // Gitコマンドを実行するディレクトリ.
				String dir_out = args[1];  // ファイルを出力するディレクトリ.

				// git の長いコミットハッシュを取得する.
				List<String> ret_hash = ExecGitCommand( "rev-parse HEAD", dir_work );
				String str_hash = ret_hash[0];

				//Console.WriteLine( str_hash );

				// git の短いコミットハッシュを取得する.
				List<String> ret_hash_n7 = ExecGitCommand( "rev-parse --short HEAD", dir_work );
				String str_hash_n7 = ret_hash_n7[0];

				//Console.WriteLine( str_hash_n7 );

				// git のアクティブブランチ名を取得する.
				List<String> ret_branch = ExecGitCommand( "rev-parse --abbrev-ref HEAD", dir_work );
				String str_branch = ret_branch[0];

				//Console.WriteLine( str_branch );

				// GitInfo.cs ファイルを指定のパスに出力する.
				String fp_out = Path.Combine( dir_out, FILE_NAME_OUT_CS );
				Encoding enc = new UTF8Encoding( false );
				using ( StreamWriter sw = new StreamWriter( fp_out, false, enc ))
				{

					sw.WriteLine( $"public static class GitInfo"                           );
					sw.WriteLine( $"{{"                                                    );
					sw.WriteLine( $"    public const string HASH    = \"{str_hash}\";"     );
					sw.WriteLine( $"    public const string HASH_N7 = \"{str_hash_n7}\";"  );
					sw.WriteLine( $"    public const string BRANCH  = \"{str_branch}\";"   );
					sw.WriteLine( $"}}"                                                    );

				}

			}
			catch ( Exception excp )
			{
				// ビルドしない.
				Console.WriteLine( excp.Message );
				return -1;
			}

			// ビルドに突入する.
			return 0;

		}

		private static List<string> ExecGitCommand( string arguments, string working_directory )
		{

			ProcessStartInfo psi = new ProcessStartInfo();
			psi.FileName               = "git";
			psi.Arguments              = arguments;
			psi.WorkingDirectory       = working_directory;
			psi.RedirectStandardOutput = true;
			psi.RedirectStandardError  = true;
			psi.StandardOutputEncoding = Encoding.UTF8; // ここを指定しないと日本語は文字化けする.
			psi.StandardErrorEncoding  = Encoding.UTF8; // ここを指定しないと日本語は文字化けする.
			psi.UseShellExecute        = false;
			psi.CreateNoWindow         = true;

			List<String> output = new List<string>();

			try
			{

				using ( Process proc = Process.Start( psi ) )
				{

					while ( !proc.StandardOutput.EndOfStream )
					{
						output.Add( proc.StandardOutput.ReadLine() );
					}

					string err = proc.StandardError.ReadToEnd();
					proc.WaitForExit();

					if ( proc.ExitCode != 0 )
					{
						throw new Exception( err );
					}

				}

			}
			catch ( Exception excp )
			{
				output.Add( excp.Message );
			}

			return output;

		}
	}
}

上記のソースコードで作成された tool.exe を、現在開発中のアプリケーションのプロジェクトディレクトリに配置します。

VisualStudio のビルド前コマンドは下記のようにします。
tool.exe に二つの実行時引数を与えてください。
・第一引数は Git コマンドを実行するディレクトリ
・第二引数は GitInfo.cs を出力するディレクトリ

$(ProjectDir)tool.exe $(SolutionDir) $(ProjectDir)

生成された GitInfo.cs は下記のように使ってください。

private void button1_Click( object sender, EventArgs e )
{

	StringBuilder sb = new StringBuilder();
	sb.AppendLine( GitInfo.BRANCH );
	sb.AppendLine( GitInfo.HASH_N7 );
	sb.AppendLine( GitInfo.HASH );

    // ブランチやハッシュをメッセージボックスで表示する.
	MessageBox.Show( sb.ToString().Trim() );

}