Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
2 changes: 1 addition & 1 deletion src/UniGetUI.Core.Tools/SerializationHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
var value = _convertXmlNode(childElement);
if (!children.ContainsKey(childElement.Name))
children[childElement.Name] = new List<object>();
children[childElement.Name].Add(value);

Check warning on line 62 in src/UniGetUI.Core.Tools/SerializationHelpers.cs

View workflow job for this annotation

GitHub Actions / test-codebase

Possible null reference argument for parameter 'item' in 'void List<object>.Add(object item)'.
}
}

Expand All @@ -83,7 +83,7 @@
{
TypeInfoResolver = new DefaultJsonTypeInfoResolver(),
AllowTrailingCommas = true,
WriteIndented = true,
WriteIndented = false,
};
}

Expand Down
203 changes: 122 additions & 81 deletions src/UniGetUI.PackageEngine.Serializable/InstallOptions.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,48 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using UniGetUI.Core.Data;

namespace UniGetUI.PackageEngine.Serializable
{
public class InstallOptions: SerializableComponent<InstallOptions>
{
private readonly IReadOnlyDictionary<string, bool> DefaultBoolValues = new Dictionary<string, bool>()
{ // OverridesNextLevelOpts is deliberately skipped here
{ "SkipHashCheck", false },
{ "InteractiveInstallation", false },
{ "RunAsAdministrator", false },
{ "PreRelease", false },
{ "SkipMinorUpdates", false },
{ "RemoveDataOnUninstall", false },
{ "UninstallPreviousVersionsOnUpdate", false },
{ "AbortOnPreInstallFail", true },
{ "AbortOnPreUpdateFail", true },
{ "AbortOnPreUninstallFail", true },
};

private readonly IReadOnlyDictionary<string, string> DefaultStringValues = new Dictionary<string, string>()
{
{"Architecture", ""},
{"InstallationScope", ""},
{"CustomInstallLocation", ""},
{"Version", ""},
{"PreInstallCommand", ""},
{"PostInstallCommand", ""},
{"PreUpdateCommand", ""},
{"PostUpdateCommand", ""},
{"PreUninstallCommand", ""},
{"PostUninstallCommand", ""},
};

private readonly IReadOnlyList<string> DefaultListValues = new List<string>()
{
"CustomParameters_Install",
"CustomParameters_Update",
"CustomParameters_Uninstall",
"KillBeforeOperation",
};


public bool SkipHashCheck { get; set; }
public bool InteractiveInstallation { get; set; }
public bool RunAsAdministrator { get; set; }
Expand All @@ -17,7 +55,6 @@ public class InstallOptions: SerializableComponent<InstallOptions>
public string CustomInstallLocation { get; set; } = "";
public string Version { get; set; } = "";
public bool SkipMinorUpdates { get; set; }
public bool OverridesNextLevelOpts { get; set; }
public bool RemoveDataOnUninstall { get; set; }
public bool UninstallPreviousVersionsOnUpdate { get; set; }
public List<string> KillBeforeOperation { get; set; } = [];
Expand All @@ -32,53 +69,54 @@ public class InstallOptions: SerializableComponent<InstallOptions>
public string PostUninstallCommand { get; set; } = "";
public bool AbortOnPreUninstallFail { get; set; } = true;

public bool OverridesNextLevelOpts { get; set; }

public override InstallOptions Copy()
{
return new()
{
SkipHashCheck = SkipHashCheck,
Architecture = Architecture,
CustomInstallLocation = CustomInstallLocation,
CustomParameters_Install = CustomParameters_Install.ToList(),
CustomParameters_Update = CustomParameters_Update.ToList(),
CustomParameters_Uninstall = CustomParameters_Uninstall.ToList(),
InstallationScope = InstallationScope,
InteractiveInstallation = InteractiveInstallation,
PreRelease = PreRelease,
RunAsAdministrator = RunAsAdministrator,
Version = Version,
SkipMinorUpdates = SkipMinorUpdates,
OverridesNextLevelOpts = OverridesNextLevelOpts,
RemoveDataOnUninstall = RemoveDataOnUninstall,
KillBeforeOperation = KillBeforeOperation.ToList(),
PreInstallCommand = PreInstallCommand,
PreUpdateCommand = PreUpdateCommand,
PreUninstallCommand = PreUninstallCommand,
PostInstallCommand = PostInstallCommand,
PostUpdateCommand = PostUpdateCommand,
PostUninstallCommand = PostUninstallCommand,
AbortOnPreInstallFail = AbortOnPreInstallFail,
AbortOnPreUpdateFail = AbortOnPreUpdateFail,
AbortOnPreUninstallFail = AbortOnPreUninstallFail,
UninstallPreviousVersionsOnUpdate = UninstallPreviousVersionsOnUpdate,
};
var copy = new InstallOptions();

foreach (var (boolKey, _) in DefaultBoolValues)
copy.SetValueToProperty(boolKey, GetValueFromProperty<bool>(boolKey));

foreach (var (stringKey, _) in DefaultStringValues)
copy.SetValueToProperty(stringKey, GetValueFromProperty<string>(stringKey));

foreach (var listKey in DefaultListValues)
copy.SetValueToProperty(listKey, GetValueFromProperty<IReadOnlyList<string>>(listKey).ToList());
Comment thread
marticliment marked this conversation as resolved.

// Handle non-automated OverridesNextLevelOpts
copy.OverridesNextLevelOpts = OverridesNextLevelOpts;
return copy;
}

public void SetValueToProperty<T>(string name, T value)
{
var property = this.GetType().GetProperty(name);
property?.SetValue(this, value);
}

public T GetValueFromProperty<T>(string name)
{
var property = this.GetType().GetProperty(name);
return (T)(property?.GetValue(this) ?? throw new InvalidDataException($"Invalid datatype for property {name} (expected {nameof(T)})"));
}

Comment thread
marticliment marked this conversation as resolved.
public override void LoadFromJson(JsonNode data)
{
// RemoveDataOnUninstall should not be loaded from disk
foreach (var (boolKey, defValue) in DefaultBoolValues)
{
// RemoveDataOnUninstall should not be loaded from disk
if(boolKey == "RemoveDataOnUninstall") continue;
SetValueToProperty(boolKey, data[boolKey]?.GetVal<bool>() ?? defValue);
}

this.SkipHashCheck = data[nameof(SkipHashCheck)]?.GetVal<bool>() ?? false;
this.InteractiveInstallation = data[nameof(InteractiveInstallation)]?.GetVal<bool>() ?? false;
this.RunAsAdministrator = data[nameof(RunAsAdministrator)]?.GetVal<bool>() ?? false;
this.Architecture = data[nameof(Architecture)]?.GetVal<string>() ?? "";
this.InstallationScope = data[nameof(InstallationScope)]?.GetVal<string>() ?? "";
foreach (var (stringKey, defValue) in DefaultStringValues)
SetValueToProperty(stringKey, data[stringKey]?.GetVal<string>() ?? defValue);

this.CustomParameters_Install = ReadArrayFromJson(data, nameof(CustomParameters_Install));
this.CustomParameters_Update = ReadArrayFromJson(data, nameof(CustomParameters_Update));
this.CustomParameters_Uninstall = ReadArrayFromJson(data, nameof(CustomParameters_Uninstall));
foreach (var listKey in DefaultListValues)
SetValueToProperty(listKey, ReadArrayFromJson(data, listKey));

// Handle case where setting has not been migrated yet
if (this.CustomParameters_Install.Count is 0 &&
this.CustomParameters_Update.Count is 0 &&
this.CustomParameters_Uninstall.Count is 0 &&
Expand All @@ -89,28 +127,42 @@ this.CustomParameters_Uninstall.Count is 0 &&
this.CustomParameters_Uninstall = ReadArrayFromJson(data, "CustomParameters");
}

this.KillBeforeOperation = ReadArrayFromJson(data, nameof(KillBeforeOperation));
this.PreRelease = data[nameof(PreRelease)]?.GetVal<bool>() ?? false;
this.CustomInstallLocation = data[nameof(CustomInstallLocation)]?.GetVal<string>() ?? "";
this.Version = data[nameof(Version)]?.GetVal<string>() ?? "";
this.SkipMinorUpdates = data[nameof(SkipMinorUpdates)]?.GetVal<bool>() ?? false;
this.UninstallPreviousVersionsOnUpdate = data[nameof(UninstallPreviousVersionsOnUpdate)]?.GetVal<bool>() ?? false;

this.PreInstallCommand = data[nameof(PreInstallCommand)]?.GetVal<string>() ?? "";
this.PreUpdateCommand = data[nameof(PreUpdateCommand)]?.GetVal<string>() ?? "";
this.PreUninstallCommand = data[nameof(PreUninstallCommand)]?.GetVal<string>() ?? "";
this.PostInstallCommand = data[nameof(PostInstallCommand)]?.GetVal<string>() ?? "";
this.PostUpdateCommand = data[nameof(PostUpdateCommand)]?.GetVal<string>() ?? "";
this.PostUninstallCommand = data[nameof(PostUninstallCommand)]?.GetVal<string>() ?? "";
this.AbortOnPreInstallFail = data[nameof(AbortOnPreInstallFail)]?.GetVal<bool>() ?? true;
this.AbortOnPreUpdateFail = data[nameof(AbortOnPreUpdateFail)]?.GetVal<bool>() ?? true;
this.AbortOnPreUninstallFail = data[nameof(AbortOnPreUninstallFail)]?.GetVal<bool>() ?? true;

// if OverridesNextLevelOpts is not found on the JSON, set it to true or false depending
// on whether the current settings instances are different from the default values.
// This entry shall be checked the last one, to ensure all other properties are set
this.OverridesNextLevelOpts =
data[nameof(OverridesNextLevelOpts)]?.GetValue<bool>() ?? DiffersFromDefault();
this.OverridesNextLevelOpts = data[nameof(OverridesNextLevelOpts)]?.GetValue<bool>() ?? DiffersFromDefault();
}

public override JsonNode AsJsonNode()
{
JsonObject obj = new();

if (OverridesNextLevelOpts is not false)
obj.Add(nameof(OverridesNextLevelOpts), OverridesNextLevelOpts);

foreach (var (boolKey, defValue) in DefaultBoolValues)
{
bool currentValue = GetValueFromProperty<bool>(boolKey);
if (currentValue != defValue) obj.Add(boolKey, currentValue);
}

foreach (var (stringKey, defValue) in DefaultStringValues)
{
string currentValue = GetValueFromProperty<string>(stringKey);
if (currentValue != defValue) obj.Add(stringKey, currentValue);
}

foreach (var listKey in DefaultListValues)
{
IReadOnlyList<string> currentValue = GetValueFromProperty<IReadOnlyList<string>>(listKey);

if (currentValue.Where(x => x.Any()).Any())
{
obj.Add(listKey, new JsonArray(currentValue.Select(x => JsonValue.Create(x) as JsonNode).ToArray()));
}
}

return obj;
}

private static List<string> ReadArrayFromJson(JsonNode data, string name)
Expand All @@ -124,30 +176,19 @@ private static List<string> ReadArrayFromJson(JsonNode data, string name)

public bool DiffersFromDefault()
{
return SkipHashCheck is not false ||
InteractiveInstallation is not false ||
RunAsAdministrator is not false ||
PreRelease is not false ||
SkipMinorUpdates is not false ||
Architecture.Any() ||
InstallationScope.Any() ||
CustomParameters_Install.Where(x => x.Any()).Any() ||
CustomParameters_Update.Where(x => x.Any()).Any() ||
CustomParameters_Uninstall.Where(x => x.Any()).Any() ||
KillBeforeOperation.Where(x => x.Any()).Any() ||
CustomInstallLocation.Any() ||
RemoveDataOnUninstall is not false ||
Version.Any() ||
PreInstallCommand.Any() ||
PostInstallCommand.Any() ||
AbortOnPreInstallFail is not true ||
PreUpdateCommand.Any() ||
PostUpdateCommand.Any() ||
AbortOnPreUpdateFail is not true ||
PreUninstallCommand.Any() ||
PostUninstallCommand.Any() ||
UninstallPreviousVersionsOnUpdate is not false ||
AbortOnPreUninstallFail is not true;
foreach (var (boolKey, defValue) in DefaultBoolValues)
if (GetValueFromProperty<bool>(boolKey) != defValue) return true;

foreach (var (stringKey, defValue) in DefaultStringValues)
if (GetValueFromProperty<string>(stringKey) != defValue) return true;

foreach (var listKey in DefaultListValues)
{
IReadOnlyList<string> currentValue = GetValueFromProperty<IReadOnlyList<string>>(listKey);
if (currentValue.Where(x => x.Any()).Any()) return true;
}

return false;
// OverridesNextLevelOpts does not need to be checked here, since
// this method is invoked before this property has been set
}
Expand Down
10 changes: 10 additions & 0 deletions src/UniGetUI.PackageEngine.Serializable/SerializableBundle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,16 @@ public override void LoadFromJson(JsonNode data)
}
}

