Skip to content

Commit

Permalink
Add modify feature to interactive update (#171)
Browse files Browse the repository at this point in the history
* initial commit of interactive modify

* Finish implementation of interactive modify

* remove unneeded using statement

* addres PR comments

* update architecture

* use getfilename in basecommand.cs
  • Loading branch information
ryfu-msft authored Sep 22, 2021
1 parent f4af949 commit 853a8bf
Show file tree
Hide file tree
Showing 9 changed files with 363 additions and 203 deletions.
17 changes: 7 additions & 10 deletions src/WingetCreateCLI/Commands/BaseCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,6 @@ protected static string SaveManifestDirToLocalPath(
DefaultLocaleManifest defaultLocaleManifest = manifests.DefaultLocaleManifest;
List<LocaleManifest> localeManifests = manifests.LocaleManifests;

string defaultPackageLocale = defaultLocaleManifest.PackageLocale;
string version = versionManifest.PackageVersion;
string packageId = versionManifest.PackageIdentifier;
string manifestDir = Utils.GetAppManifestDirPath(packageId, version);
Expand All @@ -167,17 +166,17 @@ protected static string SaveManifestDirToLocalPath(
fullDirPath = Path.Combine(outputDir, manifestDir);
}

string versionManifestFileName = $"{packageId}.yaml";
string installerManifestFileName = $"{packageId}.installer.yaml";
string defaultLocaleManifestFileName = $"{packageId}.locale.{defaultPackageLocale}.yaml";
string versionManifestFileName = Manifests.GetFileName(manifests.VersionManifest);
string installerManifestFileName = Manifests.GetFileName(manifests.InstallerManifest);
string defaultLocaleManifestFileName = Manifests.GetFileName(manifests.DefaultLocaleManifest);

File.WriteAllText(Path.Combine(fullDirPath, versionManifestFileName), versionManifest.ToYaml());
File.WriteAllText(Path.Combine(fullDirPath, installerManifestFileName), installerManifest.ToYaml());
File.WriteAllText(Path.Combine(fullDirPath, defaultLocaleManifestFileName), defaultLocaleManifest.ToYaml());

foreach (LocaleManifest localeManifest in localeManifests)
{
string localeManifestFileName = $"{packageId}.locale.{localeManifest.PackageLocale}.yaml";
string localeManifestFileName = Manifests.GetFileName(localeManifest);
File.WriteAllText(Path.Combine(fullDirPath, localeManifestFileName), localeManifest.ToYaml());
}

Expand All @@ -195,11 +194,9 @@ protected static string SaveManifestDirToLocalPath(
/// <returns>A boolean value indicating whether validation of the manifests was successful.</returns>
protected static bool ValidateManifestsInTempDir(Manifests manifests)
{
string packageId = manifests.VersionManifest.PackageIdentifier;
string defaultPackageLocale = manifests.DefaultLocaleManifest.PackageLocale;
string versionManifestFileName = $"{packageId}.yaml";
string installerManifestFileName = $"{packageId}.installer.yaml";
string defaultLocaleManifestFileName = $"{packageId}.locale.{defaultPackageLocale}.yaml";
string versionManifestFileName = Manifests.GetFileName(manifests.VersionManifest);
string installerManifestFileName = Manifests.GetFileName(manifests.InstallerManifest);
string defaultLocaleManifestFileName = Manifests.GetFileName(manifests.DefaultLocaleManifest);

string randomDirPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
Directory.CreateDirectory(randomDirPath);
Expand Down
124 changes: 1 addition & 123 deletions src/WingetCreateCLI/Commands/NewCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ private static void PromptPropertiesAndDisplayManifests(Manifests manifests)

if (Prompt.Confirm(Resources.ModifyOptionalInstallerFields_Message))
{
DisplayInstallersAsMenuSelection(manifests.InstallerManifest);
PromptHelper.DisplayInstallersAsMenuSelection(manifests.InstallerManifest);
}

Console.WriteLine();
Expand Down Expand Up @@ -252,128 +252,6 @@ private static void PromptRequiredProperties<T>(T manifest, VersionManifest vers
}
}

/// <summary>
/// Displays all installers from an Installer manifest as a selection menu.
/// </summary>
private static void DisplayInstallersAsMenuSelection(InstallerManifest installerManifest)
{
Console.Clear();

while (true)
{
List<string> selectionList = GenerateInstallerSelectionList(installerManifest.Installers, out Dictionary<string, Installer> installerSelectionMap);
var selectedItem = Prompt.Select(Resources.SelectInstallerToEdit_Message, selectionList);

if (selectedItem == Resources.None_MenuItem)
{
break;
}
else if (selectedItem == Resources.AllInstallers_MenuItem)
{
Installer installerCopy = new Installer();
PromptHelper.PromptPropertiesWithMenu(installerCopy, Resources.None_MenuItem);
ApplyChangesToIndividualInstallers(installerCopy, installerManifest.Installers);
}
else if (selectedItem == Resources.DisplayPreview_MenuItem)
{
Console.Clear();
Console.WriteLine();
Logger.InfoLocalized(nameof(Resources.DisplayPreviewOfSelectedInstaller_Message));
var serializer = Serialization.CreateSerializer();
string installerString = serializer.Serialize(installerManifest);
Console.WriteLine(installerString);
Console.WriteLine();
}
else
{
Installer selectedInstaller = installerSelectionMap[selectedItem];
PromptHelper.PromptPropertiesWithMenu(selectedInstaller, Resources.None_MenuItem);
}
}
}

private static List<string> GenerateInstallerSelectionList(List<Installer> installers, out Dictionary<string, Installer> installerSelectionMap)
{
installerSelectionMap = new Dictionary<string, Installer>();
int index = 1;
foreach (Installer installer in installers)
{
var installerTuple = string.Join(" | ", new[]
{
installer.Architecture.ToEnumAttributeValue(),
installer.InstallerType.ToEnumAttributeValue(),
installer.Scope?.ToEnumAttributeValue(),
installer.InstallerLocale,
installer.InstallerUrl,
}.Where(s => !string.IsNullOrEmpty(s)));

var installerMenuItem = string.Format(Resources.InstallerSelection_MenuItem, index, installerTuple);
installerSelectionMap.Add(installerMenuItem, installer);
index++;
}

List<string> selectionList = new List<string>() { Resources.AllInstallers_MenuItem };
selectionList.AddRange(installerSelectionMap.Keys);
selectionList.AddRange(new[] { Resources.DisplayPreview_MenuItem, Resources.None_MenuItem });
return selectionList;
}

private static void ApplyChangesToIndividualInstallers(Installer installerCopy, List<Installer> installers)
{
// Skip architecture as the default value when instantiated is x86.
var modifiedFields = installerCopy.GetType().GetProperties()
.Select(prop => prop)
.Where(pi =>
pi.GetValue(installerCopy) != null &&
pi.Name != nameof(Installer.Architecture) &&
pi.Name != nameof(Installer.AdditionalProperties));

foreach (var field in modifiedFields)
{
foreach (Installer installer in installers)
{
var fieldValue = field.GetValue(installerCopy);
var prop = installer.GetType().GetProperty(field.Name);
if (prop.PropertyType.IsValueType)
{
prop.SetValue(installer, fieldValue);
}
else if (fieldValue is IList list)
{
prop.SetValue(installer, list.DeepClone());
}
else if (fieldValue is Dependencies dependencies)
{
ApplyDependencyChangesToInstaller(dependencies, installer);
}
}
}
}

/// <summary>
/// Clones any non-null property values of the dependencies object and assigns them to the provided installer object.
/// </summary>
/// <param name="dependencies">Dependencies object with new values.</param>
/// <param name="installer">Installer object to assign new changes to.</param>
private static void ApplyDependencyChangesToInstaller(Dependencies dependencies, Installer installer)
{
var modifiedFields = dependencies.GetType().GetProperties()
.Select(prop => prop)
.Where(pi => pi.GetValue(dependencies) != null);

foreach (var field in modifiedFields.Where(f => f.Name != nameof(Installer.AdditionalProperties)))
{
var fieldValue = field.GetValue(dependencies);
installer.Dependencies ??= new Dependencies();
var prop = installer.Dependencies.GetType().GetProperty(field.Name);

if (fieldValue is IList list)
{
prop.SetValue(installer.Dependencies, list.DeepClone());
}
}
}

private static void PromptOptionalProperties<T>(T manifest)
{
var properties = manifest.GetType().GetProperties().ToList();
Expand Down
58 changes: 55 additions & 3 deletions src/WingetCreateCLI/Commands/UpdateCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,54 @@ private static bool VerifyUpdatedInstallerHash(Manifests oldManifest, InstallerM
return newHashes.Except(oldHashes).Any();
}

private static void DisplayManifestsAsMenuSelection(Manifests manifests)
{
Console.Clear();
string versionFileName = Manifests.GetFileName(manifests.VersionManifest);
string installerFileName = Manifests.GetFileName(manifests.InstallerManifest);
string versionManifestMenuItem = $"{manifests.VersionManifest.ManifestType.ToUpper()}: " + versionFileName;
string installerManifestMenuItem = $"{manifests.InstallerManifest.ManifestType.ToUpper()}: " + installerFileName;

while (true)
{
// Need to update locale manifest file name each time as PackageLocale can change
string defaultLocaleMenuItem = $"{manifests.DefaultLocaleManifest.ManifestType.ToUpper()}: " + Manifests.GetFileName(manifests.DefaultLocaleManifest);
List<string> selectionList = new List<string> { versionManifestMenuItem, installerManifestMenuItem, defaultLocaleMenuItem };
Dictionary<string, LocaleManifest> localeManifestMap = new Dictionary<string, LocaleManifest>();
foreach (LocaleManifest localeManifest in manifests.LocaleManifests)
{
string localeManifestFileName = $"{localeManifest.ManifestType.ToUpper()}: " + Manifests.GetFileName(localeManifest);
localeManifestMap.Add(localeManifestFileName, localeManifest);
selectionList.Add(localeManifestFileName);
}

selectionList.Add(Resources.Done_MenuItem);
var selectedItem = Prompt.Select(Resources.SelectManifestToEdit_Message, selectionList);

if (selectedItem == versionManifestMenuItem)
{
PromptHelper.PromptPropertiesWithMenu(manifests.VersionManifest, Resources.SaveAndExit_MenuItem, versionFileName);
}
else if (selectedItem == installerManifestMenuItem)
{
PromptHelper.PromptPropertiesWithMenu(manifests.InstallerManifest, Resources.SaveAndExit_MenuItem, installerFileName);
}
else if (selectedItem == defaultLocaleMenuItem)
{
PromptHelper.PromptPropertiesWithMenu(manifests.DefaultLocaleManifest, Resources.SaveAndExit_MenuItem, Manifests.GetFileName(manifests.DefaultLocaleManifest));
}
else if (selectedItem == Resources.Done_MenuItem)
{
break;
}
else
{
var selectedLocaleManifest = localeManifestMap[selectedItem];
PromptHelper.PromptPropertiesWithMenu(selectedLocaleManifest, Resources.SaveAndExit_MenuItem, Manifests.GetFileName(selectedLocaleManifest));
}
}
}

/// <summary>
/// Update flow for interactively updating the manifest.
/// </summary>s
Expand All @@ -393,7 +441,12 @@ private async Task<Manifests> UpdateManifestsInteractively(Manifests manifests)
ValidateManifestsInTempDir(manifests);
}
while (Prompt.Confirm(Resources.DiscardUpdateAndStartOver_Message));
Console.Clear();

if (Prompt.Confirm(Resources.EditManifests_Message))
{
DisplayManifestsAsMenuSelection(manifests);
}

return manifests;
}

Expand All @@ -404,14 +457,13 @@ private async Task<Manifests> UpdateManifestsInteractively(Manifests manifests)
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
private async Task UpdateInstallersInteractively(List<Installer> existingInstallers)
{
var serializer = Serialization.CreateSerializer();
int numOfExistingInstallers = existingInstallers.Count;
int index = 1;

foreach (var installer in existingInstallers)
{
Logger.InfoLocalized(nameof(Resources.UpdatingInstallerOutOfTotal_Message), index, numOfExistingInstallers);
Console.WriteLine(serializer.Serialize(installer));
Console.WriteLine(Serialization.Serialize(installer));
await this.UpdateSingleInstallerInteractively(installer);
index++;
}
Expand Down
Loading

0 comments on commit 853a8bf

Please sign in to comment.