Skip to content
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

Improve handling of multiple nested installers #372

Merged
merged 3 commits into from
May 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 48 additions & 11 deletions src/WingetCreateCLI/Commands/NewCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -172,15 +172,18 @@ public override async Task<bool> Execute()
selectedInstallers = Prompt.MultiSelect(Resources.SelectInstallersFromZip_Message, extractedFiles, minimum: 1).ToList();
}

installerUpdateList.Add(
foreach (var installer in selectedInstallers)
{
installerUpdateList.Add(
new InstallerMetadata
{
InstallerUrl = installerUrl,
PackageFile = packageFile,
RelativeFilePaths = selectedInstallers,
RelativeFilePaths = new List<string> { installer },
IsZipFile = true,
ExtractedDirectory = extractDirectory,
});
}
}
else
{
Expand Down Expand Up @@ -270,6 +273,7 @@ private static void PromptPropertiesAndDisplayManifests(Manifests manifests)
PromptRequiredProperties(manifests.VersionManifest);
PromptRequiredProperties(manifests.InstallerManifest, manifests.VersionManifest);
PromptRequiredProperties(manifests.DefaultLocaleManifest, manifests.VersionManifest);
MergeNestedInstallerFilesIfApplicable(manifests.InstallerManifest);

Console.WriteLine();
if (Prompt.Confirm(Resources.ModifyOptionalDefaultLocaleFields_Message))
Expand Down Expand Up @@ -359,6 +363,12 @@ private static void PromptInstallerProperties<T>(T manifest, PropertyInfo proper
List<Installer> installers = new List<Installer>((ICollection<Installer>)property.GetValue(manifest));
foreach (var installer in installers)
{
Console.WriteLine();
if (installer.InstallerType == InstallerType.Zip)
{
Logger.InfoLocalized(nameof(Resources.NestedInstallerParsing_HelpText), installer.NestedInstallerFiles.First().RelativeFilePath, installer.InstallerUrl);
}

var installerProperties = installer.GetType().GetProperties().ToList();

var requiredInstallerProperties = installerProperties
Expand All @@ -369,8 +379,6 @@ private static void PromptInstallerProperties<T>(T manifest, PropertyInfo proper
// If the installerType is EXE, prompt the user for whether the package is a portable
if (installer.InstallerType == InstallerType.Exe || installer.NestedInstallerType == NestedInstallerType.Exe)
{
Console.WriteLine();

if (!PromptForPortableExe(installer))
{
// If we know the installertype is EXE, prompt the user for installer switches (silent and silentwithprogress)
Expand Down Expand Up @@ -449,22 +457,51 @@ private static void PromptForPortableAliasIfApplicable(Installer installer)

if (!string.IsNullOrEmpty(portableCommandAlias))
{
List<string> portableCommands = new List<string> { portableCommandAlias };
List<string> portableCommands = new List<string> { portableCommandAlias.Trim() };
installer.Commands = portableCommands;
}
}

if (installer.NestedInstallerType == NestedInstallerType.Portable)
{
foreach (NestedInstallerFile nestedInstallerFile in installer.NestedInstallerFiles)
string portableCommandAlias = Prompt.Input<string>(Resources.PortableCommandAlias_Message);

if (!string.IsNullOrEmpty(portableCommandAlias))
{
string portableCommandAlias = Prompt.Input<string>(Resources.PortableCommandAlias_Message);
installer.NestedInstallerFiles.First().PortableCommandAlias = portableCommandAlias.Trim();
}
}
}

if (!string.IsNullOrEmpty(portableCommandAlias))
{
nestedInstallerFile.PortableCommandAlias = portableCommandAlias;
}
/// <summary>
/// Merge nested installer files into a single installer if:
/// 1. Matching installers have NestedInstallerType: portable.
/// 2. Matching installers have the same architecture.
/// 3. Matching installers have the same hash.
/// </summary>
private static void MergeNestedInstallerFilesIfApplicable(InstallerManifest installerManifest)
{
var nestedPortableInstallers = installerManifest.Installers.Where(i => i.NestedInstallerType == NestedInstallerType.Portable).ToList();
var mergeableInstallersList = nestedPortableInstallers.GroupBy(i => i.Architecture + i.InstallerSha256).ToList();
foreach (var installers in mergeableInstallersList)
{
// First installer in each list is used to merge into
var installerToMergeInto = installers.First();

// Remove the first installer from the manifest, will be added back once the merge is complete
installerManifest.Installers.Remove(installerToMergeInto);

var installersToMerge = installers.Skip(1).ToList();

// Append NestedInstallerFiles of other matching installers and remove them from the manifest
foreach (var installer in installersToMerge)
{
installerToMergeInto.NestedInstallerFiles.AddRange(installer.NestedInstallerFiles);
installerManifest.Installers.Remove(installer);
}

// Add the installer with the merged nested installer files back to the manifest
installerManifest.Installers.Add(installerToMergeInto);
}
}

Expand Down
11 changes: 11 additions & 0 deletions src/WingetCreateCLI/Properties/Resources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/WingetCreateCLI/Properties/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -958,6 +958,11 @@
<data name="InvocationParameter_KeywordDescription" xml:space="preserve">
<value>The optional parameter for invocable files</value>
</data>
<data name="NestedInstallerParsing_HelpText" xml:space="preserve">
<value>Parsing nested installer '{0}' from {1}</value>
<comment>{0} - will be replaced with RelativeFilePath of the nested installer
{1} - will be replaced by the InstallerUrl</comment>
</data>
<data name="NestedInstallerFileNotFound_Error" xml:space="preserve">
<value>Nested installer not found in zip archive: {0}</value>
<comment>{0} - represents the relative file path of the nested installer file.</comment>
Expand Down