public override JsonNode AsJsonNode()
{
JsonObject obj = new();
obj.Add(nameof(export_version), export_version);
obj.Add(nameof(packages), new JsonArray(packages.Select(p => p.AsJsonNode()).ToArray()));
obj.Add(nameof(incompatible_packages_info), incompatible_packages_info);
Comment thread
marticliment marked this conversation as resolved.
obj.Add(nameof(incompatible_packages), new JsonArray(incompatible_packages.Select(p => p.AsJsonNode()).ToArray()));
return obj;
}

public SerializableBundle() : base()
{
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,14 @@ public abstract class SerializableComponent<T> where T: class
/// <returns>A pretty-formatted JSON string representing the current data</returns>
public string AsJsonString()
{
return JsonSerializer.Serialize<T>(this as T ?? throw new InvalidCastException("Invalid type"), SerializationHelpers.DefaultOptions);
return JsonSerializer.Serialize(AsJsonNode(), SerializationHelpers.DefaultOptions);
}

/// <summary>
/// Serializes this object into a JsonNode object
/// </summary>
/// <returns>A pretty-formatted JSON string representing the current data</returns>
public JsonNode AsJsonNode()
{
return JsonNode.Parse(AsJsonString()) ?? throw new InvalidDataException("The JSON object could not be parsed to a JsonNode");
}
public abstract JsonNode AsJsonNode();

/// <summary>
/// Creates an instance of this object with the default data
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,16 @@ public override void LoadFromJson(JsonNode data)
this.Source = data[nameof(Source)]?.GetVal<string>() ?? "";
}

