Skip to content

Commit ab98159

Browse files
authored
cleanup: remove business fields from UpdateOptions, _customOptions, ClientCoreTest, Linux Script (#393)
* cleanup: remove business fields from UpdateOptions, _customOptions, ClientCoreTest, Linux Script 1. UpdateOptions.cs: remove 14 business fields (UpdateUrl, Token, Scheme, etc) - keep only 20 framework-level options (AppType, Silent, DiffMode, etc.) - business fields already exist in Configinfo/BaseConfigInfo 2. Remove _customOptions mechanism from GeneralUpdateBootstrap + ClientUpdateStrategy - hooks (IUpdateHooks) already cover pre/post-update logic - Hub config now uses _configInfo.Token/AppSecretKey 3. Delete tests/ClientCoreTest/ (no longer needed) 4. LinuxStrategy: remove Script mechanism - IUpdateHooks.OnBeforeStartAppAsync covers permission-setting 5. GeneralUpdate.Core cleanup: unused usings, XML docs on enums * fix: remove ClientCoreTest reference from solution file * fix: update tests for removed UpdateOptions fields and AddCustomOption - BootstrapFullParameterMatrixTests: remove all tests/options for deleted business fields (Deployment/Security/Reporting regions), remove AddCustomOption calls, keep only framework-level options - BootstrapHooksAndExtensionsTests: remove AddCustomOption and deleted UpdateOptions references, consolidate test code * fix: remove ClientCoreTest from CI workflow
1 parent ccd7f6b commit ab98159

19 files changed

Lines changed: 141 additions & 1991 deletions

.github/workflows/ci.yml

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,13 @@ jobs:
2929

3030
- name: Test (Windows)
3131
if: runner.os == 'Windows'
32-
# Exclusions: ConfiginfoBuilderTests/CleanBackup_KeepsOnlyRecentVersions (pre-existing regressions),
33-
# SharedMemoryProvider_RoundTrip/AutoProvider_ThrowsWhenAllFail (platform-specific IPC tests).
3432
run: dotnet test ./src/c#/GeneralUpdate.slnx -c Release --no-build --filter "FullyQualifiedName!~ConfiginfoBuilderTests&FullyQualifiedName!~CleanBackup_KeepsOnlyRecentVersions&FullyQualifiedName!~SharedMemoryProvider_RoundTrip&FullyQualifiedName!~AutoProvider_ThrowsWhenAllFail"
3533

3634
- name: Test (Ubuntu - cross-platform)
3735
if: runner.os == 'Linux'
3836
run: |
3937
dotnet test tests/CoreTest/CoreTest.csproj -c Release --no-build --filter "FullyQualifiedName!~ConfiginfoBuilderTests"
4038
dotnet test tests/DifferentialTest/DifferentialTest.csproj -c Release --no-build
41-
dotnet test tests/ClientCoreTest/ClientCoreTest.csproj -c Release --no-build
4239
4340
aot-verify:
4441
runs-on: windows-latest
@@ -54,8 +51,5 @@ jobs:
5451
- name: Restore
5552
run: dotnet restore ./src/c#/GeneralUpdate.slnx
5653

57-
# Verify AOT compatibility via trim analyzer warnings.
58-
# IL3050 warnings from legacy JsonSerializer calls are pre-existing;
59-
# the solution-level build with IsAotCompatible catches new AOT regressions.
6054
- name: Verify AOT compatibility
6155
run: dotnet build ./src/c#/GeneralUpdate.Core/GeneralUpdate.Core.csproj -c Release -f net10.0 /p:IsAotCompatible=true --no-restore

src/c#/GeneralUpdate.Core/Bootstrap/GeneralUpdateBootstrap.cs

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ public class GeneralUpdateBootstrap : AbstractBootstrap<GeneralUpdateBootstrap,
3737
private GlobalConfigInfo _configInfo = new();
3838
private Func<bool>? _customSkipOption;
3939
private Func<UpdateInfoEventArgs, bool>? _updatePrecheck;
40-
private readonly List<Func<bool>> _customOptions = new();
4140
private CancellationTokenSource? _cts;
4241

4342
public GeneralUpdateBootstrap()
@@ -105,7 +104,7 @@ private async Task<GeneralUpdateBootstrap> LaunchWithStrategy(IStrategy roleStra
105104
if (hubConfig != null && !string.IsNullOrEmpty(hubConfig.Url))
106105
{
107106
var hubSource = new Download.Sources.HubDownloadSource(
108-
hubConfig.Url, GetOption(UpdateOptions.Token), GetOption(UpdateOptions.AppSecretKey));
107+
hubConfig.Url, _configInfo.Token, _configInfo.AppSecretKey);
109108
await hubSource.StartAsync().ConfigureAwait(false);
110109
resolvedSource = hubSource;
111110
GeneralTracer.Info("GeneralUpdateBootstrap: HubDownloadSource started from HubConfig.");
@@ -115,8 +114,6 @@ private async Task<GeneralUpdateBootstrap> LaunchWithStrategy(IStrategy roleStra
115114
clientStrat.DownloadSource = resolvedSource;
116115
if (_updatePrecheck != null)
117116
clientStrat.UseUpdatePrecheck(_updatePrecheck);
118-
foreach (var opt in _customOptions)
119-
clientStrat.UseCustomOption(opt);
120117
await CallSmallBowlHomeAsync(_configInfo.Bowl).ConfigureAwait(false);
121118
}
122119
else if (roleStrategy is UpgradeUpdateStrategy upgradeStrat)
@@ -244,13 +241,6 @@ public GeneralUpdateBootstrap AddListenerUpdatePrecheck(Func<UpdateInfoEventArgs
244241
return this;
245242
}
246243

247-
public GeneralUpdateBootstrap AddCustomOption(List<Func<bool>> funcList)
248-
{
249-
Debug.Assert(funcList != null && funcList.Any());
250-
_customOptions.AddRange(funcList);
251-
return this;
252-
}
253-
254244
// ════════════════════════════════════════════════════════════════
255245
// Helpers
256246
// ════════════════════════════════════════════════════════════════
Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
11
namespace GeneralUpdate.Core.Configuration;
22

3-
public enum DiffMode { Serial, Parallel }
3+
/// <summary>
4+
/// Diff/patch generation mode.
5+
/// </summary>
6+
public enum DiffMode
7+
{
8+
/// <summary>Process diffs one file at a time.</summary>
9+
Serial,
10+
/// <summary>Process diffs in parallel for faster throughput.</summary>
11+
Parallel
12+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
namespace GeneralUpdate.Core.Configuration
22
{
3+
/// <summary>
4+
/// Compression format constants for update packages.
5+
/// </summary>
36
public class Format
47
{
8+
/// <summary>ZIP compression format extension.</summary>
59
public const string ZIP = ".zip";
610
}
711
}
Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
namespace GeneralUpdate.Core.Configuration;
22

3+
/// <summary>
4+
/// Report status type constants for update operation results.
5+
/// </summary>
36
public class ReportType
47
{
8+
/// <summary>No report / default state.</summary>
59
public const int None = 0;
610

11+
/// <summary>Update succeeded.</summary>
712
public const int Success = 2;
813

14+
/// <summary>Update failed.</summary>
915
public const int Failure = 3;
10-
}
16+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
namespace GeneralUpdate.Core.Configuration;
22

3+
/// <summary>
4+
/// Specifies the deployment mode for updates.
5+
/// </summary>
36
public enum UpdateMode
47
{
8+
/// <summary>Standard file-based update.</summary>
59
Default = 0,
10+
/// <summary>Script-based custom update logic.</summary>
611
Scripts = 1
712
}

src/c#/GeneralUpdate.Core/Configuration/UpdateOptions.cs

Lines changed: 41 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,84 @@
11
using System;
22
using System.Text;
3-
using GeneralUpdate.Core.FileSystem;
43

54
namespace GeneralUpdate.Core.Configuration
65
{
76
/// <summary>
8-
/// Convenience accessor for UpdateOption constants.
7+
/// Framework-level update option constants.
98
/// Each option has a unique string name and a reasonable default value.
10-
/// Use via <c>.Option(UpdateOptions.UpdateUrl, "https://...")</c>.
9+
/// Business-specific configuration (URLs, keys, app names, etc.) belongs in
10+
/// <see cref="Configinfo"/> / <see cref="BaseConfigInfo"/>.
1111
/// </summary>
1212
public static class UpdateOptions
1313
{
1414
// ═══ Core ═══
15+
/// <summary>Application role type — Client, Upgrade, or OSS.</summary>
1516
public static UpdateOption<AppType> AppType { get; } = UpdateOption.ValueOf<AppType>("APPTYPE", Configuration.AppType.Client);
1617

1718
// ═══ Diff mode ═══
19+
/// <summary>Diff/patch generation mode — Serial or Parallel.</summary>
1820
public static UpdateOption<DiffMode> DiffMode { get; } = UpdateOption.ValueOf<DiffMode>("DIFFMODE", Configuration.DiffMode.Serial);
1921

2022
// ═══ Backward-compatible options ═══
23+
/// <summary>Compression encoding for update packages.</summary>
2124
public static UpdateOption<Encoding> Encoding { get; } = UpdateOption.ValueOf<Encoding>("COMPRESSENCODING", System.Text.Encoding.UTF8);
25+
26+
/// <summary>Compression format (e.g., "ZIP").</summary>
2227
public static UpdateOption<string> Format { get; } = UpdateOption.ValueOf<string>("COMPRESSFORMAT", "ZIP");
28+
29+
/// <summary>Download timeout in seconds.</summary>
2330
public static UpdateOption<int?> DownloadTimeout { get; } = UpdateOption.ValueOf<int?>("DOWNLOADTIMEOUT", 30);
31+
32+
/// <summary>Whether driver update mode is enabled.</summary>
2433
public static UpdateOption<bool?> DriveEnabled { get; } = UpdateOption.ValueOf<bool?>("DRIVE", false);
34+
35+
/// <summary>Whether differential patch update is enabled.</summary>
2536
public static UpdateOption<bool?> PatchEnabled { get; } = UpdateOption.ValueOf<bool?>("PATCH", true);
37+
38+
/// <summary>Whether backup before update is enabled.</summary>
2639
public static UpdateOption<bool?> BackupEnabled { get; } = UpdateOption.ValueOf<bool?>("BACKUP", true);
40+
41+
/// <summary>Update mode override.</summary>
2742
public static UpdateOption<UpdateMode?> Mode { get; } = UpdateOption.ValueOf<UpdateMode?>("MODE", null);
43+
44+
/// <summary>Whether silent background update is enabled.</summary>
2845
public static UpdateOption<bool> Silent { get; } = UpdateOption.ValueOf<bool>("ENABLESILENTUPDATE", false);
2946

30-
// ═══ New options ═══
31-
public static UpdateOption<string?> UpdateUrl { get; } = UpdateOption.ValueOf<string?>("UPDATEURL", null);
32-
public static UpdateOption<string> AppSecretKey { get; } = UpdateOption.ValueOf<string>("APPSECRETKEY", string.Empty);
33-
public static UpdateOption<string> AppName { get; } = UpdateOption.ValueOf<string>("APPNAME", string.Empty);
34-
public static UpdateOption<string> MainAppName { get; } = UpdateOption.ValueOf<string>("MAINAPPNAME", string.Empty);
35-
public static UpdateOption<string> InstallPath { get; } = UpdateOption.ValueOf<string>("INSTALLPATH", AppContext.BaseDirectory);
36-
public static UpdateOption<string> ClientVersion { get; } = UpdateOption.ValueOf<string>("CLIENTVERSION", string.Empty);
37-
public static UpdateOption<string?> UpgradeClientVersion { get; } = UpdateOption.ValueOf<string?>("UPGRADECLIENTVERSION", null);
38-
public static UpdateOption<PlatformType?> Platform { get; } = UpdateOption.ValueOf<PlatformType?>("PLATFORM", null);
47+
// ═══ Silent mode ═══
48+
/// <summary>Whether silent updates auto-install without user intervention.</summary>
3949
public static UpdateOption<bool> SilentAutoInstall { get; } = UpdateOption.ValueOf<bool>("SILENTAUTOINSTALL", false);
50+
51+
/// <summary>Polling interval in minutes for silent update checks.</summary>
4052
public static UpdateOption<int> SilentPollIntervalMinutes { get; } = UpdateOption.ValueOf<int>("SILENTPOLLINTERVALMINUTES", 60);
53+
54+
// ═══ Concurrency & Resume ═══
55+
/// <summary>Maximum concurrent download operations.</summary>
4156
public static UpdateOption<int> MaxConcurrency { get; } = UpdateOption.ValueOf<int>("MAXCONCURRENCY", 3);
57+
58+
/// <summary>Whether download resume is enabled.</summary>
4259
public static UpdateOption<bool> EnableResume { get; } = UpdateOption.ValueOf<bool>("ENABLERESUME", true);
60+
61+
// ═══ Resilience ═══
62+
/// <summary>Number of retry attempts for failed operations.</summary>
4363
public static UpdateOption<int> RetryCount { get; } = UpdateOption.ValueOf<int>("RETRYCOUNT", 3);
64+
65+
/// <summary>Whether checksum verification is performed after download.</summary>
4466
public static UpdateOption<bool> VerifyChecksum { get; } = UpdateOption.ValueOf<bool>("VERIFYCHECKSUM", true);
45-
public static UpdateOption<string?> ReportUrl { get; } = UpdateOption.ValueOf<string?>("REPORTURL", null);
46-
public static UpdateOption<string?> ProductId { get; } = UpdateOption.ValueOf<string?>("PRODUCTID", null);
47-
public static UpdateOption<string?> PermissionScript { get; } = UpdateOption.ValueOf<string?>("PERMISSIONSCRIPT", null);
48-
public static UpdateOption<string?> Scheme { get; } = UpdateOption.ValueOf<string?>("SCHEME", null);
49-
public static UpdateOption<string?> Token { get; } = UpdateOption.ValueOf<string?>("TOKEN", null);
67+
68+
/// <summary>Initial retry interval for exponential back-off. Default 1 second.</summary>
69+
public static UpdateOption<TimeSpan> RetryInterval { get; } = UpdateOption.ValueOf<TimeSpan>("RETRYINTERVAL", TimeSpan.FromSeconds(1));
5070

5171
// ═══ OSS ═══
72+
/// <summary>Object Storage Service provider type.</summary>
5273
public static UpdateOption<OssProvider?> OSSProvider { get; } = UpdateOption.ValueOf<OssProvider?>("OSSPROVIDER", null);
74+
75+
/// <summary>OSS bucket region identifier.</summary>
5376
public static UpdateOption<string?> OSSBucketRegion { get; } = UpdateOption.ValueOf<string?>("OSSBUCKETREGION", null);
5477

5578
// ═══ Blacklist ═══
79+
/// <summary>Blacklist configuration for files and directories to exclude from updates.</summary>
5680
public static UpdateOption<BlackListConfig> BlackList { get; } = UpdateOption.ValueOf<BlackListConfig>("BLACKLIST", BlackListConfig.Empty);
5781

58-
// ═══ Watchdog ═══
59-
/// <summary>Bowl (crash monitor / watchdog) executable path.</summary>
60-
public static UpdateOption<string?> Bowl { get; } = UpdateOption.ValueOf<string?>("BOWL", null);
61-
62-
// ═══ Logging & Script ═══
63-
/// <summary>Remote update log / changelog URL.</summary>
64-
public static UpdateOption<string?> UpdateLogUrl { get; } = UpdateOption.ValueOf<string?>("UPDATELOGURL", null);
65-
/// <summary>Custom execution script path for pre/post-update actions.</summary>
66-
public static UpdateOption<string?> Script { get; } = UpdateOption.ValueOf<string?>("SCRIPT", null);
67-
68-
// ═══ Retry ═══
69-
/// <summary>Initial retry interval for exponential backoff. Default 1 second.</summary>
70-
public static UpdateOption<TimeSpan> RetryInterval { get; } = UpdateOption.ValueOf<TimeSpan>("RETRYINTERVAL", TimeSpan.FromSeconds(1));
71-
7282
// ═══ SignalR Hub ═══
7383
/// <summary>SignalR Hub configuration for push-based updates.</summary>
7484
public static UpdateOption<HubConfig?> Hub { get; } = UpdateOption.ValueOf<HubConfig?>("HUB", null);

src/c#/GeneralUpdate.Core/Strategy/AbstractStrategy.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
using GeneralUpdate.Core.Pipeline;
77
using GeneralUpdate.Core;
88
using GeneralUpdate.Core.Configuration;
9-
using GeneralUpdate.Core.Configuration;
109
using GeneralUpdate.Core.Network;
1110

1211
namespace GeneralUpdate.Core.Strategy

src/c#/GeneralUpdate.Core/Strategy/ClientUpdateStrategy.cs

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ public class ClientUpdateStrategy : IStrategy
3030
private GlobalConfigInfo? _configInfo;
3131
private IStrategy? _osStrategy;
3232
private Func<UpdateInfoEventArgs, bool>? _updatePrecheck;
33-
private readonly List<Func<bool>> _customOptions = new();
3433
private readonly Download.Abstractions.IDownloadOrchestrator? _orchestrator;
3534
private readonly DiffMode _diffMode = DiffMode.Serial;
3635

@@ -57,7 +56,6 @@ public async Task ExecuteAsync()
5756
{
5857
GeneralTracer.Debug("ClientUpdateStrategy.ExecuteAsync start.");
5958
await CallSmallBowlHomeAsync(_configInfo.Bowl);
60-
ExecuteCustomOptions();
6159
await ExecuteWorkflowAsync();
6260
}
6361
catch (Exception ex)
@@ -87,13 +85,6 @@ public ClientUpdateStrategy UseUpdatePrecheck(Func<UpdateInfoEventArgs, bool> fu
8785
return this;
8886
}
8987

90-
/// <summary>Register custom pre-update operations.</summary>
91-
public ClientUpdateStrategy UseCustomOption(Func<bool> func)
92-
{
93-
_customOptions.Add(func);
94-
return this;
95-
}
96-
9788
#region Workflow
9889

9990
private async Task ExecuteWorkflowAsync()
@@ -299,19 +290,6 @@ private async Task CallSmallBowlHomeAsync(string processName)
299290
}
300291
}
301292

302-
private void ExecuteCustomOptions()
303-
{
304-
foreach (var option in _customOptions)
305-
{
306-
if (!option.Invoke())
307-
{
308-
var ex = new Exception("Custom option execution failed.");
309-
GeneralTracer.Error("ExecuteCustomOptions failed.", ex);
310-
EventManager.Instance.Dispatch(this, new ExceptionEventArgs(ex, ex.Message));
311-
}
312-
}
313-
}
314-
315293
// ════════════════════════════════════════════════════════════════
316294
// Hooks & Reporter safe wrappers
317295
// ════════════════════════════════════════════════════════════════
Lines changed: 2 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,8 @@
11
using System;
22
using System.Diagnostics;
3-
using System.IO;
4-
using GeneralUpdate.Core.FileSystem;
5-
using GeneralUpdate.Core;
6-
using GeneralUpdate.Core.Event;
7-
using GeneralUpdate.Core.Pipeline;
8-
using GeneralUpdate.Core.Strategy;
93
using GeneralUpdate.Core;
104
using GeneralUpdate.Core.Configuration;
5+
using GeneralUpdate.Core.Event;
116
using GeneralUpdate.Core.Pipeline;
127

138
namespace GeneralUpdate.Core.Strategy;
@@ -59,8 +54,7 @@ public override void StartApp()
5954
if (string.IsNullOrEmpty(mainAppPath))
6055
throw new Exception($"Can't find the app {mainAppPath}!");
6156

62-
GeneralTracer.Info($"GeneralUpdate.Core.LinuxStrategy.StartApp: executing startup script then launching main app={mainAppPath}");
63-
ExecuteScript();
57+
GeneralTracer.Info($"GeneralUpdate.Core.LinuxStrategy.StartApp: launching main app={mainAppPath}");
6458
Process.Start(mainAppPath);
6559
GeneralTracer.Info("GeneralUpdate.Core.LinuxStrategy.StartApp: main app launched successfully.");
6660
}
@@ -78,60 +72,4 @@ public override void StartApp()
7872
}
7973
}
8074

