diff --git a/Source/v2/Meadow.CLI/Commands/Current/App/AppTools.cs b/Source/v2/Meadow.CLI/Commands/Current/App/AppTools.cs index 3d11bb6bd..2b856ed61 100644 --- a/Source/v2/Meadow.CLI/Commands/Current/App/AppTools.cs +++ b/Source/v2/Meadow.CLI/Commands/Current/App/AppTools.cs @@ -137,4 +137,42 @@ internal static string SanitizeMeadowFilename(string fileName) return meadowFileName!.Replace(Path.DirectorySeparatorChar, '/'); } + + internal static async Task RunProcessCommand(string command, string args, Action? handleOutput = null, Action? handleError = null, CancellationToken cancellationToken = default) + { + var processStartInfo = new ProcessStartInfo + { + FileName = command, + Arguments = args, + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true + }; + + using (var process = new Process { StartInfo = processStartInfo }) + { + process.Start(); + + var outputCompletion = ReadLinesAsync(process.StandardOutput, handleOutput, cancellationToken); + var errorCompletion = ReadLinesAsync(process.StandardError, handleError, cancellationToken); + + await Task.WhenAll(outputCompletion, errorCompletion, process.WaitForExitAsync()); + + return process.ExitCode; + } + } + + private static async Task ReadLinesAsync(StreamReader reader, Action? handleLine, CancellationToken cancellationToken) + { + while (!reader.EndOfStream) + { + var line = await reader.ReadLineAsync(cancellationToken); + if (!string.IsNullOrWhiteSpace(line) + && handleLine != null) + { + handleLine(line); + } + } + } } \ No newline at end of file diff --git a/Source/v2/Meadow.CLI/Commands/Current/UpdateCommand.cs b/Source/v2/Meadow.CLI/Commands/Current/UpdateCommand.cs index 34052f92c..01f099440 100644 --- a/Source/v2/Meadow.CLI/Commands/Current/UpdateCommand.cs +++ b/Source/v2/Meadow.CLI/Commands/Current/UpdateCommand.cs @@ -1,32 +1,27 @@ -using CliFx.Attributes; +using System.Reflection; +using CliFx.Attributes; using Microsoft.Extensions.Logging; -using Mono.Cecil.Cil; -using System.Diagnostics; -using System.Reflection; -using System.Runtime.InteropServices; -using static Meadow.CLI.Strings; namespace Meadow.CLI.Commands.DeviceManagement; -[Command("update", Description = Update.Description)] +[Command("update", Description = Strings.Update.Description)] public class UpdateCommand : BaseCommand { const string MEADOW_CLI = "WildernessLabs.Meadow.CLI"; const string MEADOW_UPDATER = "Meadow.Updater"; - const string CLIFX = "CliFx"; + const string CLIFX = "CliFx"; - [CommandOption("version", 'v', IsRequired = false)] + [CommandOption("version", 'v', IsRequired = false)] public string? Version { get; set; } - public UpdateCommand( - ILoggerFactory loggerFactory) + public UpdateCommand(ILoggerFactory loggerFactory) : base(loggerFactory) { } protected override async ValueTask ExecuteCommand() { - Logger.LogInformation(Update.Updating, MEADOW_CLI); + Logger.LogInformation(Strings.Update.Updating, MEADOW_CLI); string toVersion; if (!string.IsNullOrWhiteSpace(Version)) @@ -38,20 +33,20 @@ protected override async ValueTask ExecuteCommand() toVersion = "vLatest"; } ; - Logger.LogInformation(Update.Instruction1, MEADOW_CLI, toVersion); - Logger.LogInformation(Update.Instruction2); + Logger.LogInformation(Strings.Update.Instruction1, MEADOW_CLI, toVersion); + Logger.LogInformation(Strings.Update.Instruction2); // Path to the updater executable within the tool's output directory string meadowUpdaterPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? string.Empty, $"{MEADOW_UPDATER}.dll"); - - // Ensure the updater executable exists + + // Ensure the updater executable exists if (!File.Exists(meadowUpdaterPath)) { - Logger.LogError(Update.UpdaterNotFound); + Logger.LogError(Strings.Update.UpdaterNotFound); return; - } + } - // Copy all necessary files to a temporary location, so there aren't any access issues + // Copy all necessary files to a temporary location, so there aren't any access issues string tempUpdaterDir = Path.Combine(Path.GetTempPath(), MEADOW_UPDATER); if (!Directory.Exists(tempUpdaterDir)) { @@ -59,33 +54,16 @@ protected override async ValueTask ExecuteCommand() } CopyMeadowUpdaterFiles(Path.GetDirectoryName(meadowUpdaterPath), tempUpdaterDir, MEADOW_UPDATER); - // Supporting files required in the temp directory - CopyMeadowUpdaterFiles(Path.GetDirectoryName(meadowUpdaterPath), tempUpdaterDir, CLIFX); + // Supporting files required in the temp directory + CopyMeadowUpdaterFiles(Path.GetDirectoryName(meadowUpdaterPath), tempUpdaterDir, CLIFX); - string commandArguments = $"update -t {MEADOW_CLI}"; + string commandArguments = $"update -t {MEADOW_CLI}"; if (!string.IsNullOrWhiteSpace(Version)) { commandArguments += $" -v {Version}"; } - RunCommand("dotnet", $"{Path.Combine(tempUpdaterDir, $"{MEADOW_UPDATER}.dll")} {commandArguments}"); - } - - internal static void RunCommand(string command, string arguments) - { - var processStartInfo = new ProcessStartInfo - { - FileName = command, - Arguments = arguments, - UseShellExecute = false, - CreateNoWindow = true - }; - - // Fire and forget as the updating happens in the called exe - using (var process = new Process { StartInfo = processStartInfo }) - { - process.Start(); - } + await AppTools.RunProcessCommand("dotnet", $"{Path.Combine(tempUpdaterDir, $"{MEADOW_UPDATER}.dll")} {commandArguments}", cancellationToken: CancellationToken); } internal static void CopyMeadowUpdaterFiles(string? sourceDirectory, string targetDirectory, string filesToCopy) @@ -94,6 +72,7 @@ internal static void CopyMeadowUpdaterFiles(string? sourceDirectory, string targ { return; } + var toolUpdaterFiles = Directory.GetFiles(sourceDirectory, $"{filesToCopy}*"); foreach (var file in toolUpdaterFiles) {