public override JsonNode AsJsonNode()
{
JsonObject obj = new();
obj.Add(nameof(Id), Id);
obj.Add(nameof(Name), Name);
obj.Add(nameof(Version), Version);
obj.Add(nameof(Source), Source);
return obj;
}

public SerializableIncompatiblePackage(JsonNode data) : base(data)
{
}
Expand Down
13 changes: 13 additions & 0 deletions src/UniGetUI.PackageEngine.Serializable/SerializablePackage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,19 @@ public override void LoadFromJson(JsonNode data)
this.Updates = new(data[nameof(Updates)] ?? new JsonObject());
}

public override JsonNode AsJsonNode()
{
JsonObject obj = new();
obj.Add(nameof(Id), Id);
obj.Add(nameof(Name), Name);
obj.Add(nameof(Version), Version);
obj.Add(nameof(Source), Source);
obj.Add(nameof(ManagerName), ManagerName);
obj.Add(nameof(InstallationOptions), InstallationOptions.AsJsonNode());
obj.Add(nameof(Updates), Updates.AsJsonNode());
return obj;
}

public SerializablePackage() : base()
{
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@ public override void LoadFromJson(JsonNode data)
this.IgnoredVersion = data[nameof(IgnoredVersion)]?.GetVal<string>() ?? "";
}

