-
Notifications
You must be signed in to change notification settings - Fork 0
feat: add support for ARM and Intel architectures in builds and workflows #7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -4,129 +4,161 @@ public sealed class Commands | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private static readonly EnumerationOptions EnumerationOptions = new() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Handle recursion manually for better control | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| RecurseSubdirectories = false, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Skip symlinks/junctions to avoid infinite loops | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| AttributesToSkip = FileAttributes.ReparsePoint, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Continue on permission errors (handled in catch block) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| IgnoreInaccessible = true, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Skip "." and ".." entries | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ReturnSpecialDirectories = false, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Faster matching since we use "*" pattern (not complex wildcards) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| MatchType = MatchType.Simple, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// <summary> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// Runs 'dotnet clean', then recursively deletes 'bin' and 'obj' directories from the specified path and optionally | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// restores the project. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// Runs 'dotnet clean', then recursively deletes 'bin' and 'obj' directories from the specified path, then | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// optionally restores the project. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// </summary> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// <param name="path">-p, The root path to start cleaning from. [Default: Current directory]</param> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// <param name="noRestore">-n, If true, skips any restore operations. [Default: false]</param> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// <param name="verbose">-v, If true, outputs detailed information about the cleaning process. [Default: false]</param> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [PublicAPI] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [Command("")] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "Used by ConsoleAppFramework")] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public void Clean([HideDefaultValue] string? path = null, bool noRestore = false) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "Required by ConsoleAppFramework")] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public void Clean([HideDefaultValue] string? path = null, bool noRestore = false, bool verbose = false) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| path ??= Directory.GetCurrentDirectory(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (string.IsNullOrWhiteSpace(path) || !Directory.Exists(path)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| DotnetClean(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CleanRecursive(path); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (noRestore) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var restoreProcessStartInfo = new ProcessStartInfo("dotnet", "restore") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| WorkingDirectory = path, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| RedirectStandardOutput = true, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| RedirectStandardError = true, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| UseShellExecute = false, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CreateNoWindow = true, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| using var process = Process.Start(restoreProcessStartInfo); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (process == null) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Console.Error.WriteLine("Failed to start 'dotnet restore' process."); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Console.Error.WriteLine($"Invalid or non-existent path: {path}"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| process.WaitForExit(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| RunDotnetCommand("clean", path, verbose); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (process.ExitCode == 0) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Console.WriteLine("'dotnet restore' completed successfully."); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| else | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Console.Error.WriteLine($"'dotnet restore' failed with exit code {process.ExitCode}."); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Console.Error.WriteLine(process.StandardError.ReadToEnd()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Track deleted directories across recursive calls using ref parameter | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var deletedDirectoryCount = 0; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CleanRecursive(path, verbose, ref deletedDirectoryCount); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Console.WriteLine($"Deleted {deletedDirectoryCount} 'bin' / 'obj' directories."); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!noRestore) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| RunDotnetCommand("restore", path, verbose); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private static void DotnetClean() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private static void RunDotnetCommand(string command, string path, bool verbose) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var cleanProcessStartInfo = new ProcessStartInfo("dotnet", "clean") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var processStartInfo = new ProcessStartInfo("dotnet", command) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| RedirectStandardOutput = true, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| RedirectStandardError = true, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| UseShellExecute = false, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CreateNoWindow = true, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| WorkingDirectory = path, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| using var process = Process.Start(cleanProcessStartInfo); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| using var process = new Process(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| process.StartInfo = processStartInfo; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (process == null) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Always subscribe to output events, even in non-verbose mode | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // This is required because we always call BeginOutputReadLine below | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| process.OutputDataReceived += (_, e) => | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Console.Error.WriteLine("Failed to start 'dotnet clean' process."); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (e.Data != null && verbose) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Console.WriteLine(e.Data); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| process.ErrorDataReceived += (_, e) => | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (e.Data != null && verbose) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Console.Error.WriteLine(e.Data); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| process.Start(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Should always drain output streams to prevent buffer deadlock | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // When RedirectStandardOutput/Error = true but streams aren't consumed, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // the process buffer can fill and hang. BeginOutputReadLine() drains asynchronously. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| process.BeginOutputReadLine(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| process.BeginErrorReadLine(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+84
to
91
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| process.Start(); | |
| // Should always drain output streams to prevent buffer deadlock | |
| // When RedirectStandardOutput/Error = true but streams aren't consumed, | |
| // the process buffer can fill and hang. BeginOutputReadLine() drains asynchronously. | |
| process.BeginOutputReadLine(); | |
| process.BeginErrorReadLine(); | |
| try | |
| { | |
| process.Start(); | |
| // Should always drain output streams to prevent buffer deadlock | |
| // When RedirectStandardOutput/Error = true but streams aren't consumed, | |
| // the process buffer can fill and hang. BeginOutputReadLine() drains asynchronously. | |
| process.BeginOutputReadLine(); | |
| process.BeginErrorReadLine(); | |
| } | |
| catch (System.ComponentModel.Win32Exception ex) | |
| { | |
| Console.Error.WriteLine($"Failed to start 'dotnet {command}' in '{path}': {ex.Message}"); | |
| return; | |
| } | |
| catch (InvalidOperationException ex) | |
| { | |
| Console.Error.WriteLine($"Failed to initialize output capture for 'dotnet {command}' in '{path}': {ex.Message}"); | |
| return; | |
| } |
Copilot
AI
Apr 11, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With asynchronous BeginOutputReadLine/BeginErrorReadLine, a single WaitForExit() can return before all output events are fully drained/processed, potentially truncating logs (especially in verbose mode). Consider ensuring async reads complete (e.g., a second WaitForExit() or equivalent pattern) before returning.
| // Ensure asynchronous output/error events are fully drained before returning. | |
| process.WaitForExit(); |
Copilot
AI
Apr 11, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Materializing all subdirectories into an array at every recursion level can increase memory pressure and latency for large repos. You can avoid ToArray() by building two lists during a single enumeration pass (e.g., one for bin/obj deletion and one for recursion), which keeps streaming behavior and still supports the two-pass logic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These download steps are highly repetitive and will keep growing as the matrix expands. With
actions/download-artifact@v4, consider downloading via a single step using apattern(e.g.,Invex.Tools.ArtifactClean-*) andmerge-multiple: true, or drive downloads via a small matrix/loop, to reduce duplication and the chance of missing future runner additions.