81-
/// <summary>
82-
/// Executes the user-specified script.
83-
/// </summary>
84-
private void ExecuteScript()
85-
{
86-
try
87-
{
88-
// Check if the script path is valid (_configinfo should come from the base class configuration)
89-
if (string.IsNullOrEmpty(_configinfo.Script) || !File.Exists(_configinfo.Script))
90-
{
91-
GeneralTracer.Info("No valid script path specified, skipping script execution");
92-
return;
93-
}
94-
95-
GeneralTracer.Info($"Starting to execute script: {_configinfo.Script}");
96-
97-
// Start process to execute Linux script (using bash)
98-
var processStartInfo = new ProcessStartInfo
99-
{
100-
FileName = "/bin/bash",
101-
Arguments = $"-c \"{_configinfo.Script}\"", // Execute the script
102-
RedirectStandardOutput = true,
103-
RedirectStandardError = true,
104-
UseShellExecute = false,
105-
CreateNoWindow = true
106-
};
107-
108-
using var process = Process.Start(processStartInfo);
109-
if (process == null)
110-
{
111-
GeneralTracer.Error("Failed to start script process");
112-
return;
113-
}
114-
115-
// Read script output logs
116-
var output = process.StandardOutput.ReadToEnd();
117-
var error = process.StandardError.ReadToEnd();
118-
process.WaitForExit(); // Wait for the script to finish execution
119-
120-
if (!string.IsNullOrEmpty(output))
121-
GeneralTracer.Info($"Script output: {output}");
122-
123-
if (!string.IsNullOrEmpty(error))
124-
GeneralTracer.Warn($"Script warning: {error}");
125-
126-
if (process.ExitCode != 0)
127-
throw new Exception($"Script execution failed, exit code: {process.ExitCode}");
128-
129-
GeneralTracer.Info("Script executed successfully");
130-
}
131-
catch (Exception ex)
132-
{
133-
GeneralTracer.Error("An exception occurred while executing the script", ex);
134-
EventManager.Instance.Dispatch(this, new ExceptionEventArgs(ex, "Script execution failed"));
135-
}
136-
}
13775
}

0 commit comments

Comments
 (0)