From 13d369335d9e007deefcc031e90456e30a893d33 Mon Sep 17 00:00:00 2001 From: Ryan Fu Date: Fri, 15 Jul 2022 15:20:18 -0700 Subject: [PATCH 1/5] update new command prompts to handle portables --- src/WingetCreateCLI/Commands/NewCommand.cs | 44 ++++++++++++++++--- .../Properties/Resources.Designer.cs | 18 ++++++++ src/WingetCreateCLI/Properties/Resources.resx | 7 +++ 3 files changed, 63 insertions(+), 6 deletions(-) diff --git a/src/WingetCreateCLI/Commands/NewCommand.cs b/src/WingetCreateCLI/Commands/NewCommand.cs index 205ac951..8f232e12 100644 --- a/src/WingetCreateCLI/Commands/NewCommand.cs +++ b/src/WingetCreateCLI/Commands/NewCommand.cs @@ -296,13 +296,17 @@ private static void PromptInstallerProperties(T manifest, PropertyInfo proper bool prompted = false; - // If we know the installertype is EXE, prompt the user for installer switches (silent and silentwithprogress) + // If the installerType is EXE, prompt the user for whether the package is a portable if (installer.InstallerType == InstallerType.Exe) { Console.WriteLine(); - Logger.DebugLocalized(nameof(Resources.AdditionalMetadataNeeded_Message), installer.InstallerUrl); - prompted = true; - PromptInstallerSwitchesForExe(manifest); + if (!PromptForPortableExe(installer)) + { + // If we know the installertype is EXE, prompt the user for installer switches (silent and silentwithprogress) + Logger.DebugLocalized(nameof(Resources.AdditionalMetadataNeeded_Message), installer.InstallerUrl); + prompted = true; + PromptInstallerSwitchesForExe(installer); + } } foreach (var requiredProperty in requiredInstallerProperties) @@ -326,7 +330,7 @@ private static void PromptInstallerProperties(T manifest, PropertyInfo proper } } - private static void PromptInstallerSwitchesForExe(T manifest) + private static void PromptInstallerSwitchesForExe(T manifestInstaller) { InstallerSwitches installerSwitches = new InstallerSwitches(); @@ -335,7 +339,35 @@ private static void PromptInstallerSwitchesForExe(T manifest) if (!string.IsNullOrEmpty(installerSwitches.Silent) || !string.IsNullOrEmpty(installerSwitches.SilentWithProgress)) { - manifest.GetType().GetProperty(nameof(InstallerSwitches)).SetValue(manifest, installerSwitches); + manifestInstaller.GetType().GetProperty(nameof(InstallerSwitches)).SetValue(manifestInstaller, installerSwitches); + } + } + + /// + /// Prompts the user to confirm whether the package is a portable. + /// If true, then prompts for related portable metadata. + /// + /// Manifest installer. + /// Manifest installer object model. + /// Boolean value indicating whether the package is a portable. + private static bool PromptForPortableExe(T manifestInstaller) + { + if (Prompt.Confirm(Resources.ConfirmPortablePackage_Message)) + { + manifestInstaller.GetType().GetProperty(nameof(Installer.InstallerType)).SetValue(manifestInstaller, InstallerType.Portable); + string portableCommandAlias = Prompt.Input(Resources.PortableCommandAlias_Message); + + if (!string.IsNullOrEmpty(portableCommandAlias)) + { + List portableCommands = new List { portableCommandAlias }; + manifestInstaller.GetType().GetProperty(nameof(Installer.Commands)).SetValue(manifestInstaller, portableCommands); + } + + return true; + } + else + { + return false; } } diff --git a/src/WingetCreateCLI/Properties/Resources.Designer.cs b/src/WingetCreateCLI/Properties/Resources.Designer.cs index facb9e64..84ac1520 100644 --- a/src/WingetCreateCLI/Properties/Resources.Designer.cs +++ b/src/WingetCreateCLI/Properties/Resources.Designer.cs @@ -339,6 +339,15 @@ public static string ConfirmManifestCreation_Message { } } + /// + /// Looks up a localized string similar to Is this a portable package?. + /// + public static string ConfirmPortablePackage_Message { + get { + return ResourceManager.GetString("ConfirmPortablePackage_Message", resourceCulture); + } + } + /// /// Looks up a localized string similar to The package copyright. /// @@ -1608,6 +1617,15 @@ public static string Platform_KeywordDescription { } } + /// + /// Looks up a localized string similar to What is the command alias of the portable package |e.g. nuget|. + /// + public static string PortableCommandAlias_Message { + get { + return ResourceManager.GetString("PortableCommandAlias_Message", resourceCulture); + } + } + /// /// Looks up a localized string similar to Press any key to continue.... /// diff --git a/src/WingetCreateCLI/Properties/Resources.resx b/src/WingetCreateCLI/Properties/Resources.resx index 9543ca13..c75f4699 100644 --- a/src/WingetCreateCLI/Properties/Resources.resx +++ b/src/WingetCreateCLI/Properties/Resources.resx @@ -919,4 +919,11 @@ List of winget arguments the installer does not support "winget" is the proper name of the tool + + Is this a portable package? + + + What is the command alias of the portable package |e.g. nuget| + `command alias` refers to the name of the exe file that will be used when running the application from the command line. + \ No newline at end of file From 8523f976ffe14d1379e6bf7c75344f37069b9d29 Mon Sep 17 00:00:00 2001 From: Ryan Fu Date: Wed, 20 Jul 2022 16:43:15 -0700 Subject: [PATCH 2/5] add intial commit --- src/WingetCreateCore/Common/PackageParser.cs | 26 +++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/WingetCreateCore/Common/PackageParser.cs b/src/WingetCreateCore/Common/PackageParser.cs index 463fac09..cebcb3c8 100644 --- a/src/WingetCreateCore/Common/PackageParser.cs +++ b/src/WingetCreateCore/Common/PackageParser.cs @@ -10,8 +10,10 @@ namespace Microsoft.WingetCreateCore using System.Globalization; using System.IO; using System.Linq; - using System.Net.Http; - using System.Security.Cryptography; + using System.Net.Http; + using System.Reflection.PortableExecutable; + using System.Security.Cryptography; + using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Xml; @@ -278,7 +280,8 @@ public static void UpdateInstallerNodesAsync(List installerMe public static bool ParsePackageAndUpdateInstallerNode(Installer installer, string path, string url) { List newInstallers = new List(); - bool parseResult = ParseExeInstallerType(path, installer, newInstallers) || + bool parseResult = ParsePortableInstallerType(path, installer, newInstallers) || + ParseExeInstallerType(path, installer, newInstallers) || ParseMsix(path, installer, null, newInstallers) || ParseMsi(path, installer, null, newInstallers); @@ -468,7 +471,8 @@ private static bool ParsePackageAndGenerateInstallerNodes(InstallerMetadata inst bool parseMsixResult = false; - bool parseResult = ParseExeInstallerType(path, baseInstaller, newInstallers) || + bool parseResult = ParsePortableInstallerType(path, baseInstaller, newInstallers) || + ParseExeInstallerType(path, baseInstaller, newInstallers) || (parseMsixResult = ParseMsix(path, baseInstaller, manifests, newInstallers)) || ParseMsi(path, baseInstaller, manifests, newInstallers); @@ -626,6 +630,20 @@ private static CompatibilitySet GetCompatibilitySet(InstallerType type) default: return CompatibilitySet.None; } + } + + private static bool ParsePortableInstallerType(string path, Installer baseInstaller, List newInstallers) + { + using (var fileStream = File.Open(path, FileMode.Open)) + { + PEHeaders pEHeaders = new PEHeaders(fileStream); + if (pEHeaders.IsExe == true) + { + return true; + } + } + + return false; } private static bool ParseExeInstallerType(string path, Installer baseInstaller, List newInstallers) From 6139f3d50eac0013931f9379c26126ee90efb99e Mon Sep 17 00:00:00 2001 From: Ryan Fu Date: Fri, 22 Jul 2022 14:41:24 -0700 Subject: [PATCH 3/5] add tests --- src/WingetCreateCore/Common/PackageParser.cs | 25 ++++-------------- .../WingetCreateTests/E2ETests/E2ETests.cs | 3 ++- .../Resources/TestPublisher.Portable.yaml | 16 ++++++++++++ .../WingetCreateE2E.PortableTest.yaml | 26 +++++++++++++++++++ .../WingetCreateTests/TestConstants.cs | 10 +++++++ .../UnitTests/UpdateCommandTests.cs | 19 ++++++++++++++ .../WingetCreateTests.csproj | 6 +++++ 7 files changed, 84 insertions(+), 21 deletions(-) create mode 100644 src/WingetCreateTests/WingetCreateTests/Resources/TestPublisher.Portable.yaml create mode 100644 src/WingetCreateTests/WingetCreateTests/Resources/WingetCreateE2E.PortableTest.yaml diff --git a/src/WingetCreateCore/Common/PackageParser.cs b/src/WingetCreateCore/Common/PackageParser.cs index cebcb3c8..1873b108 100644 --- a/src/WingetCreateCore/Common/PackageParser.cs +++ b/src/WingetCreateCore/Common/PackageParser.cs @@ -280,8 +280,7 @@ public static void UpdateInstallerNodesAsync(List installerMe public static bool ParsePackageAndUpdateInstallerNode(Installer installer, string path, string url) { List newInstallers = new List(); - bool parseResult = ParsePortableInstallerType(path, installer, newInstallers) || - ParseExeInstallerType(path, installer, newInstallers) || + bool parseResult = ParseExeInstallerType(path, installer, newInstallers) || ParseMsix(path, installer, null, newInstallers) || ParseMsi(path, installer, null, newInstallers); @@ -471,8 +470,7 @@ private static bool ParsePackageAndGenerateInstallerNodes(InstallerMetadata inst bool parseMsixResult = false; - bool parseResult = ParsePortableInstallerType(path, baseInstaller, newInstallers) || - ParseExeInstallerType(path, baseInstaller, newInstallers) || + bool parseResult = ParseExeInstallerType(path, baseInstaller, newInstallers) || (parseMsixResult = ParseMsix(path, baseInstaller, manifests, newInstallers)) || ParseMsi(path, baseInstaller, manifests, newInstallers); @@ -619,31 +617,18 @@ private static CompatibilitySet GetCompatibilitySet(InstallerType type) case InstallerType.Inno: case InstallerType.Nullsoft: case InstallerType.Exe: - case InstallerType.Burn: + case InstallerType.Burn: + case InstallerType.Portable: return CompatibilitySet.Exe; case InstallerType.Wix: case InstallerType.Msi: return CompatibilitySet.Msi; case InstallerType.Msix: case InstallerType.Appx: - return CompatibilitySet.Msix; + return CompatibilitySet.Msix; default: return CompatibilitySet.None; } - } - - private static bool ParsePortableInstallerType(string path, Installer baseInstaller, List newInstallers) - { - using (var fileStream = File.Open(path, FileMode.Open)) - { - PEHeaders pEHeaders = new PEHeaders(fileStream); - if (pEHeaders.IsExe == true) - { - return true; - } - } - - return false; } private static bool ParseExeInstallerType(string path, Installer baseInstaller, List newInstallers) diff --git a/src/WingetCreateTests/WingetCreateTests/E2ETests/E2ETests.cs b/src/WingetCreateTests/WingetCreateTests/E2ETests/E2ETests.cs index 96c056d1..a6480495 100644 --- a/src/WingetCreateTests/WingetCreateTests/E2ETests/E2ETests.cs +++ b/src/WingetCreateTests/WingetCreateTests/E2ETests/E2ETests.cs @@ -42,7 +42,8 @@ public void Setup() /// A representing the asynchronous test. [TestCase(TestConstants.TestExePackageIdentifier, TestConstants.TestExeManifest, TestConstants.TestExeInstaller)] [TestCase(TestConstants.TestMsiPackageIdentifier, TestConstants.TestMsiManifest, TestConstants.TestMsiInstaller)] - [TestCase(TestConstants.TestMultifileMsixPackageIdentifier, TestConstants.TestMultifileMsixManifestDir, TestConstants.TestMsixInstaller)] + [TestCase(TestConstants.TestMultifileMsixPackageIdentifier, TestConstants.TestMultifileMsixManifestDir, TestConstants.TestMsixInstaller)] + [TestCase(TestConstants.TestPortablePackageIdentifier, TestConstants.TestPortableManifest, TestConstants.TestExeInstaller)] public async Task SubmitAndUpdateInstaller(string packageId, string manifestName, string installerName) { await this.RunSubmitAndUpdateFlow(packageId, TestUtils.GetTestFile(manifestName), installerName); diff --git a/src/WingetCreateTests/WingetCreateTests/Resources/TestPublisher.Portable.yaml b/src/WingetCreateTests/WingetCreateTests/Resources/TestPublisher.Portable.yaml new file mode 100644 index 00000000..c7b6ee8c --- /dev/null +++ b/src/WingetCreateTests/WingetCreateTests/Resources/TestPublisher.Portable.yaml @@ -0,0 +1,16 @@ +PackageIdentifier: TestPublisher.Portable +PackageVersion: 0.1.2 +PackageName: Test portable app +Publisher: Test publisher +License: MIT +ShortDescription: A manifest used for testing a portable package. +Installers: +- Architecture: x64 + InstallerType: portable + InstallerUrl: https://fakedomain.com/WingetCreateTestExeInstaller.exe + InstallerSha256: 8A052767127A6E2058BAAE03B551A807777BB1B726650E2C7E92C3E92C8DF80D + Commands: + - portableCommand +PackageLocale: en-US +ManifestType: singleton +ManifestVersion: 1.2.0 \ No newline at end of file diff --git a/src/WingetCreateTests/WingetCreateTests/Resources/WingetCreateE2E.PortableTest.yaml b/src/WingetCreateTests/WingetCreateTests/Resources/WingetCreateE2E.PortableTest.yaml new file mode 100644 index 00000000..ed99dc7b --- /dev/null +++ b/src/WingetCreateTests/WingetCreateTests/Resources/WingetCreateE2E.PortableTest.yaml @@ -0,0 +1,26 @@ +PackageIdentifier: WingetCreateE2E.PortableTest +PackageName: PortableTest +PackageVersion: 1.2.3.4 +Publisher: WingetCreateE2E +Author: Microsoft +License: MIT +LicenseUrl: https://github.com/microsoft/winget-create +MinimumOSVersion: 10.0.0.0 +ShortDescription: Testing WingetCreate with a portable exe +PackageLocale: en-US +Tags: + - Windows Package Manager + - winget create + - package manager + - utility + - tool + - test +InstallerType: portable +Installers: + - Architecture: x64 + InstallerUrl: https://fakedomain.com/WingetCreateTestExeInstaller.exe + InstallerSha256: A7803233EEDB6A4B59B3024CCF9292A6FFFB94507DC998AA67C5B745D197A5DC + Commands: + - portableCommand +ManifestType: singleton +ManifestVersion: 1.2.0 \ No newline at end of file diff --git a/src/WingetCreateTests/WingetCreateTests/TestConstants.cs b/src/WingetCreateTests/WingetCreateTests/TestConstants.cs index 79fd10a5..c59bb9e7 100644 --- a/src/WingetCreateTests/WingetCreateTests/TestConstants.cs +++ b/src/WingetCreateTests/WingetCreateTests/TestConstants.cs @@ -53,6 +53,11 @@ public static class TestConstants /// public const string TestMultifileMsixPackageIdentifier = "Multifile.MsixTest"; + /// + /// PackageIdentifier for test portable. + /// + public const string TestPortablePackageIdentifier = "WingetCreateE2E.PortableTest"; + /// /// File name of the test exe manifest. /// @@ -63,6 +68,11 @@ public static class TestConstants /// public const string TestMsiManifest = "WingetCreateE2E.MsiTest.yaml"; + /// + /// File name of the test portable manifest. + /// + public const string TestPortableManifest = "WingetCreateE2E.PortableTest.yaml"; + /// /// Path of the directory with the multifile msix test manifests. /// diff --git a/src/WingetCreateTests/WingetCreateTests/UnitTests/UpdateCommandTests.cs b/src/WingetCreateTests/WingetCreateTests/UnitTests/UpdateCommandTests.cs index fea41e0b..cdf14d91 100644 --- a/src/WingetCreateTests/WingetCreateTests/UnitTests/UpdateCommandTests.cs +++ b/src/WingetCreateTests/WingetCreateTests/UnitTests/UpdateCommandTests.cs @@ -539,6 +539,25 @@ public async Task UpdateResetsVersionSpecificFields() Assert.IsNull(updatedDefaultLocaleManifest.ReleaseNotesUrl, "ReleaseNotesUrl should be null."); } + /// + /// Ensures that updating a portable package preserves the portable installerType. + /// + /// A representing the result of the asynchronous operation. + [Test] + public async Task UpdatePortable() + { + TestUtils.InitializeMockDownloads(TestConstants.TestExeInstaller); + (UpdateCommand command, var initialManifestContent) = GetUpdateCommandAndManifestData("TestPublisher.Portable", null, this.tempPath, null); + var updatedManifests = await RunUpdateCommand(command, initialManifestContent); + Assert.IsNotNull(updatedManifests, "Command should have succeeded"); + + InstallerManifest updatedInstallerManifest = updatedManifests.InstallerManifest; + var updatedInstaller = updatedInstallerManifest.Installers.First(); + + Assert.IsTrue(updatedInstaller.InstallerType == InstallerType.Portable, "InstallerType should be portable"); + Assert.IsTrue(updatedInstaller.Commands[0] == "portableCommand", "Command value should be preserved."); + } + private static (UpdateCommand UpdateCommand, List InitialManifestContent) GetUpdateCommandAndManifestData(string id, string version, string outputDir, IEnumerable installerUrls) { var updateCommand = new UpdateCommand diff --git a/src/WingetCreateTests/WingetCreateTests/WingetCreateTests.csproj b/src/WingetCreateTests/WingetCreateTests/WingetCreateTests.csproj index 53cbe8fa..1319c8f9 100644 --- a/src/WingetCreateTests/WingetCreateTests/WingetCreateTests.csproj +++ b/src/WingetCreateTests/WingetCreateTests/WingetCreateTests.csproj @@ -33,6 +33,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest @@ -78,6 +81,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest From b7e7ddc02ff88f70371e744b3c003281e8c7457c Mon Sep 17 00:00:00 2001 From: Ryan Fu Date: Fri, 22 Jul 2022 14:46:59 -0700 Subject: [PATCH 4/5] remove unused using statements --- src/WingetCreateCore/Common/PackageParser.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/WingetCreateCore/Common/PackageParser.cs b/src/WingetCreateCore/Common/PackageParser.cs index 1873b108..21c5a907 100644 --- a/src/WingetCreateCore/Common/PackageParser.cs +++ b/src/WingetCreateCore/Common/PackageParser.cs @@ -11,9 +11,7 @@ namespace Microsoft.WingetCreateCore using System.IO; using System.Linq; using System.Net.Http; - using System.Reflection.PortableExecutable; using System.Security.Cryptography; - using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Xml; From becded93fe544ea9d9c0a116029722523a0eb609 Mon Sep 17 00:00:00 2001 From: Ryan Fu Date: Wed, 3 Aug 2022 08:44:51 -0700 Subject: [PATCH 5/5] fix resx --- src/WingetCreateCLI/Properties/Resources.resx | 1 + .../WingetCreateTests/UnitTests/CharacterValidationTests.cs | 4 +--- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/WingetCreateCLI/Properties/Resources.resx b/src/WingetCreateCLI/Properties/Resources.resx index 5d6dba41..affddc3d 100644 --- a/src/WingetCreateCLI/Properties/Resources.resx +++ b/src/WingetCreateCLI/Properties/Resources.resx @@ -921,6 +921,7 @@ What is the command alias of the portable package |e.g. nuget| `command alias` refers to the name of the exe file that will be used when running the application from the command line. + Unable to create a reference to the forked repository. This can be caused when the forked repository is behind by too many commits. Sync your fork and try again. diff --git a/src/WingetCreateTests/WingetCreateTests/UnitTests/CharacterValidationTests.cs b/src/WingetCreateTests/WingetCreateTests/UnitTests/CharacterValidationTests.cs index cc123ac2..a040f89c 100644 --- a/src/WingetCreateTests/WingetCreateTests/UnitTests/CharacterValidationTests.cs +++ b/src/WingetCreateTests/WingetCreateTests/UnitTests/CharacterValidationTests.cs @@ -9,7 +9,7 @@ namespace Microsoft.WingetCreateUnitTests using Microsoft.WingetCreateCore; using Microsoft.WingetCreateCore.Models.Singleton; using NUnit.Framework; - + /// /// Unit tests for verifying unicode text and directionality. /// @@ -76,11 +76,9 @@ public void VerfiyNewLineSupport() // we know when written that \r\n and \x85 characters are replaced with \n. var writtenFixed = string.Join('\n', written.Description.Split(new string[] { "\n", "\r\n", "\x85" }, StringSplitOptions.None)); - Assert.AreEqual(writtenFixed, read.Description, $"String {read.Description} had the wrong number of newlines :(."); File.Delete(testManifestFilePath); } } - } }