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

Add architecture override option to Update command #206

Merged
merged 10 commits into from
Dec 1, 2021
73 changes: 72 additions & 1 deletion src/WingetCreateCLI/Commands/UpdateCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ namespace Microsoft.WingetCreateCLI.Commands
using Microsoft.WingetCreateCLI.Telemetry;
using Microsoft.WingetCreateCLI.Telemetry.Events;
using Microsoft.WingetCreateCore;
using Microsoft.WingetCreateCore.Common;
using Microsoft.WingetCreateCore.Common.Exceptions;
using Microsoft.WingetCreateCore.Models;
using Microsoft.WingetCreateCore.Models.DefaultLocale;
Expand All @@ -40,6 +41,7 @@ public static IEnumerable<Example> Examples
{
yield return new Example(Resources.Example_UpdateCommand_SearchAndUpdateVersionAndInstallerURL, new UpdateCommand { Id = "<PackageIdentifier>", InstallerUrls = new string[] { "<InstallerUrl1>", "<InstallerUrl2>" }, Version = "<Version>" });
yield return new Example(Resources.Example_UpdateCommand_SaveAndPublish, new UpdateCommand { Id = "<PackageIdentifier>", Version = "<Version>", OutputDir = "<OutputDirectory>", GitHubToken = "<GitHubPersonalAccessToken>" });
yield return new Example(Resources.Example_UpdateCommand_OverrideArchitecture, new UpdateCommand { Id = "<PackageIdentifier>", InstallerUrls = new string[] { "<InstallerUrl1>|<InstallerArchitecture>" }, Version = "<Version>" });
ryfu-msft marked this conversation as resolved.
Show resolved Hide resolved
}
}

Expand Down Expand Up @@ -220,6 +222,20 @@ public async Task<Manifests> UpdateManifestsAutonomously(Manifests manifests)
this.InstallerUrls = installerManifest.Installers.Select(i => i.InstallerUrl).Distinct().ToArray();
}

// Parse out architecture overrides from installer URLs and reassign.
this.InstallerUrls = this.ParseInstallerUrlsForArchOverride(this.InstallerUrls.ToList(), out Dictionary<string, InstallerArchitecture> installerArchOverrideMap);

// If InstallerUrls is null, there was an issue when parsing for architecture override.
if (this.InstallerUrls == null)
{
return null;
}

foreach (var key in installerArchOverrideMap.Keys)
{
Logger.Warn($"Overriding {key} with architecture {installerArchOverrideMap[key]}");
}

// We only support updates with same number of installer URLs
if (this.InstallerUrls.Distinct().Count() != installerManifest.Installers.Select(i => i.InstallerUrl).Distinct().Count())
{
Expand All @@ -243,7 +259,8 @@ public async Task<Manifests> UpdateManifestsAutonomously(Manifests manifests)
this.InstallerUrls,
packageFiles,
out detectedArchOfInstallers,
out newInstallers);
out newInstallers,
installerArchOverrideMap);

DisplayMismatchedArchitectures(detectedArchOfInstallers);
}
Expand All @@ -267,6 +284,12 @@ public async Task<Manifests> UpdateManifestsAutonomously(Manifests manifests)
Logger.ErrorLocalized(nameof(Resources.NewInstallerUrlMustMatchExisting_Message));
installerMatchException.MultipleMatchedInstallers.ForEach(i => Logger.ErrorLocalized(nameof(Resources.UnmatchedInstaller_Error), i.Architecture, i.InstallerType, i.InstallerUrl));
installerMatchException.UnmatchedInstallers.ForEach(i => Logger.ErrorLocalized(nameof(Resources.MultipleMatchedInstaller_Error), i.Architecture, i.InstallerType, i.InstallerUrl));

if (installerMatchException.IsArchitectureOverride)
{
Logger.WarnLocalized(nameof(Resources.ArchitectureOverride_Warning));
}

return null;
}

Expand Down Expand Up @@ -419,6 +442,54 @@ private static void DisplayManifestsAsMenuSelection(Manifests manifests)
}
}

