feat(installer): async mode detection + mode-aware DI wiring
This commit is contained in:
@@ -1,3 +1,6 @@
|
|||||||
|
using System.IO;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Reflection;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using ClaudeDo.Installer.Core;
|
using ClaudeDo.Installer.Core;
|
||||||
using ClaudeDo.Installer.Pages.InstallPage;
|
using ClaudeDo.Installer.Pages.InstallPage;
|
||||||
@@ -15,16 +18,45 @@ public partial class App : Application
|
|||||||
{
|
{
|
||||||
private ServiceProvider? _services;
|
private ServiceProvider? _services;
|
||||||
|
|
||||||
protected override void OnStartup(StartupEventArgs e)
|
protected override async void OnStartup(StartupEventArgs e)
|
||||||
{
|
{
|
||||||
base.OnStartup(e);
|
base.OnStartup(e);
|
||||||
|
|
||||||
_services = BuildServices();
|
_services = BuildServices();
|
||||||
|
|
||||||
// TODO(Task 11): replace with async InstallModeDetector
|
var context = _services.GetRequiredService<InstallContext>();
|
||||||
Window mainWindow = new WizardWindow
|
context.InstallerVersion = GetInstallerVersion();
|
||||||
|
|
||||||
|
// Default install dir for detection — on upgrade we stay where we were.
|
||||||
|
var detector = _services.GetRequiredService<InstallModeDetector>();
|
||||||
|
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
|
||||||
|
DetectedState state;
|
||||||
|
try
|
||||||
{
|
{
|
||||||
DataContext = _services.GetRequiredService<WizardViewModel>()
|
state = await detector.DetectAsync(context.InstallDirectory, cts.Token);
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
state = new DetectedState(InstallerMode.FreshInstall, null, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Mode = state.Mode;
|
||||||
|
context.InstalledVersion = state.Existing?.Version;
|
||||||
|
context.LatestVersion = state.LatestVersion;
|
||||||
|
if (state.Existing is not null)
|
||||||
|
context.InstallDirectory = state.Existing.InstallDir;
|
||||||
|
|
||||||
|
Window mainWindow = state.Mode switch
|
||||||
|
{
|
||||||
|
InstallerMode.FreshInstall or InstallerMode.Update => new WizardWindow
|
||||||
|
{
|
||||||
|
DataContext = _services.GetRequiredService<WizardViewModel>()
|
||||||
|
},
|
||||||
|
InstallerMode.Config => new SettingsWindow
|
||||||
|
{
|
||||||
|
DataContext = _services.GetRequiredService<SettingsViewModel>()
|
||||||
|
},
|
||||||
|
_ => throw new InvalidOperationException($"Unknown installer mode: {state.Mode}")
|
||||||
};
|
};
|
||||||
|
|
||||||
DarkTitleBar.Apply(mainWindow);
|
DarkTitleBar.Apply(mainWindow);
|
||||||
@@ -37,6 +69,13 @@ public partial class App : Application
|
|||||||
base.OnExit(e);
|
base.OnExit(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string GetInstallerVersion()
|
||||||
|
{
|
||||||
|
var infoAttr = Assembly.GetExecutingAssembly()
|
||||||
|
.GetCustomAttribute<AssemblyInformationalVersionAttribute>();
|
||||||
|
return infoAttr?.InformationalVersion ?? "0.0.0";
|
||||||
|
}
|
||||||
|
|
||||||
private static ServiceProvider BuildServices()
|
private static ServiceProvider BuildServices()
|
||||||
{
|
{
|
||||||
var sc = new ServiceCollection();
|
var sc = new ServiceCollection();
|
||||||
@@ -46,6 +85,11 @@ public partial class App : Application
|
|||||||
sc.AddSingleton<PageResolver>();
|
sc.AddSingleton<PageResolver>();
|
||||||
sc.AddSingleton<InstallerService>();
|
sc.AddSingleton<InstallerService>();
|
||||||
|
|
||||||
|
// HTTP + release client
|
||||||
|
sc.AddSingleton(_ => new HttpClient { Timeout = TimeSpan.FromSeconds(15) });
|
||||||
|
sc.AddSingleton<IReleaseClient>(sp => new ReleaseClient(sp.GetRequiredService<HttpClient>()));
|
||||||
|
sc.AddSingleton<InstallModeDetector>();
|
||||||
|
|
||||||
// Pages
|
// Pages
|
||||||
sc.AddSingleton<IInstallerPage, WelcomePageViewModel>();
|
sc.AddSingleton<IInstallerPage, WelcomePageViewModel>();
|
||||||
sc.AddSingleton<IInstallerPage, PathsPageViewModel>();
|
sc.AddSingleton<IInstallerPage, PathsPageViewModel>();
|
||||||
@@ -53,11 +97,22 @@ public partial class App : Application
|
|||||||
sc.AddSingleton<IInstallerPage, UiSettingsPageViewModel>();
|
sc.AddSingleton<IInstallerPage, UiSettingsPageViewModel>();
|
||||||
sc.AddSingleton<IInstallerPage, InstallPageViewModel>();
|
sc.AddSingleton<IInstallerPage, InstallPageViewModel>();
|
||||||
|
|
||||||
// Steps (registration order = execution order)
|
// Steps — execution order matters for the FreshInstall pipeline (IEnumerable<IInstallStep>).
|
||||||
|
// Double-registered as both IInstallStep and concrete type so Task 15's Update pipeline
|
||||||
|
// can pull them out individually via GetRequiredService<T>().
|
||||||
|
sc.AddSingleton<DownloadAndExtractStep>();
|
||||||
|
sc.AddSingleton<IInstallStep>(sp => sp.GetRequiredService<DownloadAndExtractStep>());
|
||||||
sc.AddSingleton<IInstallStep, WriteConfigStep>();
|
sc.AddSingleton<IInstallStep, WriteConfigStep>();
|
||||||
sc.AddSingleton<IInstallStep, InitDatabaseStep>();
|
sc.AddSingleton<IInstallStep, InitDatabaseStep>();
|
||||||
sc.AddSingleton<IInstallStep, RegisterServiceStep>();
|
sc.AddSingleton<IInstallStep, RegisterServiceStep>();
|
||||||
sc.AddSingleton<IInstallStep, CreateShortcutsStep>();
|
sc.AddSingleton<IInstallStep, CreateShortcutsStep>();
|
||||||
|
sc.AddSingleton<WriteInstallManifestStep>();
|
||||||
|
sc.AddSingleton<IInstallStep>(sp => sp.GetRequiredService<WriteInstallManifestStep>());
|
||||||
|
|
||||||
|
// Stop/Start — NOT registered as IInstallStep (not part of default FreshInstall pipeline).
|
||||||
|
// Pulled by Update flow + Repair/Uninstall.
|
||||||
|
sc.AddSingleton<StopServiceStep>();
|
||||||
|
sc.AddSingleton<StartServiceStep>();
|
||||||
|
|
||||||
// ViewModels
|
// ViewModels
|
||||||
sc.AddSingleton<WizardViewModel>();
|
sc.AddSingleton<WizardViewModel>();
|
||||||
|
|||||||
Reference in New Issue
Block a user