public override JsonNode AsJsonNode()
{
JsonObject obj = new();
if(UpdatesIgnored is not false) obj.Add(nameof(UpdatesIgnored), UpdatesIgnored);
if(IgnoredVersion.Any()) obj.Add(nameof(IgnoredVersion), IgnoredVersion);
return obj;
}

public SerializableUpdatesOptions() : base()
{
}
Expand Down
4 changes: 1 addition & 3 deletions src/UniGetUI/Pages/SoftwarePages/PackageBundlesPage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -600,9 +600,7 @@ static int Comparison(IPackage x, IPackage y)
string ExportableData;

if (formatType is BundleFormatType.JSON or BundleFormatType.UBUNDLE)
ExportableData = JsonSerializer.Serialize(
exportable,
SerializationHelpers.DefaultOptions);
ExportableData = exportable.AsJsonString();

else if (formatType is BundleFormatType.YAML)
{
Expand Down
4 changes: 2 additions & 2 deletions src/UniGetUI/Services/GitHubBackupService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ namespace UniGetUI.Services
{
public class GitHubBackupService
{
private const string GistDescription_EndingKey = "#[UNIGETUI_BACKUP_V1]";
private const string PackageBackup_StartingKey = "#[PACKAGES]";
private const string GistDescription_EndingKey = "@[UNIGETUI_BACKUP_V1]";
private const string PackageBackup_StartingKey = "@[PACKAGES]";

private const string GistDescription = $"UniGetUI package backups - DO NOT RENAME OR MODIFY {GistDescription_EndingKey}";
private const string ReadMeContents = "" +
Expand Down
Loading