From ab179997b8eafeb749d7556b0b3c31a97adb63a4 Mon Sep 17 00:00:00 2001 From: Frank Robijn <13610628+frobijn@users.noreply.github.com> Date: Mon, 16 Dec 2024 16:15:00 +0100 Subject: [PATCH] Firmware archive related bug fixes (#307) --- nanoFirmwareFlasher.Library/ExitCodes.cs | 8 ++- .../FirmwareArchiveManager.cs | 34 +++++++++++++ .../FirmwarePackage.cs | 14 +++++- .../FirmwarePackageTests.cs | 49 ++++++++++++++----- .../ToolFirmwareArchiveTests.cs | 34 ++++++------- nanoFirmwareFlasher.Tool/Program.cs | 12 ++--- 6 files changed, 113 insertions(+), 38 deletions(-) diff --git a/nanoFirmwareFlasher.Library/ExitCodes.cs b/nanoFirmwareFlasher.Library/ExitCodes.cs index 9d664d65..fdcbab18 100644 --- a/nanoFirmwareFlasher.Library/ExitCodes.cs +++ b/nanoFirmwareFlasher.Library/ExitCodes.cs @@ -339,7 +339,13 @@ public enum ExitCodes /// /// Error clearing cache location. /// - [Display(Name = "Error occured when clearing the firmware cache location.")] + [Display(Name = "Error occurred when clearing the firmware cache location.")] E9014 = 9014, + + /// + /// Can't find the target in the firmware archive. + /// + [Display(Name = "Can't find the target in the firmware archive.")] + E9015 = 9015, } } diff --git a/nanoFirmwareFlasher.Library/FirmwareArchiveManager.cs b/nanoFirmwareFlasher.Library/FirmwareArchiveManager.cs index bd9890de..603c1d91 100644 --- a/nanoFirmwareFlasher.Library/FirmwareArchiveManager.cs +++ b/nanoFirmwareFlasher.Library/FirmwareArchiveManager.cs @@ -67,6 +67,40 @@ public List GetTargetList( return targetPackages; } + /// + /// Get the latest version present in the firmware archive for the specified target. + /// + /// Option for preview version. + /// Target to find the latest version of. + /// The with details on latest firmware package for the target, or if none is present. + public CloudSmithPackageDetail GetLatestVersion( + bool preview, + string target) + { + CloudSmithPackageDetail result = null; + Version latest = null; + if (Directory.Exists(_archivePath) && !string.IsNullOrEmpty(target)) + { + foreach (string filePath in Directory.EnumerateFiles(_archivePath, $"{target}-*{INFOFILE_EXTENSION}")) + { + PersistedPackageInformation packageInformation = JsonConvert.DeserializeObject(File.ReadAllText(filePath)); + if (packageInformation is not null && packageInformation.IsPreview == preview) + { + if (Version.TryParse(packageInformation.Version, out Version version)) + { + if (latest is null || latest < version) + { + latest = version; + result = packageInformation; + } + } + } + } + } + + return result; + } + /// /// Download a firmware package from the repository and add it to the archive directory /// diff --git a/nanoFirmwareFlasher.Library/FirmwarePackage.cs b/nanoFirmwareFlasher.Library/FirmwarePackage.cs index e7d9c1dc..41e54ab8 100644 --- a/nanoFirmwareFlasher.Library/FirmwarePackage.cs +++ b/nanoFirmwareFlasher.Library/FirmwarePackage.cs @@ -344,6 +344,18 @@ void UpdateLocationPathAndFileName(bool initial) } + if (archiveDirectoryPath is not null && Version is null) + { + // Find the latest version in the archive directory + var archiveManager = new FirmwareArchiveManager(archiveDirectoryPath); + Version = archiveManager.GetLatestVersion(_preview, _targetName)?.Version; + if (Version is null) + { + // Package is considered to be not present, even if it does exist in the cache location + return (ExitCodes.E9015, null); + } + } + // create the download folder try { @@ -369,7 +381,7 @@ void UpdateLocationPathAndFileName(bool initial) if (!File.Exists(archiveFileName)) { // Package is considered to be not present, even if it does exist in the cache location - return (ExitCodes.E9007, null); + return (ExitCodes.E9015, null); } if (!skipDownload) diff --git a/nanoFirmwareFlasher.Tests/FirmwarePackageTests.cs b/nanoFirmwareFlasher.Tests/FirmwarePackageTests.cs index 026ee919..bfc2b416 100644 --- a/nanoFirmwareFlasher.Tests/FirmwarePackageTests.cs +++ b/nanoFirmwareFlasher.Tests/FirmwarePackageTests.cs @@ -194,7 +194,7 @@ where d.StartsWith(targetName + "-") [TestMethod] [TestCategory("CloudSmith")] - public void FirmwarePackage_DebugFirmware_Download() + public void FirmwarePackage_LegacyVirtualDevice_Download() { #region Setup using var output = new OutputWriterHelper(); @@ -236,32 +236,55 @@ public void FirmwarePackage_FromArchive() { Assert.Inconclusive("Cannot download the ESP32 package."); } - string testTargetName = "NO_REAL_TARGET"; - string testVersion = "0.0.0.0"; - File.Copy(Path.Combine(cacheDirectory, package.Name, $"{package.Name}-{package.Version}.zip"), Path.Combine(archiveDirectory, $"{testTargetName}-{testVersion}.zip")); + string testTarget1Name = "TARGET1_IN_ARCHIVE_ONLY"; + string testTarget2Name = "TARGET2_IN_ARCHIVE_ONLY"; + string testVersion = "1.23.4.5"; + string testOldVersion = "1.6.7.8"; + + // Copy the package to the archive directory, modified for TARGET1_IN_ARCHIVE_ONLY and TARGET2_IN_ARCHIVE_ONLY + File.Copy(Path.Combine(cacheDirectory, package.Name, $"{package.Name}-{package.Version}.zip"), Path.Combine(archiveDirectory, $"{testTarget1Name}-{testVersion}.zip")); + File.WriteAllText(Path.Combine(archiveDirectory, $"{testTarget1Name}-{testVersion}.zip.json"), $@"{{ ""Name"": ""{testTarget1Name}"", ""Version"": ""{testVersion}"", ""Platform"": ""esp32"" }}"); + File.Copy(Path.Combine(cacheDirectory, package.Name, $"{package.Name}-{package.Version}.zip"), Path.Combine(archiveDirectory, $"{testTarget2Name}-{testVersion}.zip")); + File.WriteAllText(Path.Combine(archiveDirectory, $"{testTarget2Name}-{testVersion}.zip.json"), $@"{{ ""Name"": ""{testTarget2Name}"", ""Version"": ""{testVersion}"", ""Platform"": ""esp32"" }}"); + + // Create an invalid package for an earlier version of TARGET2_IN_ARCHIVE_ONLY - this should not be used + File.WriteAllText(Path.Combine(archiveDirectory, $"{testTarget2Name}-{testOldVersion}.zip"), ""); + File.WriteAllText(Path.Combine(archiveDirectory, $"{testTarget2Name}-{testOldVersion}.zip.json"), $@"{{ ""Name"": ""{testTarget2Name}"", ""Version"": ""{testOldVersion}"", ""Platform"": ""esp32"" }}"); #endregion - #region Get package that exist in the archive directory but not in the repository + #region Get package that exist in the archive directory but not in the repository; include version output.Reset(); - var actual = new Esp32Firmware(testTargetName, testVersion, false, null); + var actual = new Esp32Firmware(testTarget1Name, testVersion, false, null); exitCode = actual.DownloadAndExtractAsync(archiveDirectory).GetAwaiter().GetResult(); Assert.AreEqual(ExitCodes.OK, exitCode); output.AssertAreEqual(""); - Assert.IsTrue(Directory.Exists(Path.Combine(cacheDirectory, testTargetName))); - Assert.IsTrue(File.Exists(Path.Combine(cacheDirectory, testTargetName, $"{testTargetName}-{testVersion}.zip"))); - Assert.IsTrue(File.Exists(Path.Combine(cacheDirectory, testTargetName, "nanoCLR.bin"))); + Assert.IsTrue(Directory.Exists(Path.Combine(cacheDirectory, testTarget1Name))); + Assert.IsTrue(File.Exists(Path.Combine(cacheDirectory, testTarget1Name, $"{testTarget1Name}-{testVersion}.zip"))); + Assert.IsTrue(File.Exists(Path.Combine(cacheDirectory, testTarget1Name, "nanoCLR.bin"))); + #endregion + + #region Get package that exist in the archive directory but not in the repository; do not include version + output.Reset(); + actual = new Esp32Firmware(testTarget2Name, null, false, null); + exitCode = actual.DownloadAndExtractAsync(archiveDirectory).GetAwaiter().GetResult(); + + Assert.AreEqual(ExitCodes.OK, exitCode); + output.AssertAreEqual(""); + Assert.IsTrue(Directory.Exists(Path.Combine(cacheDirectory, testTarget2Name))); + Assert.IsTrue(File.Exists(Path.Combine(cacheDirectory, testTarget2Name, $"{testTarget2Name}-{testVersion}.zip"))); + Assert.IsTrue(File.Exists(Path.Combine(cacheDirectory, testTarget2Name, "nanoCLR.bin"))); #endregion #region Get package that does not exist in the archive directory - testTargetName = "MISSING_TARGET"; + testTarget1Name = "MISSING_TARGET"; - actual = new Esp32Firmware(testTargetName, testVersion, false, null); + actual = new Esp32Firmware(testTarget1Name, testVersion, false, null); exitCode = actual.DownloadAndExtractAsync(archiveDirectory).GetAwaiter().GetResult(); - Assert.AreEqual(ExitCodes.E9007, exitCode); + Assert.AreEqual(ExitCodes.E9015, exitCode); output.AssertAreEqual(""); - Assert.IsFalse(File.Exists(Path.Combine(cacheDirectory, testTargetName, $"{testTargetName}-{testVersion}.zip"))); + Assert.IsFalse(File.Exists(Path.Combine(cacheDirectory, testTarget1Name, $"{testTarget1Name}-{testVersion}.zip"))); #endregion } } diff --git a/nanoFirmwareFlasher.Tests/ToolFirmwareArchiveTests.cs b/nanoFirmwareFlasher.Tests/ToolFirmwareArchiveTests.cs index 3ac52d92..b7a3a1d2 100644 --- a/nanoFirmwareFlasher.Tests/ToolFirmwareArchiveTests.cs +++ b/nanoFirmwareFlasher.Tests/ToolFirmwareArchiveTests.cs @@ -33,21 +33,21 @@ public void FirmwareArchive_Platform_UpdateArchive_ListTargets() #endregion #region List empty archive - int actual = Program.Main(["--listtargets", "--platform", $"{SupportedPlatform.ti_simplelink}", "--fromfwarchive", "--fwarchivepath", archiveDirectory]) + int actual = Program.Main(["--listtargets", "--platform", $"{SupportedPlatform.ti_simplelink}", "--fromarchive", "--archivepath", archiveDirectory]) .GetAwaiter().GetResult(); Assert.AreEqual((int)ExitCodes.OK, actual); #endregion #region Update archive output.Reset(); - actual = Program.Main(["--updatefwarchive", "--platform", $"{SupportedPlatform.ti_simplelink}", "--fwarchivepath", archiveDirectory]) + actual = Program.Main(["--updatearchive", "--platform", $"{SupportedPlatform.ti_simplelink}", "--archivepath", archiveDirectory]) .GetAwaiter().GetResult(); Assert.AreEqual((int)ExitCodes.OK, actual); #endregion #region List filled archive output.Reset(); - actual = Program.Main(["--listtargets", "--platform", $"{SupportedPlatform.ti_simplelink}", "--fromfwarchive", "--fwarchivepath", archiveDirectory]) + actual = Program.Main(["--listtargets", "--platform", $"{SupportedPlatform.ti_simplelink}", "--fromarchive", "--archivepath", archiveDirectory]) .GetAwaiter().GetResult(); Assert.AreEqual((int)ExitCodes.OK, actual); @@ -70,14 +70,14 @@ public void FirmwareArchive_Target_UpdateArchive_ListTargets() #region Update archive output.Reset(); - int actual = Program.Main(["--updatefwarchive", "--target", $"{allPackages[0].Name}", "--fwarchivepath", archiveDirectory]) + int actual = Program.Main(["--updatearchive", "--target", $"{allPackages[0].Name}", "--archivepath", archiveDirectory]) .GetAwaiter().GetResult(); Assert.AreEqual((int)ExitCodes.OK, actual); #endregion #region List filled archive output.Reset(); - actual = Program.Main(["--listtargets", "--platform", $"{SupportedPlatform.ti_simplelink}", "--fromfwarchive", "--fwarchivepath", archiveDirectory]) + actual = Program.Main(["--listtargets", "--platform", $"{SupportedPlatform.ti_simplelink}", "--fromarchive", "--archivepath", archiveDirectory]) .GetAwaiter().GetResult(); Assert.AreEqual((int)ExitCodes.OK, actual); @@ -96,11 +96,11 @@ public void FirmwareArchive_ListTargets_InvalidArguments() string testDirectory = TestDirectoryHelper.GetTestDirectory(TestContext); string archiveDirectory = Path.Combine(testDirectory, "archive"); - int actual = Program.Main(["--listtargets", "--platform", $"{SupportedPlatform.ti_simplelink}", "--fromfwarchive", "--verbosity", "diagnostic"]) + int actual = Program.Main(["--listtargets", "--platform", $"{SupportedPlatform.ti_simplelink}", "--fromarchive", "--verbosity", "diagnostic"]) .GetAwaiter().GetResult(); Assert.AreEqual((int)ExitCodes.E9000, actual); - Assert.IsTrue(output.Output.Contains("--fwarchivepath is required when --fromfwarchive is specified.")); + Assert.IsTrue(output.Output.Contains("--archivepath is required when --fromarchive is specified.")); } [TestMethod] @@ -110,25 +110,25 @@ public void FirmwareArchive_UpdateArchive_InvalidArguments() string testDirectory = TestDirectoryHelper.GetTestDirectory(TestContext); string archiveDirectory = Path.Combine(testDirectory, "archive"); - int actual = Program.Main(["--updatefwarchive", "--platform", $"{SupportedPlatform.ti_simplelink}", "--fromfwarchive", "--verbosity", "diagnostic"]) + int actual = Program.Main(["--updatearchive", "--platform", $"{SupportedPlatform.ti_simplelink}", "--fromarchive", "--verbosity", "diagnostic"]) .GetAwaiter().GetResult(); Assert.AreEqual((int)ExitCodes.E9000, actual); - Assert.IsTrue(output.Output.Contains("Incompatible option --fromfwarchive combined with --updatefwarchive.")); + Assert.IsTrue(output.Output.Contains("Incompatible option --fromarchive combined with --updatearchive.")); output.Reset(); - actual = Program.Main(["--updatefwarchive", "--platform", $"{SupportedPlatform.ti_simplelink}", "--verbosity", "diagnostic"]) + actual = Program.Main(["--updatearchive", "--platform", $"{SupportedPlatform.ti_simplelink}", "--verbosity", "diagnostic"]) .GetAwaiter().GetResult(); Assert.AreEqual((int)ExitCodes.E9000, actual); - Assert.IsTrue(output.Output.Contains("--fwarchivepath is required when --updatefwarchive is specified.")); + Assert.IsTrue(output.Output.Contains("--archivepath is required when --updatearchive is specified.")); output.Reset(); - actual = Program.Main(["--updatefwarchive", "--fwarchivepath", $"{SupportedPlatform.ti_simplelink}", "--verbosity", "diagnostic"]) + actual = Program.Main(["--updatearchive", "--archivepath", $"{SupportedPlatform.ti_simplelink}", "--verbosity", "diagnostic"]) .GetAwaiter().GetResult(); Assert.AreEqual((int)ExitCodes.E9000, actual); - Assert.IsTrue(output.Output.Contains("--platform or --target is required when --updatefwarchive is specified.")); + Assert.IsTrue(output.Output.Contains("--platform or --target is required when --updatearchive is specified.")); } [TestMethod] @@ -138,18 +138,18 @@ public void FirmwareArchive_UpdateFirmware_InvalidArguments() string testDirectory = TestDirectoryHelper.GetTestDirectory(TestContext); string archiveDirectory = Path.Combine(testDirectory, "archive"); - int actual = Program.Main(["--serialport", "COM3", "--target", "SOME_TARGET", "--fromfwarchive", "--verbosity", "diagnostic"]) + int actual = Program.Main(["--serialport", "COM3", "--target", "SOME_TARGET", "--fromarchive", "--verbosity", "diagnostic"]) .GetAwaiter().GetResult(); Assert.AreEqual((int)ExitCodes.E9000, actual); - Assert.IsTrue(output.Output.Contains("--fwarchivepath is required when --fromfwarchive is specified.")); + Assert.IsTrue(output.Output.Contains("--archivepath is required when --fromarchive is specified.")); output.Reset(); - actual = Program.Main(["--serialport", "COM3", "--target", "SOME_TARGET", "--fwarchivepath", archiveDirectory, "--verbosity", "diagnostic"]) + actual = Program.Main(["--serialport", "COM3", "--target", "SOME_TARGET", "--archivepath", archiveDirectory, "--verbosity", "diagnostic"]) .GetAwaiter().GetResult(); Assert.AreEqual((int)ExitCodes.E9000, actual); - Assert.IsTrue(output.Output.Contains("--fromfwarchive is required when --fwarchivepath is specified.")); + Assert.IsTrue(output.Output.Contains("--fromarchive is required when --archivepath is specified.")); } } } diff --git a/nanoFirmwareFlasher.Tool/Program.cs b/nanoFirmwareFlasher.Tool/Program.cs index 28e69dc6..e45b0f2c 100644 --- a/nanoFirmwareFlasher.Tool/Program.cs +++ b/nanoFirmwareFlasher.Tool/Program.cs @@ -289,7 +289,7 @@ static async Task RunOptionsAndReturnExitCodeAsync(Options o) if (string.IsNullOrEmpty(o.FwArchivePath)) { _exitCode = ExitCodes.E9000; - _extraMessage = "--fwarchivepath is required when --fromfwarchive is specified."; + _extraMessage = "--archivepath is required when --fromarchive is specified."; return; } @@ -558,20 +558,20 @@ static async Task RunOptionsAndReturnExitCodeAsync(Options o) if (o.FromFwArchive) { _exitCode = ExitCodes.E9000; - _extraMessage = "Incompatible option --fromfwarchive combined with --updatefwarchive."; + _extraMessage = "Incompatible option --fromarchive combined with --updatearchive."; return; } if (string.IsNullOrEmpty(o.FwArchivePath)) { _exitCode = ExitCodes.E9000; - _extraMessage = $"--fwarchivepath is required when --updatefwarchive is specified."; + _extraMessage = $"--archivepath is required when --updatearchive is specified."; return; } if (o.Platform is null && string.IsNullOrEmpty(o.TargetName)) { _exitCode = ExitCodes.E9000; - _extraMessage = $"--platform or --target is required when --updatefwarchive is specified."; + _extraMessage = $"--platform or --target is required when --updatearchive is specified."; return; } @@ -591,14 +591,14 @@ static async Task RunOptionsAndReturnExitCodeAsync(Options o) if (o.FromFwArchive) { _exitCode = ExitCodes.E9000; - _extraMessage = $"--fwarchivepath is required when --fromfwarchive is specified."; + _extraMessage = $"--archivepath is required when --fromarchive is specified."; return; } } else if (!o.FromFwArchive) { _exitCode = ExitCodes.E9000; - _extraMessage = $"--fromfwarchive is required when --fwarchivepath is specified."; + _extraMessage = $"--fromarchive is required when --archivepath is specified."; return; } #endregion