using System.Collections; using System.Diagnostics; using System.Runtime.InteropServices; using System.Security.Cryptography; namespace Facepunch; internal static class Utility { public static bool RunDotnetCommand( string workingDirectory, string arguments ) { return RunProcess( "dotnet", arguments, workingDirectory ); } /// /// Runs an external process with standard output/error redirection and logging. /// /// Path to the executable /// Command line arguments /// Working directory for the process /// If true, will pause and wait for user input after process completes /// Exit code that indicates success (default 0) /// True if the process exited with success code, false otherwise public static bool RunProcess( string executablePath, string arguments = "", string workingDirectory = null, Dictionary environmentVariables = null, int timeoutMs = 0, int successExitCode = 0, DataReceivedEventHandler onDataReceived = null ) { using Process process = new Process(); process.StartInfo.FileName = executablePath; process.StartInfo.Arguments = arguments; process.StartInfo.UseShellExecute = false; process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardError = true; process.StartInfo.CreateNoWindow = false; if ( !string.IsNullOrEmpty( workingDirectory ) ) { process.StartInfo.WorkingDirectory = Path.Combine( Directory.GetCurrentDirectory(), workingDirectory ); } // Copy environment variables from the current process foreach ( DictionaryEntry entry in Environment.GetEnvironmentVariables() ) { if ( entry.Value is null || entry.Value is not string strValue ) continue; process.StartInfo.EnvironmentVariables[(string)entry.Key] = strValue; } if ( environmentVariables != null ) { foreach ( var envVar in environmentVariables ) { process.StartInfo.EnvironmentVariables[envVar.Key] = envVar.Value; } } process.OutputDataReceived += ( sender, e ) => { if ( e.Data != null ) { if ( onDataReceived != null ) { onDataReceived( sender, e ); } else { Log.Info( e.Data ); } } }; process.ErrorDataReceived += ( sender, e ) => { if ( e.Data != null ) { Log.Error( e.Data ); } }; process.Start(); process.BeginOutputReadLine(); process.BeginErrorReadLine(); // Wait for process with optional timeout bool exited; if ( timeoutMs > 0 ) { exited = process.WaitForExit( timeoutMs ); if ( !exited ) { Log.Error( $"Process timed out after {timeoutMs}ms" ); try { process.Kill(); } catch { } return false; } } else { process.WaitForExit(); exited = true; } bool success = exited && process.ExitCode == successExitCode; if ( !success ) { Log.Error( $"Process failed with exit code: {process.ExitCode}" ); } Log.Info( "" ); return success; } /// /// Gets the version name from GitHub environment variables /// /// Version name string public static string VersionName() { var versionHash = Environment.GetEnvironmentVariable( "GITHUB_SHA" ) ?? ""; versionHash = versionHash[..Math.Min( versionHash.Length, 7 )]; var versionName = $"{DateTime.Now:yy.MM.dd}-{versionHash}"; // tagged release, prefer tag name if ( Environment.GetEnvironmentVariable( "GITHUB_REF" )?.StartsWith( "refs/tags/" ) == true ) { versionName = Environment.GetEnvironmentVariable( "GITHUB_REF_NAME" ) ?? ""; } return versionName; } public static bool IsCi() { return Environment.GetEnvironmentVariable( "GITHUB_ACTIONS" ) != null; } public static string CalculateSha256( string filePath ) { using var sha256 = SHA256.Create(); using var stream = File.OpenRead( filePath ); var hash = sha256.ComputeHash( stream ); return Convert.ToHexString( hash ).ToLowerInvariant(); } public static string FormatSize( long bytes ) { if ( bytes <= 0 ) { return "0 B"; } string[] units = { "B", "KB", "MB", "GB", "TB", "PB" }; var size = (double)bytes; var unitIndex = 0; while ( size >= 1024 && unitIndex < units.Length - 1 ) { size /= 1024; unitIndex++; } return $"{size:0.##} {units[unitIndex]}"; } }