Skip to content

Commit 63656d9

Browse files
committed
InstallOptions class will operate dynamically, making it easier to add more fields and more robust against mistakes
1 parent 8634cc7 commit 63656d9

1 file changed

Lines changed: 107 additions & 153 deletions

File tree

src/UniGetUI.PackageEngine.Serializable/InstallOptions.cs

Lines changed: 107 additions & 153 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,43 @@ namespace UniGetUI.PackageEngine.Serializable
66
{
77
public class InstallOptions: SerializableComponent<InstallOptions>
88
{
9+
private readonly IReadOnlyDictionary<string, bool> DefaultBoolValues = new Dictionary<string, bool>()
10+
{ // OverridesNextLevelOpts is deliberately skipped here
11+
{ "SkipHashCheck", false },
12+
{ "InteractiveInstallation", false },
13+
{ "RunAsAdministrator", false },
14+
{ "PreRelease", false },
15+
{ "SkipMinorUpdates", false },
16+
{ "RemoveDataOnUninstall", false },
17+
{ "UninstallPreviousVersionsOnUpdate", false },
18+
{ "AbortOnPreInstallFail", true },
19+
{ "AbortOnPreUpdateFail", true },
20+
{ "AbortOnPreUninstallFail", true },
21+
};
22+
23+
private readonly IReadOnlyDictionary<string, string> DefaultStringValues = new Dictionary<string, string>()
24+
{
25+
{"Architecture", ""},
26+
{"InstallationScope", ""},
27+
{"CustomInstallLocation", ""},
28+
{"Version", ""},
29+
{"PreInstallCommand", ""},
30+
{"PostInstallCommand", ""},
31+
{"PreUpdateCommand", ""},
32+
{"PostUpdateCommand", ""},
33+
{"PreUninstallCommand", ""},
34+
{"PostUninstallCommand", ""},
35+
};
36+
37+
private readonly IReadOnlyList<string> DefaultListValues = new List<string>()
38+
{
39+
"CustomParameters_Install",
40+
"CustomParameters_Update",
41+
"CustomParameters_Uninstall",
42+
"KillBeforeOperation",
43+
};
44+
45+
946
public bool SkipHashCheck { get; set; }
1047
public bool InteractiveInstallation { get; set; }
1148
public bool RunAsAdministrator { get; set; }
@@ -18,7 +55,6 @@ public class InstallOptions: SerializableComponent<InstallOptions>
1855
public string CustomInstallLocation { get; set; } = "";
1956
public string Version { get; set; } = "";
2057
public bool SkipMinorUpdates { get; set; }
21-
public bool OverridesNextLevelOpts { get; set; }
2258
public bool RemoveDataOnUninstall { get; set; }
2359
public bool UninstallPreviousVersionsOnUpdate { get; set; }
2460
public List<string> KillBeforeOperation { get; set; } = [];
@@ -33,53 +69,54 @@ public class InstallOptions: SerializableComponent<InstallOptions>
3369
public string PostUninstallCommand { get; set; } = "";
3470
public bool AbortOnPreUninstallFail { get; set; } = true;
3571

72+
public bool OverridesNextLevelOpts { get; set; }
3673

3774
public override InstallOptions Copy()
3875
{
39-
return new()
40-
{
41-
SkipHashCheck = SkipHashCheck,
42-
Architecture = Architecture,
43-
CustomInstallLocation = CustomInstallLocation,
44-
CustomParameters_Install = CustomParameters_Install.ToList(),
45-
CustomParameters_Update = CustomParameters_Update.ToList(),
46-
CustomParameters_Uninstall = CustomParameters_Uninstall.ToList(),
47-
InstallationScope = InstallationScope,
48-
InteractiveInstallation = InteractiveInstallation,
49-
PreRelease = PreRelease,
50-
RunAsAdministrator = RunAsAdministrator,
51-
Version = Version,
52-
SkipMinorUpdates = SkipMinorUpdates,
53-
OverridesNextLevelOpts = OverridesNextLevelOpts,
54-
RemoveDataOnUninstall = RemoveDataOnUninstall,
55-
KillBeforeOperation = KillBeforeOperation.ToList(),
56-
PreInstallCommand = PreInstallCommand,
57-
PreUpdateCommand = PreUpdateCommand,
58-
PreUninstallCommand = PreUninstallCommand,
59-
PostInstallCommand = PostInstallCommand,
60-
PostUpdateCommand = PostUpdateCommand,
61-
PostUninstallCommand = PostUninstallCommand,
62-
AbortOnPreInstallFail = AbortOnPreInstallFail,
63-
AbortOnPreUpdateFail = AbortOnPreUpdateFail,
64-
AbortOnPreUninstallFail = AbortOnPreUninstallFail,
65-
UninstallPreviousVersionsOnUpdate = UninstallPreviousVersionsOnUpdate,
66-
};
76+
var copy = new InstallOptions();
77+
78+
foreach (var (boolKey, _) in DefaultBoolValues)
79+
copy.SetValueToProperty(boolKey, GetValueFromProperty<bool>(boolKey));
80+
81+
foreach (var (stringKey, _) in DefaultStringValues)
82+
copy.SetValueToProperty(stringKey, GetValueFromProperty<string>(stringKey));
83+
84+
foreach (var listKey in DefaultListValues)
85+
copy.SetValueToProperty(listKey, GetValueFromProperty<IReadOnlyList<string>>(listKey).ToList());
86+
87+
// Handle non-automated OverridesNextLevelOpts
88+
copy.OverridesNextLevelOpts = OverridesNextLevelOpts;
89+
return copy;
90+
}
91+
92+
public void SetValueToProperty<T>(string name, T value)
93+
{
94+
var property = this.GetType().GetProperty(name);
95+
property?.SetValue(this, value);
96+
}
97+
98+
public T GetValueFromProperty<T>(string name)
99+
{
100+
var property = this.GetType().GetProperty(name);
101+
return (T)(property?.GetValue(this) ?? throw new InvalidDataException($"Invalid datatype for property {name} (expected {nameof(T)})"));
67102
}
68103

69104
public override void LoadFromJson(JsonNode data)
70105
{
71-
// RemoveDataOnUninstall should not be loaded from disk
106+
foreach (var (boolKey, defValue) in DefaultBoolValues)
107+
{
108+
// RemoveDataOnUninstall should not be loaded from disk
109+
if(boolKey == "RemoveDataOnUninstall") continue;
110+
SetValueToProperty(boolKey, data[boolKey]?.GetVal<bool>() ?? defValue);
111+
}
72112

73-
this.SkipHashCheck = data[nameof(SkipHashCheck)]?.GetVal<bool>() ?? false;
74-
this.InteractiveInstallation = data[nameof(InteractiveInstallation)]?.GetVal<bool>() ?? false;
75-
this.RunAsAdministrator = data[nameof(RunAsAdministrator)]?.GetVal<bool>() ?? false;
76-
this.Architecture = data[nameof(Architecture)]?.GetVal<string>() ?? "";
77-
this.InstallationScope = data[nameof(InstallationScope)]?.GetVal<string>() ?? "";
113+
foreach (var (stringKey, defValue) in DefaultStringValues)
114+
SetValueToProperty(stringKey, data[stringKey]?.GetVal<string>() ?? defValue);
78115

79-
this.CustomParameters_Install = ReadArrayFromJson(data, nameof(CustomParameters_Install));
80-
this.CustomParameters_Update = ReadArrayFromJson(data, nameof(CustomParameters_Update));
81-
this.CustomParameters_Uninstall = ReadArrayFromJson(data, nameof(CustomParameters_Uninstall));
116+
foreach (var listKey in DefaultListValues)
117+
SetValueToProperty(listKey, ReadArrayFromJson(data, listKey));
82118

119+
// Handle case where setting has not been migrated yet
83120
if (this.CustomParameters_Install.Count is 0 &&
84121
this.CustomParameters_Update.Count is 0 &&
85122
this.CustomParameters_Uninstall.Count is 0 &&
@@ -90,28 +127,10 @@ this.CustomParameters_Uninstall.Count is 0 &&
90127
this.CustomParameters_Uninstall = ReadArrayFromJson(data, "CustomParameters");
91128
}
92129

93-
this.KillBeforeOperation = ReadArrayFromJson(data, nameof(KillBeforeOperation));
94-
this.PreRelease = data[nameof(PreRelease)]?.GetVal<bool>() ?? false;
95-
this.CustomInstallLocation = data[nameof(CustomInstallLocation)]?.GetVal<string>() ?? "";
96-
this.Version = data[nameof(Version)]?.GetVal<string>() ?? "";
97-
this.SkipMinorUpdates = data[nameof(SkipMinorUpdates)]?.GetVal<bool>() ?? false;
98-
this.UninstallPreviousVersionsOnUpdate = data[nameof(UninstallPreviousVersionsOnUpdate)]?.GetVal<bool>() ?? false;
99-
100-
this.PreInstallCommand = data[nameof(PreInstallCommand)]?.GetVal<string>() ?? "";
101-
this.PreUpdateCommand = data[nameof(PreUpdateCommand)]?.GetVal<string>() ?? "";
102-
this.PreUninstallCommand = data[nameof(PreUninstallCommand)]?.GetVal<string>() ?? "";
103-
this.PostInstallCommand = data[nameof(PostInstallCommand)]?.GetVal<string>() ?? "";
104-
this.PostUpdateCommand = data[nameof(PostUpdateCommand)]?.GetVal<string>() ?? "";
105-
this.PostUninstallCommand = data[nameof(PostUninstallCommand)]?.GetVal<string>() ?? "";
106-
this.AbortOnPreInstallFail = data[nameof(AbortOnPreInstallFail)]?.GetVal<bool>() ?? true;
107-
this.AbortOnPreUpdateFail = data[nameof(AbortOnPreUpdateFail)]?.GetVal<bool>() ?? true;
108-
this.AbortOnPreUninstallFail = data[nameof(AbortOnPreUninstallFail)]?.GetVal<bool>() ?? true;
109-
110130
// if OverridesNextLevelOpts is not found on the JSON, set it to true or false depending
111131
// on whether the current settings instances are different from the default values.
112132
// This entry shall be checked the last one, to ensure all other properties are set
113-
this.OverridesNextLevelOpts =
114-
data[nameof(OverridesNextLevelOpts)]?.GetValue<bool>() ?? DiffersFromDefault();
133+
this.OverridesNextLevelOpts = data[nameof(OverridesNextLevelOpts)]?.GetValue<bool>() ?? DiffersFromDefault();
115134
}
116135

117136
public override JsonNode AsJsonNode()
@@ -121,81 +140,27 @@ public override JsonNode AsJsonNode()
121140
if (OverridesNextLevelOpts is not false)
122141
obj.Add(nameof(OverridesNextLevelOpts), OverridesNextLevelOpts);
123142

124-
if(SkipHashCheck is not false)
125-
obj.Add(nameof(SkipHashCheck), SkipHashCheck);
126-
127-
if(InteractiveInstallation is not false)
128-
obj.Add(nameof(InteractiveInstallation), InteractiveInstallation);
129-
130-
if(RunAsAdministrator is not false)
131-
obj.Add(nameof(RunAsAdministrator), RunAsAdministrator);
132-
133-
if(PreRelease is not false)
134-
obj.Add(nameof(PreRelease), PreRelease);
135-
136-
if(SkipMinorUpdates is not false)
137-
obj.Add(nameof(SkipMinorUpdates), SkipMinorUpdates);
138-
139-
if(Architecture.Any())
140-
obj.Add(nameof(Architecture), Architecture);
141-
142-
if(InstallationScope.Any())
143-
obj.Add(nameof(InstallationScope), InstallationScope);
144-
145-
if(CustomParameters_Install.Where(x => x.Any()).Any())
146-
obj.Add(nameof(CustomParameters_Install),
147-
new JsonArray(CustomParameters_Install.Select(x => JsonValue.Create(x) as JsonNode).ToArray()));
148-
149-
if(CustomParameters_Update.Where(x => x.Any()).Any())
150-
obj.Add(nameof(CustomParameters_Update),
151-
new JsonArray(CustomParameters_Update.Select(x => JsonValue.Create(x) as JsonNode).ToArray()));
152-
153-
if(CustomParameters_Uninstall.Where(x => x.Any()).Any())
154-
obj.Add(nameof(CustomParameters_Uninstall),
155-
new JsonArray(CustomParameters_Uninstall.Select(x => JsonValue.Create(x) as JsonNode).ToArray()));
156-
157-
if(KillBeforeOperation.Where(x => x.Any()).Any())
158-
obj.Add(nameof(KillBeforeOperation),
159-
new JsonArray(KillBeforeOperation.Select(x => JsonValue.Create(x) as JsonNode).ToArray()));
160-
161-
if(CustomInstallLocation.Any())
162-
obj.Add(nameof(CustomInstallLocation), CustomInstallLocation);
163-
164-
if(RemoveDataOnUninstall is not false)
165-
obj.Add(nameof(RemoveDataOnUninstall), RemoveDataOnUninstall);
166-
167-
if(Version.Any())
168-
obj.Add(nameof(Version), Version);
169-
170-
if(PreInstallCommand.Any())
171-
obj.Add(nameof(PreInstallCommand), PreInstallCommand);
172-
173-
if(PostInstallCommand.Any())
174-
obj.Add(nameof(PostInstallCommand), PostInstallCommand);
175-
176-
if(AbortOnPreInstallFail is not true)
177-
obj.Add(nameof(AbortOnPreInstallFail), AbortOnPreInstallFail);
178-
179-
if(PreUpdateCommand.Any())
180-
obj.Add(nameof(PreUpdateCommand), PreUpdateCommand);
181-
182-
if(PostUpdateCommand.Any())
183-
obj.Add(nameof(PostUpdateCommand), PostUpdateCommand);
184-
185-
if(AbortOnPreUpdateFail is not true)
186-
obj.Add(nameof(AbortOnPreUpdateFail), AbortOnPreUpdateFail);
187-
188-
if(PreUninstallCommand.Any())
189-
obj.Add(nameof(PreUninstallCommand), PreUninstallCommand);
143+
foreach (var (boolKey, defValue) in DefaultBoolValues)
144+
{
145+
bool currentValue = GetValueFromProperty<bool>(boolKey);
146+
if (currentValue != defValue) obj.Add(boolKey, currentValue);
147+
}
190148

191-
if(PostUninstallCommand.Any())
192-
obj.Add(nameof(PostUninstallCommand), PostUninstallCommand);
149+
foreach (var (stringKey, defValue) in DefaultStringValues)
150+
{
151+
string currentValue = GetValueFromProperty<string>(stringKey);
152+
if (currentValue != defValue) obj.Add(stringKey, currentValue);
153+
}
193154

194-
if(UninstallPreviousVersionsOnUpdate is not false)
195-
obj.Add(nameof(UninstallPreviousVersionsOnUpdate), UninstallPreviousVersionsOnUpdate);
155+
foreach (var listKey in DefaultListValues)
156+
{
157+
IReadOnlyList<string> currentValue = GetValueFromProperty<IReadOnlyList<string>>(listKey);
196158

197-
if(AbortOnPreUninstallFail is not true)
198-
obj.Add(nameof(AbortOnPreUninstallFail), AbortOnPreUninstallFail);
159+
if (currentValue.Where(x => x.Any()).Any())
160+
{
161+
obj.Add(listKey, new JsonArray(currentValue.Select(x => JsonValue.Create(x) as JsonNode).ToArray()));
162+
}
163+
}
199164

200165
return obj;
201166
}
@@ -211,30 +176,19 @@ private static List<string> ReadArrayFromJson(JsonNode data, string name)
211176

212177
public bool DiffersFromDefault()
213178
{
214-
return SkipHashCheck is not false ||
215-
InteractiveInstallation is not false ||
216-
RunAsAdministrator is not false ||
217-
PreRelease is not false ||
218-
SkipMinorUpdates is not false ||
219-
Architecture.Any() ||
220-
InstallationScope.Any() ||
221-
CustomParameters_Install.Where(x => x.Any()).Any() ||
222-
CustomParameters_Update.Where(x => x.Any()).Any() ||
223-
CustomParameters_Uninstall.Where(x => x.Any()).Any() ||
224-
KillBeforeOperation.Where(x => x.Any()).Any() ||
225-
CustomInstallLocation.Any() ||
226-
RemoveDataOnUninstall is not false ||
227-
Version.Any() ||
228-
PreInstallCommand.Any() ||
229-
PostInstallCommand.Any() ||
230-
AbortOnPreInstallFail is not true ||
231-
PreUpdateCommand.Any() ||
232-
PostUpdateCommand.Any() ||
233-
AbortOnPreUpdateFail is not true ||
234-
PreUninstallCommand.Any() ||
235-
PostUninstallCommand.Any() ||
236-
UninstallPreviousVersionsOnUpdate is not false ||
237-
AbortOnPreUninstallFail is not true;
179+
foreach (var (boolKey, defValue) in DefaultBoolValues)
180+
if (GetValueFromProperty<bool>(boolKey) != defValue) return true;
181+
182+
foreach (var (stringKey, defValue) in DefaultStringValues)
183+
if (GetValueFromProperty<string>(stringKey) != defValue) return true;
184+
185+
foreach (var listKey in DefaultListValues)
186+
{
187+
IReadOnlyList<string> currentValue = GetValueFromProperty<IReadOnlyList<string>>(listKey);
188+
if (currentValue.Where(x => x.Any()).Any()) return true;
189+
}
190+
191+
return false;
238192
// OverridesNextLevelOpts does not need to be checked here, since
239193
// this method is invoked before this property has been set
240194
}

0 commit comments

Comments
 (0)