diff --git a/BuildGeneratorEditorWindow.cs b/BuildGeneratorEditorWindow.cs index d414720..eed2917 100644 --- a/BuildGeneratorEditorWindow.cs +++ b/BuildGeneratorEditorWindow.cs @@ -1,282 +1,326 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using UnityEditor; -using UnityEngine; - -public class BuildGeneratorEditorWindow : EditorWindow -{ - private VersionDefinition versionDefinition = default; - - [MenuItem("Window/Build Generator")] - private static void ShowWindow() - { - BuildGeneratorEditorWindow window = GetWindow(); - window.titleContent = new GUIContent("Build Generator"); - - window.versionDefinition = new(PlayerSettings.bundleVersion); - - window.Show(); - } - - private void OnGUI() - { - EditorGUILayout.LabelField($"Current Version: {versionDefinition.Version}"); - EditorGUILayout.LabelField($"Build Number: {versionDefinition.BuildNumber}"); - - // EditorGUILayout.BeginHorizontal(); - // if (IncrementButton("Major", versionDefinition.IncreaseMajor())) - // ApplyVersion(versionDefinition.IncreaseMajor()); - - // if (IncrementButton("Minor", versionDefinition.IncreaseMinor())) - // ApplyVersion(versionDefinition.IncreaseMinor()); - - // if (IncrementButton("Patch", versionDefinition.IncreasePatch())) - // ApplyVersion(versionDefinition.IncreasePatch()); - - // if (IncrementButton("Release Candidate", versionDefinition.IncreaseReleaseCandidate())) - // ApplyVersion(versionDefinition.IncreaseReleaseCandidate()); - - // EditorGUILayout.EndHorizontal(); - - if (GUILayout.Button($"Evaluate Version from git")) versionDefinition = GitProcess.GetUpcomingReleaseCandidateVersion(); - EditorGUILayout.BeginHorizontal(); - if (GUILayout.Button($"Commit Release Candidate")) CommitVersion(GitProcess.GetUpcomingReleaseCandidateVersion()); - if (GUILayout.Button($"Commit Release")) CommitVersion(GitProcess.GetUpcomingReleaseVersion()); - EditorGUILayout.EndHorizontal(); - } - - private void CommitVersion(VersionDefinition versionDefinition) - { - ApplyVersion(versionDefinition); - GitProcess.Add("ProjectSettings\\ProjectSettings.asset"); - GitProcess.Add("Assets\\Settings\\Build Profiles\\**"); - GitProcess.Commit($"chore: Bump Version to {versionDefinition}"); - GitProcess.CreateVersionTag(versionDefinition); - } - - private bool IncrementButton(string fieldName, VersionDefinition resultDefinition) - { - EditorGUILayout.BeginVertical(); - - bool isButtonPressed = GUILayout.Button($"Add Incremental {fieldName}"); - EditorGUILayout.LabelField($"{versionDefinition} -> {resultDefinition}", new GUIStyle(GUI.skin.label) { alignment = TextAnchor.MiddleCenter }); - - EditorGUILayout.EndVertical(); - - return isButtonPressed && EditorUtility.DisplayDialog("Increment Confirmation", $"Are you sure to add an incremental {fieldName} version?", "Yes", "Cancel"); - } - - private void ApplyVersion(VersionDefinition versionDefinition) - { - this.versionDefinition = this.versionDefinition >= versionDefinition ? this.versionDefinition : versionDefinition; - PlayerSettings.Android.bundleVersionCode = versionDefinition.BuildNumber; - PlayerSettings.iOS.buildNumber = versionDefinition.BuildNumber.ToString(); - PlayerSettings.bundleVersion = versionDefinition.ToString(); - AssetDatabase.SaveAssets(); - } - - private struct VersionDefinition - { - public const uint MAX_VALUE = 99; - - public const uint DEFAULT_MAJOR = 0; - public const uint DEFAULT_MINOR = 0; - public const uint DEFAULT_PATCH = 0; - public const uint DEFAULT_RELEASE_CANDIDATE = 1; - public const uint RELEASE_RC_VALUE = 99; - - private readonly uint _major; - private readonly uint _minor; - private readonly uint _patch; - private readonly uint _releaseCandidate; - - public readonly uint Major => _major > MAX_VALUE ? MAX_VALUE : _major; - public readonly uint Minor => _minor > MAX_VALUE ? MAX_VALUE : _minor; - public readonly uint Patch => _patch > MAX_VALUE ? MAX_VALUE : _patch; - public readonly uint ReleaseCandidate => _releaseCandidate > MAX_VALUE ? MAX_VALUE : _releaseCandidate; - - public readonly bool IsRelease => ReleaseCandidate == RELEASE_RC_VALUE; - - public VersionDefinition(uint? major = null, uint? minor = null, uint? patch = null, uint? releaseCandidate = null) - { - _major = major ?? DEFAULT_MAJOR; - _minor = minor ?? DEFAULT_MINOR; - _patch = patch ?? DEFAULT_PATCH; - _releaseCandidate = releaseCandidate ?? DEFAULT_RELEASE_CANDIDATE; - - if (_major == 0 && _minor == 0) - _minor = 1; - } - - public VersionDefinition(string versionString) - { - if (versionString.StartsWith('v')) - versionString = versionString[1..]; - - _major = DEFAULT_MAJOR; - _minor = DEFAULT_MINOR; - _patch = DEFAULT_PATCH; - _releaseCandidate = RELEASE_RC_VALUE; - - string[] releaseCandidateVersionStrings = versionString.Split("-rc"); - string[] versionNumbers = releaseCandidateVersionStrings[0].Split('.'); - - if (versionNumbers.Length > 0 && uint.TryParse(versionNumbers[0], out uint major)) _major = major; - if (versionNumbers.Length > 1 && uint.TryParse(versionNumbers[1], out uint minor)) _minor = minor; - if (versionNumbers.Length > 2 && uint.TryParse(versionNumbers[2], out uint patch)) _patch = patch; - if (releaseCandidateVersionStrings.Length > 1 && uint.TryParse(releaseCandidateVersionStrings[1], out uint releaseCandidate)) _releaseCandidate = releaseCandidate; - - if (Major == 0 && Minor == 0) - Minor = ReleaseCandidate = 1; - } - - public readonly VersionDefinition IncreaseMajor() => new(Major + 1, DEFAULT_MINOR, DEFAULT_PATCH, DEFAULT_RELEASE_CANDIDATE); - public readonly VersionDefinition IncreaseMinor() => new(Major, Minor + 1, DEFAULT_PATCH, DEFAULT_RELEASE_CANDIDATE); - public readonly VersionDefinition IncreasePatch() => new(Major, Minor, Patch + 1, DEFAULT_RELEASE_CANDIDATE); - public readonly VersionDefinition IncreaseReleaseCandidate() => new(Major, Minor, Patch, ReleaseCandidate + 1); - public readonly VersionDefinition ToReleaseVersion() => new(Major, Minor, Patch, RELEASE_RC_VALUE); - - public readonly uint BuildNumber => uint.Parse($"{Major:00}{Minor:00}{Patch:00}{ReleaseCandidate:00}"); - - public override readonly string ToString() - { - if (IsRelease) - return $"{Major}.{Minor}.{Patch}"; - return $"{Major}.{Minor}.{Patch}-rc{ReleaseCandidate}"; - } - - public static bool operator >(VersionDefinition left, VersionDefinition right) => left.BuildNumber > right.BuildNumber; - public static bool operator <(VersionDefinition left, VersionDefinition right) => left.BuildNumber < right.BuildNumber; - public static bool operator >=(VersionDefinition left, VersionDefinition right) => left.BuildNumber >= right.BuildNumber; - public static bool operator <=(VersionDefinition left, VersionDefinition right) => left.BuildNumber <= right.BuildNumber; - public static bool operator ==(VersionDefinition left, VersionDefinition right) => left.BuildNumber == right.BuildNumber; - public static bool operator !=(VersionDefinition left, VersionDefinition right) => left.BuildNumber != right.BuildNumber; - } - - private static class GitProcess - { - public static VersionDefinition GetLatestBuildVersion() => new(GetLatestBuildVersionString()); - public static VersionDefinition GetUpcomingReleaseVersion() => GetUpcomingReleaseCandidateVersion().ToReleaseVersion(); - public static VersionDefinition GetUpcomingReleaseCandidateVersion() - { - VersionDefinition latestVersionDefinition = GetLatestBuildVersion(); - string[] commits = GetCommitsSinceLastTag(); - return ApplySemVer(latestVersionDefinition, commits); - } - - public static VersionDefinition GetVersion(string version, IList gitLogs) - => ApplySemVer(new(version), gitLogs); - - public static VersionDefinition ApplySemVer(VersionDefinition latestVersionDefinition, IList commits) - { - VersionDefinition result = latestVersionDefinition.IsRelease ? latestVersionDefinition.IncreasePatch() : latestVersionDefinition; - for (int i = commits.Count - 1; i >= 0; i--) - { - string line = commits[i]; - if (string.IsNullOrWhiteSpace(line)) - continue; - - string commitTitle = line.Length > 9 ? line[9..] : line; - if (commitTitle.StartsWith("breaking change", StringComparison.InvariantCultureIgnoreCase)) - { - result = result.IncreaseMajor(); - break; - } - - if (latestVersionDefinition.Minor != result.Minor) - continue; - - if (commitTitle.StartsWith("feat", StringComparison.OrdinalIgnoreCase)) - { - result = result.IncreaseMinor(); - continue; - } - - if (latestVersionDefinition.Patch != result.Patch) - continue; - - if (commitTitle.StartsWith("fix", StringComparison.OrdinalIgnoreCase)) - { - result = result.IncreasePatch(); - continue; - } - - if (latestVersionDefinition.ReleaseCandidate == result.ReleaseCandidate) - result = result.IncreaseReleaseCandidate(); - } - - return result; - } - - public static string GetLatestBuildVersionString() - => RunGitCommand($"describe --tags --abbrev=0"); - - public static string[] GetCommits() - => RunGitCommand("log --oneline").Replace("\r", "").Split('\n'); - - public static string[] GetCommitsSinceLastTag() - => RunGitCommand($"log {GetLatestBuildVersionString()}..HEAD --oneline").Replace("\r", "").Split('\n'); - - public static string CreateVersionTag(VersionDefinition versionDefinition) - => CreateTag($"v{versionDefinition.Version}", $"{(versionDefinition.IsRelease ? "Release" : "Build")} {versionDefinition.Version} with build number: {versionDefinition.BuildNumber}\""); - - public static string Push() - => RunGitCommand($"push"); - - public static string Add(IList files) - => RunGitCommand($"add \"{string.Join("\" \"", files)}\""); - - public static string Add(string file) - => RunGitCommand($"add \"{file}\""); - - public static string Commit(string message) - => RunGitCommand($"commit -m \"{message}\""); - - public static string PushTags() - => RunGitCommand($"tag --push"); - - public static string PushVersionTag(VersionDefinition versionDefinition) - => RunGitCommand($"push origin tag v{versionDefinition.Version}"); - - public static string CreateTag(string title, string message) - => RunGitCommand($"tag -a {title} -m \"{message}"); - - public static string Unstage(IList files) - => RunGitCommand($"reset \"{string.Join("\" \"", files)}\""); - - public static string Unstage(string file) - => RunGitCommand($"reset \"{file}\""); - - public static string Unstage() - => RunGitCommand($"reset"); - - private static string RunGitCommand(string gitArgs) - { - ProcessStartInfo processStartInfo = new() - { - FileName = "git", - Arguments = gitArgs, - RedirectStandardOutput = true, - UseShellExecute = false, - CreateNoWindow = true - }; - - try - { - Process process = Process.Start(processStartInfo); - string output = process.StandardOutput.ReadToEnd(); - if (output.EndsWith('\n')) output = output[0..^1]; - if (output.EndsWith('\r')) output = output[0..^1]; - process.WaitForExit(); - return output; - } - catch (Exception ex) - { - Console.WriteLine("An error occurred: " + ex.Message); - throw; - } - } - } -} +using System; +using System.Collections.Generic; +using System.Diagnostics; + +using UnityEditor; + +using UnityEngine; + +public class BuildGeneratorEditorWindow : EditorWindow +{ + private VersionDefinition editorVersion = default; + private VersionDefinition gitVersion = default; + + [MenuItem("Window/Build Generator")] + private static void ShowWindow() + { + BuildGeneratorEditorWindow window = GetWindow(); + window.titleContent = new GUIContent("Build Generator"); + + window.editorVersion = new(PlayerSettings.bundleVersion); + try { window.gitVersion = GitProcess.GetLatestBuildVersion(); } catch { } + + window.Show(); + } + + private void OnGUI() + { + if (GUILayout.Button($"Re-evaluate versions")) + { + editorVersion = new(PlayerSettings.bundleVersion); + gitVersion = GitProcess.GetLatestBuildVersion(); + } + + EditorGUILayout.Space(); + + EditorGUILayout.BeginHorizontal(); + + EditorGUILayout.BeginVertical(); + if (GUILayout.Button($"Create Release")) CommitVersion(GitProcess.GetUpcomingReleaseVersion()); + if (GUILayout.Button($"Create Release Candidate")) CommitVersion(GitProcess.GetUpcomingReleaseCandidateVersion()); + EditorGUILayout.EndVertical(); + + EditorGUILayout.BeginVertical(); + EditorGUILayout.LabelField($"Editor Version: {editorVersion} ({editorVersion.BuildNumber})"); + EditorGUILayout.LabelField($"Git Version: {editorVersion} ({editorVersion.BuildNumber})"); + EditorGUILayout.EndVertical(); + + EditorGUILayout.EndHorizontal(); + + EditorGUILayout.Space(); + if (GUILayout.Button($"Push All")) { GitProcess.Push(); GitProcess.PushTags(); } + + // EditorGUILayout.BeginHorizontal(); + // if (IncrementButton("Major", versionDefinition.IncreaseMajor())) + // CommitVersion(versionDefinition.IncreaseMajor()); + + // if (IncrementButton("Minor", versionDefinition.IncreaseMinor())) + // CommitVersion(versionDefinition.IncreaseMinor()); + + // if (IncrementButton("Patch", versionDefinition.IncreasePatch())) + // CommitVersion(versionDefinition.IncreasePatch()); + + // if (IncrementButton("Release Candidate", versionDefinition.IncreaseReleaseCandidate())) + // CommitVersion(versionDefinition.IncreaseReleaseCandidate()); + + // EditorGUILayout.EndHorizontal(); + } + + private void CommitVersion(VersionDefinition versionDefinition) + { + if (this.editorVersion >= versionDefinition) + { + EditorUtility.DisplayDialog( + "Release Conflict", + $"You can't create a new version because the old version({this.editorVersion}) is either higher or the same as the new version({versionDefinition}). Please make new commits to create new releases.", + "Return"); + return; + } + + if (EditorUtility.DisplayDialog( + "Release Confirmation", + $"Are you sure to commit a new incremental version of {versionDefinition}?", + "Yes", + "Cancel") + ) + return; + + ApplyVersion(versionDefinition); + GitProcess.Add("ProjectSettings\\ProjectSettings.asset"); + GitProcess.Add("Assets\\Settings\\Build Profiles\\**"); + GitProcess.Commit($"chore: Bump Version to {versionDefinition}"); + GitProcess.CreateTag(versionDefinition); + GitProcess.PushTag(versionDefinition); + } + + private bool IncrementButton(string fieldName, VersionDefinition resultDefinition) + { + EditorGUILayout.BeginVertical(); + + bool isButtonPressed = GUILayout.Button($"Add Incremental {fieldName}"); + EditorGUILayout.LabelField($"{editorVersion} -> {resultDefinition}", new GUIStyle(GUI.skin.label) { alignment = TextAnchor.MiddleCenter }); + + EditorGUILayout.EndVertical(); + + return isButtonPressed && EditorUtility.DisplayDialog("Increment Confirmation", $"Are you sure to add an incremental {fieldName} version?", "Yes", "Cancel"); + } + + private void ApplyVersion(VersionDefinition versionDefinition) + { + this.editorVersion = versionDefinition; + PlayerSettings.Android.bundleVersionCode = versionDefinition.BuildNumber; + PlayerSettings.iOS.buildNumber = versionDefinition.BuildNumber.ToString(); + PlayerSettings.bundleVersion = versionDefinition.ToString(); + AssetDatabase.SaveAssets(); + } + + private struct VersionDefinition + { + public const int MAX_VALUE = 99; + public const string BUILD_NUMBER_FORMAT = "00"; + + public const int DEFAULT_MAJOR = 0; + public const int DEFAULT_MINOR = 0; + public const int DEFAULT_PATCH = 0; + public const int DEFAULT_RELEASE_CANDIDATE = 1; + public const int RELEASE_RC_VALUE = 99; + + private readonly int _major; + private readonly int _minor; + private readonly int _patch; + private readonly int _releaseCandidate; + + public readonly int Major => _major > MAX_VALUE ? MAX_VALUE : _major; + public readonly int Minor => _minor > MAX_VALUE ? MAX_VALUE : _minor; + public readonly int Patch => _patch > MAX_VALUE ? MAX_VALUE : _patch; + public readonly int ReleaseCandidate => _releaseCandidate > MAX_VALUE ? MAX_VALUE : _releaseCandidate; + + public readonly bool IsRelease => ReleaseCandidate == RELEASE_RC_VALUE; + + public VersionDefinition(int? major = null, int? minor = null, int? patch = null, int? releaseCandidate = null) + { + _major = major ?? DEFAULT_MAJOR; + _minor = minor ?? DEFAULT_MINOR; + _patch = patch ?? DEFAULT_PATCH; + _releaseCandidate = releaseCandidate ?? DEFAULT_RELEASE_CANDIDATE; + + if (_major == 0 && _minor == 0) + _minor = _releaseCandidate = 1; + } + + public VersionDefinition(string versionString) + { + if (versionString.StartsWith('v')) + versionString = versionString[1..]; + + _major = DEFAULT_MAJOR; + _minor = DEFAULT_MINOR; + _patch = DEFAULT_PATCH; + _releaseCandidate = RELEASE_RC_VALUE; + + string[] releaseCandidateVersionStrings = versionString.Split("-rc"); + string[] versionNumbers = releaseCandidateVersionStrings[0].Split('.'); + + if (versionNumbers.Length > 0 && int.TryParse(versionNumbers[0], out int major)) _major = major; + if (versionNumbers.Length > 1 && int.TryParse(versionNumbers[1], out int minor)) _minor = minor; + if (versionNumbers.Length > 2 && int.TryParse(versionNumbers[2], out int patch)) _patch = patch; + if (releaseCandidateVersionStrings.Length > 1 && int.TryParse(releaseCandidateVersionStrings[1], out int releaseCandidate)) _releaseCandidate = releaseCandidate; + + if (_major == 0 && _minor == 0) + _minor = _releaseCandidate = 1; + } + + public readonly VersionDefinition IncreaseMajor() => new(Major + 1, DEFAULT_MINOR, DEFAULT_PATCH, DEFAULT_RELEASE_CANDIDATE); + public readonly VersionDefinition IncreaseMinor() => new(Major, Minor + 1, DEFAULT_PATCH, DEFAULT_RELEASE_CANDIDATE); + public readonly VersionDefinition IncreasePatch() => new(Major, Minor, Patch + 1, DEFAULT_RELEASE_CANDIDATE); + public readonly VersionDefinition IncreaseReleaseCandidate() => new(Major, Minor, Patch, ReleaseCandidate + 1); + public readonly VersionDefinition ToReleaseVersion() => new(Major, Minor, Patch, RELEASE_RC_VALUE); + + public readonly int BuildNumber => int.Parse($"{Major.ToString(BUILD_NUMBER_FORMAT)}{Minor.ToString(BUILD_NUMBER_FORMAT)}{Patch.ToString(BUILD_NUMBER_FORMAT)}{ReleaseCandidate.ToString(BUILD_NUMBER_FORMAT)}"); + + public override readonly string ToString() + { + if (IsRelease) + return $"{Major}.{Minor}.{Patch}"; + return $"{Major}.{Minor}.{Patch}-rc{ReleaseCandidate}"; + } + + public static bool operator >(VersionDefinition left, VersionDefinition right) => left.BuildNumber > right.BuildNumber; + public static bool operator <(VersionDefinition left, VersionDefinition right) => left.BuildNumber < right.BuildNumber; + public static bool operator >=(VersionDefinition left, VersionDefinition right) => left.BuildNumber >= right.BuildNumber; + public static bool operator <=(VersionDefinition left, VersionDefinition right) => left.BuildNumber <= right.BuildNumber; + public static bool operator ==(VersionDefinition left, VersionDefinition right) => left.BuildNumber == right.BuildNumber; + public static bool operator !=(VersionDefinition left, VersionDefinition right) => left.BuildNumber != right.BuildNumber; + + public override readonly bool Equals(object obj) + => obj is VersionDefinition versionDefinition && BuildNumber == versionDefinition.BuildNumber; + + public override readonly int GetHashCode() + => HashCode.Combine(Major, Minor, Patch, ReleaseCandidate); + } + + private static class GitProcess + { + public static VersionDefinition GetLatestBuildVersion() => new(GetLatestBuildVersionString()); + public static VersionDefinition GetUpcomingReleaseVersion() => GetUpcomingReleaseCandidateVersion().ToReleaseVersion(); + public static VersionDefinition GetUpcomingReleaseCandidateVersion() + { + VersionDefinition latestVersionDefinition = GetLatestBuildVersion(); + string[] commits = GetCommitsSinceLastTag(); + return ApplySemVer(latestVersionDefinition, commits); + } + + public static VersionDefinition GetVersion(string version, IList gitLogs) + => ApplySemVer(new(version), gitLogs); + + public static VersionDefinition ApplySemVer(VersionDefinition latestVersionDefinition, IList commits) + { + VersionDefinition result = latestVersionDefinition.IsRelease ? latestVersionDefinition.IncreasePatch() : latestVersionDefinition; + for (int i = commits.Count - 1; i >= 0; i--) + { + string line = commits[i]; + if (string.IsNullOrWhiteSpace(line)) + continue; + + string commitTitle = line.Length > 9 ? line[9..] : line; + if (commitTitle.StartsWith("breaking change", StringComparison.InvariantCultureIgnoreCase)) + { + result = result.IncreaseMajor(); + break; + } + + if (latestVersionDefinition.Minor != result.Minor) + continue; + + if (commitTitle.StartsWith("feat", StringComparison.OrdinalIgnoreCase)) + { + result = result.IncreaseMinor(); + continue; + } + + if (latestVersionDefinition.Patch != result.Patch) + continue; + + if (commitTitle.StartsWith("fix", StringComparison.OrdinalIgnoreCase)) + { + result = result.IncreasePatch(); + continue; + } + + if (latestVersionDefinition.ReleaseCandidate == result.ReleaseCandidate) + result = result.IncreaseReleaseCandidate(); + } + + return result; + } + + public static string GetLatestBuildVersionString() + => RunGitCommand($"describe --tags --abbrev=0"); + + public static string[] GetCommits() + => RunGitCommand("log --oneline").Replace("\r", "").Split('\n'); + + public static string[] GetCommitsSinceLastTag() + => RunGitCommand($"log {GetLatestBuildVersionString()}..HEAD --oneline").Replace("\r", "").Split('\n'); + + public static string CreateTag(VersionDefinition versionDefinition) + => CreateTag($"v{versionDefinition}", $"{(versionDefinition.IsRelease ? "Release" : "Build")} {versionDefinition} with build number: {versionDefinition.BuildNumber}\""); + + public static string Push() + => RunGitCommand($"push"); + + public static string Add(IList files) + => RunGitCommand($"add \"{string.Join("\" \"", files)}\""); + + public static string Add(string file) + => RunGitCommand($"add \"{file}\""); + + public static string Commit(string message) + => RunGitCommand($"commit -m \"{message}\""); + + public static string PushTags() + => RunGitCommand($"push --tags"); + + public static string PushTag(VersionDefinition versionDefinition, string remote = "origin") + => RunGitCommand($"push {remote} tag v{versionDefinition}"); + + public static string CreateTag(string title, string message) + => RunGitCommand($"tag -a {title} -m \"{message}"); + + public static string Unstage(IList files) + => RunGitCommand($"reset \"{string.Join("\" \"", files)}\""); + + public static string Unstage(string file) + => RunGitCommand($"reset \"{file}\""); + + public static string Unstage() + => RunGitCommand($"reset"); + + private static string RunGitCommand(string gitArgs) + { + ProcessStartInfo processStartInfo = new() + { + FileName = "git", + Arguments = gitArgs, + RedirectStandardOutput = true, + UseShellExecute = false, + CreateNoWindow = true + }; + + try + { + Process process = Process.Start(processStartInfo); + string output = process.StandardOutput.ReadToEnd(); + if (output.EndsWith('\n')) output = output[0..^1]; + if (output.EndsWith('\r')) output = output[0..^1]; + process.WaitForExit(); + return output; + } + catch (Exception ex) + { + Console.WriteLine("An error occurred: " + ex.Message); + throw; + } + } + } +}