/// <summary>
/// Parse out architecture overrides included in the installer URLs and returns the parsed list of installer URLs.
/// </summary>
/// <param name="installerUrlsToBeParsed">List of installer URLs to be parsed for architecture overrides.</param>
/// <param name="installerArchOverrideMap">Dictionary that maps the overridden architecture to the installer URL.</param>
/// <returns>List of parsed installer URLs without appended architecture overrides.</returns>
private List<string> ParseInstallerUrlsForArchOverride(
List<string> installerUrlsToBeParsed,
out Dictionary<string, InstallerArchitecture> installerArchOverrideMap)
{
installerArchOverrideMap = new Dictionary<string, InstallerArchitecture>();
List<string> parsedInstallerUrls = new List<string>();
foreach (string item in installerUrlsToBeParsed)
{
if (item.Contains('|'))
{
// '|' character indicates that an architecture override can be parsed from the installer.
string[] installerUrlOverride = item.Split('|');

if (installerUrlOverride.Length > 2)
{
Logger.ErrorLocalized(nameof(Resources.MultipleArchitectureOverride_Error));
return null;
}

string installerUrl = installerUrlOverride[0];
string overrideArchString = installerUrlOverride[1];
InstallerArchitecture? overrideArch = overrideArchString.ToEnumOrDefault<InstallerArchitecture>();
if (overrideArch.HasValue)
{
parsedInstallerUrls.Add(installerUrl);
installerArchOverrideMap.Add(installerUrl, overrideArch.Value);
}
else
{
Logger.ErrorLocalized(nameof(Resources.UnableToParseArchOverride_Error), overrideArchString);
return null;
}
}
else
{
parsedInstallerUrls.Add(item);
}
}

return parsedInstallerUrls;
}

/// <summary>
/// Update flow for interactively updating the manifest.
/// </summary>s
Expand Down
36 changes: 36 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.

14 changes: 14 additions & 0 deletions src/WingetCreateCLI/Properties/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -786,4 +786,18 @@
<data name="DownloadConnectionTimeout_Error" xml:space="preserve">
<value>Unable to complete the download request as the connection has timed out. Please verify your installer URL and try again.</value>
</data>
<data name="ArchitectureOverride_Warning" xml:space="preserve">
<value>If the installer you provided fails to match an existing installer even when overriding the architecture, you may need to edit the existing manifest manually. Make sure that the existing manifest has a single installer that matches the overriding architecture and installer type of the new installer. To modify an existing manifest, use the '--interactive' flag with the update command and submit the new changes. Once the changes are published, please try again.</value>
<comment>'--interactive' refers to a flag that can be included with the command-line arguments for this tool.</comment>
</data>
<data name="MultipleArchitectureOverride_Error" xml:space="preserve">
<value>Multiple architectures detected. Only one architecture can be specified for an override.</value>
</data>
<data name="UnableToParseArchOverride_Error" xml:space="preserve">
<value>Unable to parse the specified override architecture {0}.</value>
<comment>{0} - represents the override architecture that failed to parse.</comment>
</data>
<data name="Example_UpdateCommand_OverrideArchitecture" xml:space="preserve">
<value>Override the architecture of an installer</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ public class InstallerMatchException : Exception
/// </summary>
/// <param name="multipleMatchedInstaller">List of installers with multiple matches.</param>
/// <param name="unmatchedInstallers">List of installers with no matches.</param>
public InstallerMatchException(List<Installer> multipleMatchedInstaller, List<Installer> unmatchedInstallers)
/// <param name="isArchitectureOverride">Architecture of an installer was overridden by the user.</param>
public InstallerMatchException(List<Installer> multipleMatchedInstaller, List<Installer> unmatchedInstallers, bool isArchitectureOverride)
{
this.MultipleMatchedInstallers = multipleMatchedInstaller;
this.UnmatchedInstallers = unmatchedInstallers;
this.IsArchitectureOverride = isArchitectureOverride;
}

/// <summary>
Expand All @@ -32,5 +34,10 @@ public InstallerMatchException(List<Installer> multipleMatchedInstaller, List<In
/// Gets the list of installers with no matches.
/// </summary>
public List<Installer> UnmatchedInstallers { get; private set; }

/// <summary>
/// Gets a value indicating whether the user overrode the architecture of installer to be updated.
/// </summary>
public bool IsArchitectureOverride { get; private set; }
}
}
Loading