Skip to content

Commit

Permalink
Improve handling of multiple nested installers
Browse files Browse the repository at this point in the history
  • Loading branch information
mdanish-kh committed May 13, 2023
1 parent 735abc1 commit d406c80
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 4 deletions.
79 changes: 75 additions & 4 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 @@ -468,6 +476,69 @@ private static void PromptForPortableAliasIfApplicable(Installer installer)
}
}

/// <summary>
/// Retrieve nested portable installers that are compatible to have their NestedInstallerFiles merged.
/// </summary>
/// <returns>A list of lists where each list element contains installers that are applicable for merge.</returns>
private static List<List<Installer>> GetNestedPortableInstallersForMerge(InstallerManifest installerManifest)
{
List<List<Installer>> nestedPortablesCompatibleForMerge = new List<List<Installer>>();

foreach (Installer installer in installerManifest.Installers)
{
if (installer.NestedInstallerType == NestedInstallerType.Portable)
{
// If the current installer has the same hash and architecture as another installer, add it to an existing list
// else create a new list
var matchingInstallers = nestedPortablesCompatibleForMerge.SingleOrDefault(i => i.Any(x =>
x.Architecture.Equals(installer.Architecture) &&
x.InstallerSha256.Equals(installer.InstallerSha256)));

if (matchingInstallers != null)
{
matchingInstallers.Add(installer);
}
else
{
nestedPortablesCompatibleForMerge.Add(new List<Installer> { installer });
}
}
}

return nestedPortablesCompatibleForMerge;
}

/// <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 mergeableInstallersList = GetNestedPortableInstallersForMerge(installerManifest);
foreach (List<Installer> 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);
}
}

/// <summary>
/// Prompts for the package identifier and applies the value to all manifests.
/// </summary>
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

0 comments on commit d406c80

Please sign in to comment.