installer: wizard C# Windows d'installation guidee (WSL2, Podman, agent, desinstallation)
This commit is contained in:
@@ -0,0 +1,78 @@
|
|||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace StudioE5.SetupWizard;
|
||||||
|
|
||||||
|
public enum WizardStep
|
||||||
|
{
|
||||||
|
Welcome,
|
||||||
|
Prerequisites,
|
||||||
|
InstallVirtualEnvironment,
|
||||||
|
RestartRequired,
|
||||||
|
InstallPodman,
|
||||||
|
ConfigurePodman,
|
||||||
|
InstallAgent,
|
||||||
|
Finished,
|
||||||
|
Uninstall
|
||||||
|
}
|
||||||
|
|
||||||
|
public class InstallerState
|
||||||
|
{
|
||||||
|
[JsonPropertyName("step")]
|
||||||
|
public WizardStep Step { get; set; } = WizardStep.Welcome;
|
||||||
|
|
||||||
|
[JsonPropertyName("virtualEnvironmentInstalled")]
|
||||||
|
public bool VirtualEnvironmentInstalled { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("podmanInstalled")]
|
||||||
|
public bool PodmanInstalled { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("podmanConfigured")]
|
||||||
|
public bool PodmanConfigured { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("agentInstalled")]
|
||||||
|
public bool AgentInstalled { get; set; }
|
||||||
|
|
||||||
|
private static string StateFilePath
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var dir = Path.Combine(
|
||||||
|
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
|
||||||
|
"studioE5",
|
||||||
|
"installer");
|
||||||
|
Directory.CreateDirectory(dir);
|
||||||
|
return Path.Combine(dir, "installer-state.json");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static InstallerState Load()
|
||||||
|
{
|
||||||
|
var path = StateFilePath;
|
||||||
|
if (!File.Exists(path))
|
||||||
|
return new InstallerState();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var json = File.ReadAllText(path);
|
||||||
|
return JsonSerializer.Deserialize<InstallerState>(json) ?? new InstallerState();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return new InstallerState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Save()
|
||||||
|
{
|
||||||
|
var json = JsonSerializer.Serialize(this, new JsonSerializerOptions { WriteIndented = true });
|
||||||
|
File.WriteAllText(StateFilePath, json);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Delete()
|
||||||
|
{
|
||||||
|
var path = StateFilePath;
|
||||||
|
if (File.Exists(path))
|
||||||
|
File.Delete(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,662 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
using System.Reflection;
|
||||||
|
using Microsoft.Win32;
|
||||||
|
|
||||||
|
namespace StudioE5.SetupWizard;
|
||||||
|
|
||||||
|
public partial class MainForm : Form
|
||||||
|
{
|
||||||
|
private readonly InstallerState _state;
|
||||||
|
private readonly Panel _contentPanel;
|
||||||
|
private readonly Button _btnBack;
|
||||||
|
private readonly Button _btnNext;
|
||||||
|
private readonly Button _btnCancel;
|
||||||
|
private readonly Label _titleLabel;
|
||||||
|
private readonly Label _subtitleLabel;
|
||||||
|
|
||||||
|
private WizardStep _currentStep = WizardStep.Welcome;
|
||||||
|
private PrerequisiteResult? _lastCheck;
|
||||||
|
|
||||||
|
public MainForm(bool startInUninstallMode = false)
|
||||||
|
{
|
||||||
|
_state = InstallerState.Load();
|
||||||
|
Text = startInUninstallMode ? "Désinstallation studioE5" : "Installateur studioE5 Agent";
|
||||||
|
Size = new Size(700, 520);
|
||||||
|
StartPosition = FormStartPosition.CenterScreen;
|
||||||
|
FormBorderStyle = FormBorderStyle.FixedDialog;
|
||||||
|
MaximizeBox = false;
|
||||||
|
MinimizeBox = false;
|
||||||
|
|
||||||
|
_titleLabel = new Label
|
||||||
|
{
|
||||||
|
Left = 24,
|
||||||
|
Top = 18,
|
||||||
|
Width = 640,
|
||||||
|
Height = 32,
|
||||||
|
Font = new Font("Segoe UI", 14, FontStyle.Bold),
|
||||||
|
Text = "Installateur studioE5 Agent"
|
||||||
|
};
|
||||||
|
|
||||||
|
_subtitleLabel = new Label
|
||||||
|
{
|
||||||
|
Left = 24,
|
||||||
|
Top = 50,
|
||||||
|
Width = 640,
|
||||||
|
Height = 24,
|
||||||
|
Font = new Font("Segoe UI", 9),
|
||||||
|
ForeColor = Color.Gray
|
||||||
|
};
|
||||||
|
|
||||||
|
_contentPanel = new Panel
|
||||||
|
{
|
||||||
|
Left = 24,
|
||||||
|
Top = 84,
|
||||||
|
Width = 640,
|
||||||
|
Height = 320,
|
||||||
|
BorderStyle = BorderStyle.None
|
||||||
|
};
|
||||||
|
|
||||||
|
var separator = new Panel
|
||||||
|
{
|
||||||
|
Left = 0,
|
||||||
|
Top = 416,
|
||||||
|
Width = 700,
|
||||||
|
Height = 1,
|
||||||
|
BackColor = Color.LightGray,
|
||||||
|
Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom
|
||||||
|
};
|
||||||
|
|
||||||
|
_btnBack = new Button
|
||||||
|
{
|
||||||
|
Left = 360,
|
||||||
|
Top = 440,
|
||||||
|
Width = 100,
|
||||||
|
Height = 30,
|
||||||
|
Text = "< Précédent",
|
||||||
|
Visible = false
|
||||||
|
};
|
||||||
|
_btnBack.Click += (s, e) => GoBack();
|
||||||
|
|
||||||
|
_btnNext = new Button
|
||||||
|
{
|
||||||
|
Left = 470,
|
||||||
|
Top = 440,
|
||||||
|
Width = 100,
|
||||||
|
Height = 30,
|
||||||
|
Text = "Suivant >"
|
||||||
|
};
|
||||||
|
_btnNext.Click += (s, e) => GoNext();
|
||||||
|
|
||||||
|
_btnCancel = new Button
|
||||||
|
{
|
||||||
|
Left = 584,
|
||||||
|
Top = 440,
|
||||||
|
Width = 80,
|
||||||
|
Height = 30,
|
||||||
|
Text = "Annuler"
|
||||||
|
};
|
||||||
|
_btnCancel.Click += (s, e) => Application.Exit();
|
||||||
|
|
||||||
|
Controls.Add(_titleLabel);
|
||||||
|
Controls.Add(_subtitleLabel);
|
||||||
|
Controls.Add(_contentPanel);
|
||||||
|
Controls.Add(separator);
|
||||||
|
Controls.Add(_btnBack);
|
||||||
|
Controls.Add(_btnNext);
|
||||||
|
Controls.Add(_btnCancel);
|
||||||
|
|
||||||
|
if (startInUninstallMode)
|
||||||
|
{
|
||||||
|
GoToStep(WizardStep.Uninstall);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResumeAfterReboot();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ResumeAfterReboot()
|
||||||
|
{
|
||||||
|
// If we are resuming after a reboot, skip directly to the relevant step.
|
||||||
|
if (_state.VirtualEnvironmentInstalled && !_state.PodmanInstalled)
|
||||||
|
{
|
||||||
|
GoToStep(WizardStep.InstallPodman);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (_state.PodmanInstalled && !_state.PodmanConfigured)
|
||||||
|
{
|
||||||
|
GoToStep(WizardStep.ConfigurePodman);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (_state.PodmanConfigured && !_state.AgentInstalled)
|
||||||
|
{
|
||||||
|
GoToStep(WizardStep.InstallAgent);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GoToStep(WizardStep.Welcome);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GoBack()
|
||||||
|
{
|
||||||
|
switch (_currentStep)
|
||||||
|
{
|
||||||
|
case WizardStep.Prerequisites:
|
||||||
|
GoToStep(WizardStep.Welcome);
|
||||||
|
break;
|
||||||
|
case WizardStep.InstallVirtualEnvironment:
|
||||||
|
case WizardStep.RestartRequired:
|
||||||
|
GoToStep(WizardStep.Prerequisites);
|
||||||
|
break;
|
||||||
|
case WizardStep.InstallPodman:
|
||||||
|
GoToStep(WizardStep.Prerequisites);
|
||||||
|
break;
|
||||||
|
case WizardStep.ConfigurePodman:
|
||||||
|
GoToStep(WizardStep.InstallPodman);
|
||||||
|
break;
|
||||||
|
case WizardStep.InstallAgent:
|
||||||
|
GoToStep(WizardStep.ConfigurePodman);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GoNext()
|
||||||
|
{
|
||||||
|
switch (_currentStep)
|
||||||
|
{
|
||||||
|
case WizardStep.Welcome:
|
||||||
|
GoToStep(WizardStep.Prerequisites);
|
||||||
|
break;
|
||||||
|
case WizardStep.Prerequisites:
|
||||||
|
if (_lastCheck?.VirtualEnvironmentInstalled == true)
|
||||||
|
GoToStep(WizardStep.InstallPodman);
|
||||||
|
else
|
||||||
|
GoToStep(WizardStep.InstallVirtualEnvironment);
|
||||||
|
break;
|
||||||
|
case WizardStep.InstallVirtualEnvironment:
|
||||||
|
InstallVirtualEnvironment();
|
||||||
|
break;
|
||||||
|
case WizardStep.RestartRequired:
|
||||||
|
Application.Exit();
|
||||||
|
break;
|
||||||
|
case WizardStep.InstallPodman:
|
||||||
|
InstallPodman();
|
||||||
|
break;
|
||||||
|
case WizardStep.ConfigurePodman:
|
||||||
|
ConfigurePodman();
|
||||||
|
break;
|
||||||
|
case WizardStep.InstallAgent:
|
||||||
|
InstallAgent();
|
||||||
|
break;
|
||||||
|
case WizardStep.Finished:
|
||||||
|
Application.Exit();
|
||||||
|
break;
|
||||||
|
case WizardStep.Uninstall:
|
||||||
|
RunUninstall();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GoToStep(WizardStep step)
|
||||||
|
{
|
||||||
|
_currentStep = step;
|
||||||
|
_state.Step = step;
|
||||||
|
_state.Save();
|
||||||
|
_contentPanel.Controls.Clear();
|
||||||
|
|
||||||
|
switch (step)
|
||||||
|
{
|
||||||
|
case WizardStep.Welcome:
|
||||||
|
ShowWelcome();
|
||||||
|
break;
|
||||||
|
case WizardStep.Prerequisites:
|
||||||
|
ShowPrerequisites();
|
||||||
|
break;
|
||||||
|
case WizardStep.InstallVirtualEnvironment:
|
||||||
|
ShowInstallVirtualEnvironment();
|
||||||
|
break;
|
||||||
|
case WizardStep.RestartRequired:
|
||||||
|
ShowRestartRequired();
|
||||||
|
break;
|
||||||
|
case WizardStep.InstallPodman:
|
||||||
|
ShowInstallPodman();
|
||||||
|
break;
|
||||||
|
case WizardStep.ConfigurePodman:
|
||||||
|
ShowConfigurePodman();
|
||||||
|
break;
|
||||||
|
case WizardStep.InstallAgent:
|
||||||
|
ShowInstallAgent();
|
||||||
|
break;
|
||||||
|
case WizardStep.Finished:
|
||||||
|
ShowFinished();
|
||||||
|
break;
|
||||||
|
case WizardStep.Uninstall:
|
||||||
|
ShowUninstall();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowWelcome()
|
||||||
|
{
|
||||||
|
_titleLabel.Text = "Bienvenue dans l'installateur studioE5";
|
||||||
|
_subtitleLabel.Text = "Cet assistant va vous guider pour installer studioE5 Agent sur votre poste.";
|
||||||
|
|
||||||
|
var label = new Label
|
||||||
|
{
|
||||||
|
Left = 0,
|
||||||
|
Top = 20,
|
||||||
|
Width = _contentPanel.Width,
|
||||||
|
Height = 200,
|
||||||
|
Text = "L'installation se déroule en plusieurs étapes :\n\n" +
|
||||||
|
"1. Vérification des prérequis\n" +
|
||||||
|
"2. Installation de l'environnement virtuel (si nécessaire)\n" +
|
||||||
|
"3. Installation de Podman\n" +
|
||||||
|
"4. Configuration de Podman\n" +
|
||||||
|
"5. Installation de studioE5 Agent\n\n" +
|
||||||
|
"Cliquez sur 'Suivant' pour commencer.",
|
||||||
|
Font = new Font("Segoe UI", 10)
|
||||||
|
};
|
||||||
|
|
||||||
|
_contentPanel.Controls.Add(label);
|
||||||
|
|
||||||
|
_btnBack.Visible = false;
|
||||||
|
_btnNext.Text = "Suivant >";
|
||||||
|
_btnNext.Enabled = true;
|
||||||
|
_btnCancel.Text = "Annuler";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowPrerequisites()
|
||||||
|
{
|
||||||
|
_titleLabel.Text = "Vérification des prérequis";
|
||||||
|
_subtitleLabel.Text = "Assurez-vous que votre poste est prêt avant de continuer.";
|
||||||
|
|
||||||
|
_lastCheck = PrerequisiteChecker.Check();
|
||||||
|
var result = _lastCheck;
|
||||||
|
|
||||||
|
var text = $"Système d'exploitation : {(result.WindowsCompatible ? "✅ Compatible" : "❌ Non compatible (Windows 10 2004+ requis)")}\n" +
|
||||||
|
$"Mémoire vive (RAM) : {(result.RamMB >= 8192 ? "✅" : result.RamMB >= 4096 ? "⚠️" : "❌")} {result.RamMB} Mo (8 Go recommandés)\n" +
|
||||||
|
$"Espace disque disponible : {(result.FreeDiskMB >= 10240 ? "✅" : result.FreeDiskMB >= 5120 ? "⚠️" : "❌")} {result.FreeDiskMB} Mo (10 Go recommandés)\n" +
|
||||||
|
$"Environnement virtuel : {(result.VirtualEnvironmentInstalled ? "✅ Installé" : "❌ Non installé")}\n" +
|
||||||
|
$"Podman : {(result.PodmanInstalled ? "✅ Installé" : "❌ Non installé")}\n" +
|
||||||
|
$"Machine Podman : {(result.PodmanMachineReady ? "✅ Prête" : "❌ Non prête")}\n\n";
|
||||||
|
|
||||||
|
if (result.AllReady)
|
||||||
|
{
|
||||||
|
text += "Tous les prérequis sont satisfaits. Vous pouvez continuer.";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
text += "Ordre d'installation recommandé :\n" +
|
||||||
|
"1. Installer l'environnement virtuel\n" +
|
||||||
|
"2. Installer Podman\n" +
|
||||||
|
"3. Configurer Podman\n" +
|
||||||
|
"4. Installer studioE5 Agent";
|
||||||
|
}
|
||||||
|
|
||||||
|
var label = new Label
|
||||||
|
{
|
||||||
|
Left = 0,
|
||||||
|
Top = 20,
|
||||||
|
Width = _contentPanel.Width,
|
||||||
|
Height = 240,
|
||||||
|
Text = text,
|
||||||
|
Font = new Font("Consolas", 10),
|
||||||
|
ForeColor = Color.Black
|
||||||
|
};
|
||||||
|
|
||||||
|
_contentPanel.Controls.Add(label);
|
||||||
|
|
||||||
|
_btnBack.Visible = true;
|
||||||
|
_btnNext.Text = result.AllReady ? "Suivant >" : (result.VirtualEnvironmentInstalled ? "Installer Podman" : "Installer l'environnement virtuel");
|
||||||
|
_btnNext.Enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowInstallVirtualEnvironment()
|
||||||
|
{
|
||||||
|
_titleLabel.Text = "Installation de l'environnement virtuel";
|
||||||
|
_subtitleLabel.Text = "L'environnement virtuel permet de faire tourner Podman sur Windows.";
|
||||||
|
|
||||||
|
var label = new Label
|
||||||
|
{
|
||||||
|
Left = 0,
|
||||||
|
Top = 20,
|
||||||
|
Width = _contentPanel.Width,
|
||||||
|
Height = 120,
|
||||||
|
Text = "L'environnement virtuel (WSL2) n'est pas installé.\n\n" +
|
||||||
|
"Cliquez sur 'Installer' pour lancer l'installation.\n" +
|
||||||
|
"Un redémarrage de l'ordinateur sera nécessaire. L'installateur se relancera automatiquement.",
|
||||||
|
Font = new Font("Segoe UI", 10)
|
||||||
|
};
|
||||||
|
|
||||||
|
_contentPanel.Controls.Add(label);
|
||||||
|
|
||||||
|
_btnBack.Visible = true;
|
||||||
|
_btnNext.Text = "Installer";
|
||||||
|
_btnNext.Enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InstallVirtualEnvironment()
|
||||||
|
{
|
||||||
|
_btnNext.Enabled = false;
|
||||||
|
_btnBack.Enabled = false;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
RunCommand("wsl.exe", "--install --no-distribution", "Installation de l'environnement virtuel en cours...");
|
||||||
|
_state.VirtualEnvironmentInstalled = true;
|
||||||
|
_state.Save();
|
||||||
|
RegisterRunOnce();
|
||||||
|
GoToStep(WizardStep.RestartRequired);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
MessageBox.Show($"Erreur lors de l'installation de l'environnement virtuel : {ex.Message}", "Erreur", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_btnNext.Enabled = true;
|
||||||
|
_btnBack.Enabled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowRestartRequired()
|
||||||
|
{
|
||||||
|
_titleLabel.Text = "Redémarrage nécessaire";
|
||||||
|
_subtitleLabel.Text = "L'environnement virtuel a été installé.";
|
||||||
|
|
||||||
|
var label = new Label
|
||||||
|
{
|
||||||
|
Left = 0,
|
||||||
|
Top = 20,
|
||||||
|
Width = _contentPanel.Width,
|
||||||
|
Height = 120,
|
||||||
|
Text = "Veuillez redémarrer votre ordinateur pour finaliser l'installation de l'environnement virtuel.\n\n" +
|
||||||
|
"L'installateur se relancera automatiquement après le redémarrage pour continuer l'installation.",
|
||||||
|
Font = new Font("Segoe UI", 10)
|
||||||
|
};
|
||||||
|
|
||||||
|
_contentPanel.Controls.Add(label);
|
||||||
|
|
||||||
|
_btnBack.Visible = false;
|
||||||
|
_btnNext.Text = "Redémarrer maintenant";
|
||||||
|
_btnNext.Enabled = true;
|
||||||
|
_btnCancel.Text = "Redémarrer plus tard";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowInstallPodman()
|
||||||
|
{
|
||||||
|
_titleLabel.Text = "Installation de Podman";
|
||||||
|
_subtitleLabel.Text = "Podman est le moteur de conteneurs utilisé par studioE5.";
|
||||||
|
|
||||||
|
var label = new Label
|
||||||
|
{
|
||||||
|
Left = 0,
|
||||||
|
Top = 20,
|
||||||
|
Width = _contentPanel.Width,
|
||||||
|
Height = 120,
|
||||||
|
Text = "Podman va être installé sur votre poste.\n\n" +
|
||||||
|
"Cliquez sur 'Installer' pour lancer l'installation silencieuse.",
|
||||||
|
Font = new Font("Segoe UI", 10)
|
||||||
|
};
|
||||||
|
|
||||||
|
_contentPanel.Controls.Add(label);
|
||||||
|
|
||||||
|
_btnBack.Visible = true;
|
||||||
|
_btnNext.Text = "Installer Podman";
|
||||||
|
_btnNext.Enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InstallPodman()
|
||||||
|
{
|
||||||
|
_btnNext.Enabled = false;
|
||||||
|
_btnBack.Enabled = false;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var msiPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? ".", "Resources", "podman-setup.msi");
|
||||||
|
if (!File.Exists(msiPath))
|
||||||
|
throw new FileNotFoundException("Le fichier podman-setup.msi est introuvable. Vérifiez qu'il est bien inclus dans le package.");
|
||||||
|
|
||||||
|
RunCommand("msiexec.exe", $"/i \"{msiPath}\" /qn /norestart", "Installation de Podman en cours...");
|
||||||
|
_state.PodmanInstalled = true;
|
||||||
|
_state.Save();
|
||||||
|
GoToStep(WizardStep.ConfigurePodman);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
MessageBox.Show($"Erreur lors de l'installation de Podman : {ex.Message}", "Erreur", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_btnNext.Enabled = true;
|
||||||
|
_btnBack.Enabled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowConfigurePodman()
|
||||||
|
{
|
||||||
|
_titleLabel.Text = "Configuration de Podman";
|
||||||
|
_subtitleLabel.Text = "Initialisation de la machine Podman.";
|
||||||
|
|
||||||
|
var label = new Label
|
||||||
|
{
|
||||||
|
Left = 0,
|
||||||
|
Top = 20,
|
||||||
|
Width = _contentPanel.Width,
|
||||||
|
Height = 120,
|
||||||
|
Text = "La machine virtuelle Podman va être créée et démarrée.\n\n" +
|
||||||
|
"Cette opération peut prendre plusieurs minutes la première fois.",
|
||||||
|
Font = new Font("Segoe UI", 10)
|
||||||
|
};
|
||||||
|
|
||||||
|
_contentPanel.Controls.Add(label);
|
||||||
|
|
||||||
|
_btnBack.Visible = true;
|
||||||
|
_btnNext.Text = "Configurer Podman";
|
||||||
|
_btnNext.Enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ConfigurePodman()
|
||||||
|
{
|
||||||
|
_btnNext.Enabled = false;
|
||||||
|
_btnBack.Enabled = false;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
RunCommand("podman.exe", "machine init", "Initialisation de la machine Podman...");
|
||||||
|
RunCommand("podman.exe", "machine start", "Démarrage de la machine Podman...");
|
||||||
|
_state.PodmanConfigured = true;
|
||||||
|
_state.Save();
|
||||||
|
GoToStep(WizardStep.InstallAgent);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
MessageBox.Show($"Erreur lors de la configuration de Podman : {ex.Message}", "Erreur", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_btnNext.Enabled = true;
|
||||||
|
_btnBack.Enabled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowInstallAgent()
|
||||||
|
{
|
||||||
|
_titleLabel.Text = "Installation de studioE5 Agent";
|
||||||
|
_subtitleLabel.Text = "L'environnement est prêt. Il ne reste plus qu'à installer l'agent.";
|
||||||
|
|
||||||
|
var label = new Label
|
||||||
|
{
|
||||||
|
Left = 0,
|
||||||
|
Top = 20,
|
||||||
|
Width = _contentPanel.Width,
|
||||||
|
Height = 120,
|
||||||
|
Text = "Cliquez sur 'Installer studioE5 Agent' pour lancer le package d'installation.\n\n" +
|
||||||
|
"Une fois l'installation terminée, fermez cet assistant.",
|
||||||
|
Font = new Font("Segoe UI", 10)
|
||||||
|
};
|
||||||
|
|
||||||
|
_contentPanel.Controls.Add(label);
|
||||||
|
|
||||||
|
_btnBack.Visible = true;
|
||||||
|
_btnNext.Text = "Installer studioE5 Agent";
|
||||||
|
_btnNext.Enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InstallAgent()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var setupPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? ".", "Resources", "studioE5-agent-setup.exe");
|
||||||
|
if (!File.Exists(setupPath))
|
||||||
|
throw new FileNotFoundException("Le fichier studioE5-agent-setup.exe est introuvable. Vérifiez qu'il est bien inclus dans le package.");
|
||||||
|
|
||||||
|
var psi = new ProcessStartInfo(setupPath)
|
||||||
|
{
|
||||||
|
UseShellExecute = true,
|
||||||
|
Verb = "runas"
|
||||||
|
};
|
||||||
|
Process.Start(psi);
|
||||||
|
|
||||||
|
_state.AgentInstalled = true;
|
||||||
|
_state.Save();
|
||||||
|
GoToStep(WizardStep.Finished);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
MessageBox.Show($"Erreur lors du lancement de l'installation de l'agent : {ex.Message}", "Erreur", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowFinished()
|
||||||
|
{
|
||||||
|
_titleLabel.Text = "Installation terminée";
|
||||||
|
_subtitleLabel.Text = "studioE5 Agent est prêt à être utilisé.";
|
||||||
|
|
||||||
|
var label = new Label
|
||||||
|
{
|
||||||
|
Left = 0,
|
||||||
|
Top = 20,
|
||||||
|
Width = _contentPanel.Width,
|
||||||
|
Height = 120,
|
||||||
|
Text = "L'installation est terminée.\n\n" +
|
||||||
|
"Vous pouvez lancer studioE5 Agent depuis le menu Démarrer ou le bureau.",
|
||||||
|
Font = new Font("Segoe UI", 10)
|
||||||
|
};
|
||||||
|
|
||||||
|
_contentPanel.Controls.Add(label);
|
||||||
|
|
||||||
|
_btnBack.Visible = false;
|
||||||
|
_btnNext.Text = "Terminer";
|
||||||
|
_btnCancel.Text = "Fermer";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowUninstall()
|
||||||
|
{
|
||||||
|
_titleLabel.Text = "Désinstallation de studioE5";
|
||||||
|
_subtitleLabel.Text = "Suppression complète de studioE5 Agent et des composants associés.";
|
||||||
|
|
||||||
|
var label = new Label
|
||||||
|
{
|
||||||
|
Left = 0,
|
||||||
|
Top = 20,
|
||||||
|
Width = _contentPanel.Width,
|
||||||
|
Height = 200,
|
||||||
|
Text = "Cette opération va :\n\n" +
|
||||||
|
"- Arrêter studioE5 Agent\n" +
|
||||||
|
"- Désinstaller studioE5 Agent\n" +
|
||||||
|
"- Supprimer les données élèves\n" +
|
||||||
|
"- Désinstaller Podman\n" +
|
||||||
|
"- Proposer de désactiver l'environnement virtuel\n\n" +
|
||||||
|
"Cliquez sur 'Désinstaller' pour commencer.",
|
||||||
|
Font = new Font("Segoe UI", 10)
|
||||||
|
};
|
||||||
|
|
||||||
|
_contentPanel.Controls.Add(label);
|
||||||
|
|
||||||
|
_btnBack.Visible = false;
|
||||||
|
_btnNext.Text = "Désinstaller";
|
||||||
|
_btnCancel.Text = "Annuler";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RunUninstall()
|
||||||
|
{
|
||||||
|
_btnNext.Enabled = false;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 1. Kill agent
|
||||||
|
RunCommand("taskkill.exe", "/f /im studioE5-agent.exe", "Arrêt de studioE5 Agent...");
|
||||||
|
|
||||||
|
// 2. Uninstall agent via Inno Setup uninstaller
|
||||||
|
var agentUninstaller = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "studioE5-agent", "unins000.exe");
|
||||||
|
if (File.Exists(agentUninstaller))
|
||||||
|
RunCommand(agentUninstaller, "/SILENT", "Désinstallation de studioE5 Agent...");
|
||||||
|
|
||||||
|
// 3. Delete student data
|
||||||
|
var dataDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "studioE5-agent");
|
||||||
|
if (Directory.Exists(dataDir))
|
||||||
|
{
|
||||||
|
Directory.Delete(dataDir, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Uninstall Podman
|
||||||
|
var podmanMsiPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? ".", "Resources", "podman-setup.msi");
|
||||||
|
if (File.Exists(podmanMsiPath))
|
||||||
|
{
|
||||||
|
RunCommand("msiexec.exe", $"/x \"{podmanMsiPath}\" /qn /norestart", "Désinstallation de Podman...");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MessageBox.Show("Le MSI de Podman n'a pas été trouvé dans le package. Veuillez désinstaller Podman manuellement via Ajouter/Supprimer des programmes.", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. Optionally disable WSL2
|
||||||
|
var result = MessageBox.Show("Voulez-vous désactiver l'environnement virtuel (WSL2) ?", "Environnement virtuel", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
|
||||||
|
if (result == DialogResult.Yes)
|
||||||
|
{
|
||||||
|
RunCommand("wsl.exe", "--uninstall", "Désactivation de l'environnement virtuel...");
|
||||||
|
}
|
||||||
|
|
||||||
|
InstallerState.Delete();
|
||||||
|
MessageBox.Show("Désinstallation terminée.", "Terminé", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||||
|
Application.Exit();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
MessageBox.Show($"Erreur lors de la désinstallation : {ex.Message}", "Erreur", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_btnNext.Enabled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RunCommand(string fileName, string arguments, string description)
|
||||||
|
{
|
||||||
|
var psi = new ProcessStartInfo(fileName, arguments)
|
||||||
|
{
|
||||||
|
UseShellExecute = false,
|
||||||
|
CreateNoWindow = true,
|
||||||
|
RedirectStandardOutput = true,
|
||||||
|
RedirectStandardError = true
|
||||||
|
};
|
||||||
|
|
||||||
|
using var process = Process.Start(psi);
|
||||||
|
if (process == null)
|
||||||
|
throw new InvalidOperationException($"Impossible de démarrer {fileName}");
|
||||||
|
|
||||||
|
process.WaitForExit();
|
||||||
|
if (process.ExitCode != 0)
|
||||||
|
{
|
||||||
|
var error = process.StandardError.ReadToEnd();
|
||||||
|
throw new InvalidOperationException($"{description} a échoué (code {process.ExitCode}) : {error}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RegisterRunOnce()
|
||||||
|
{
|
||||||
|
var executablePath = Application.ExecutablePath;
|
||||||
|
var key = Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce", true);
|
||||||
|
key?.SetValue("StudioE5SetupWizard", $"\"{executablePath}\"");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,142 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
using System.Management;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace StudioE5.SetupWizard;
|
||||||
|
|
||||||
|
public record PrerequisiteResult(
|
||||||
|
bool WindowsCompatible,
|
||||||
|
ulong RamMB,
|
||||||
|
ulong FreeDiskMB,
|
||||||
|
bool VirtualEnvironmentInstalled,
|
||||||
|
bool PodmanInstalled,
|
||||||
|
bool PodmanMachineReady)
|
||||||
|
{
|
||||||
|
public bool AllReady => WindowsCompatible && RamMB >= 4096 && FreeDiskMB >= 5120 && VirtualEnvironmentInstalled && PodmanInstalled && PodmanMachineReady;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class PrerequisiteChecker
|
||||||
|
{
|
||||||
|
public static PrerequisiteResult Check()
|
||||||
|
{
|
||||||
|
return new PrerequisiteResult(
|
||||||
|
WindowsCompatible: IsWindowsCompatible(),
|
||||||
|
RamMB: GetTotalPhysicalMemoryMB(),
|
||||||
|
FreeDiskMB: GetFreeDiskSpaceMB("C:\\"),
|
||||||
|
VirtualEnvironmentInstalled: IsWSLInstalled(),
|
||||||
|
PodmanInstalled: IsPodmanInstalled(),
|
||||||
|
PodmanMachineReady: IsPodmanMachineReady()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsWindowsCompatible()
|
||||||
|
{
|
||||||
|
var os = Environment.OSVersion;
|
||||||
|
if (os.Platform != PlatformID.Win32NT)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Windows 10 version 2004 (build 19041) or Windows 11.
|
||||||
|
return Environment.OSVersion.Version.Build >= 19041;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ulong GetTotalPhysicalMemoryMB()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var searcher = new ManagementObjectSearcher("SELECT TotalVisibleMemorySize FROM Win32_OperatingSystem");
|
||||||
|
foreach (ManagementObject obj in searcher.Get())
|
||||||
|
{
|
||||||
|
var kb = Convert.ToUInt64(obj["TotalVisibleMemorySize"]);
|
||||||
|
return kb / 1024;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ulong GetFreeDiskSpaceMB(string path)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var drive = new DriveInfo(Path.GetPathRoot(path) ?? path);
|
||||||
|
return (ulong)(drive.AvailableFreeSpace / (1024 * 1024));
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsWSLInstalled()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var psi = new ProcessStartInfo("wsl.exe", "--version")
|
||||||
|
{
|
||||||
|
UseShellExecute = false,
|
||||||
|
CreateNoWindow = true,
|
||||||
|
RedirectStandardOutput = true,
|
||||||
|
RedirectStandardError = true
|
||||||
|
};
|
||||||
|
using var process = Process.Start(psi);
|
||||||
|
if (process == null) return false;
|
||||||
|
process.WaitForExit();
|
||||||
|
return process.ExitCode == 0;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsPodmanInstalled()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var psi = new ProcessStartInfo("podman.exe", "--version")
|
||||||
|
{
|
||||||
|
UseShellExecute = false,
|
||||||
|
CreateNoWindow = true,
|
||||||
|
RedirectStandardOutput = true,
|
||||||
|
RedirectStandardError = true
|
||||||
|
};
|
||||||
|
using var process = Process.Start(psi);
|
||||||
|
if (process == null) return false;
|
||||||
|
process.WaitForExit();
|
||||||
|
return process.ExitCode == 0;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsPodmanMachineReady()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var psi = new ProcessStartInfo("podman.exe", "machine list --format json")
|
||||||
|
{
|
||||||
|
UseShellExecute = false,
|
||||||
|
CreateNoWindow = true,
|
||||||
|
RedirectStandardOutput = true,
|
||||||
|
RedirectStandardError = true
|
||||||
|
};
|
||||||
|
using var process = Process.Start(psi);
|
||||||
|
if (process == null) return false;
|
||||||
|
var output = process.StandardOutput.ReadToEnd();
|
||||||
|
process.WaitForExit();
|
||||||
|
if (process.ExitCode != 0) return false;
|
||||||
|
|
||||||
|
// Very permissive check: if podman machine list returns any JSON, we consider it ready.
|
||||||
|
return output.TrimStart().StartsWith("[") || output.TrimStart().StartsWith("{");
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
using StudioE5.SetupWizard;
|
||||||
|
|
||||||
|
static class Program
|
||||||
|
{
|
||||||
|
[STAThread]
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
ApplicationConfiguration.Initialize();
|
||||||
|
|
||||||
|
if (args.Contains("/uninstall", StringComparer.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
Application.Run(new MainForm(startInUninstallMode: true));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Application.Run(new MainForm(startInUninstallMode: false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
# StudioE5 Setup Wizard
|
||||||
|
|
||||||
|
Assistant d’installation graphique Windows pour studioE5 Agent.
|
||||||
|
|
||||||
|
## Rôle
|
||||||
|
|
||||||
|
Ce wizard guide l’utilisateur pas à pas pour :
|
||||||
|
|
||||||
|
1. Vérifier les prérequis (RAM, disque, Windows, environnement virtuel, Podman).
|
||||||
|
2. Installer l’**environnement virtuel** (WSL2) si nécessaire, avec reprise après redémarrage.
|
||||||
|
3. Installer **Podman** depuis le MSI bundlé.
|
||||||
|
4. Initialiser et démarrer la **machine Podman**.
|
||||||
|
5. Lancer le package **Inno Setup** de studioE5 Agent.
|
||||||
|
|
||||||
|
Il propose aussi un mode **désinstallation** complet (`/uninstall`).
|
||||||
|
|
||||||
|
## Prérequis de build
|
||||||
|
|
||||||
|
- Windows 10/11
|
||||||
|
- [.NET 8 SDK](https://dotnet.microsoft.com/download/dotnet/8.0)
|
||||||
|
- Visual Studio 2022 ou Visual Studio Code (optionnel)
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
```text
|
||||||
|
setup-wizard/
|
||||||
|
├── SetupWizard.csproj
|
||||||
|
├── Program.cs
|
||||||
|
├── MainForm.cs
|
||||||
|
├── InstallerState.cs
|
||||||
|
├── PrerequisiteChecker.cs
|
||||||
|
└── Resources/
|
||||||
|
├── podman-setup.msi # MSI officiel Podman pour Windows
|
||||||
|
└── studioE5-agent-setup.exe # Package Inno Setup de l'agent
|
||||||
|
```
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
Ouvrir un terminal PowerShell dans ce dossier et exécuter :
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
dotnet build -c Release
|
||||||
|
```
|
||||||
|
|
||||||
|
Pour publier un exécutable autonome (pas besoin du runtime .NET sur le poste cible) :
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
dotnet publish -c Release -r win-x64 --self-contained true /p:PublishSingleFile=true
|
||||||
|
```
|
||||||
|
|
||||||
|
L’exécutable se trouve dans :
|
||||||
|
|
||||||
|
```text
|
||||||
|
bin\Release\net8.0-windows\win-x64\publish\StudioE5-SetupWizard.exe
|
||||||
|
```
|
||||||
|
|
||||||
|
## Préparation du package
|
||||||
|
|
||||||
|
1. Télécharger le MSI Podman Windows :
|
||||||
|
<https://github.com/containers/podman/releases>
|
||||||
|
2. Le renommer en `podman-setup.msi` et le placer dans `Resources/`.
|
||||||
|
3. Générer le package Inno Setup de l’agent (`studioE5-agent-setup.exe`) et le placer dans `Resources/`.
|
||||||
|
4. Builder et publier le wizard.
|
||||||
|
|
||||||
|
## Lancement
|
||||||
|
|
||||||
|
### Mode installation
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
.\StudioE5-SetupWizard.exe
|
||||||
|
```
|
||||||
|
|
||||||
|
### Mode désinstallation
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
.\StudioE5-SetupWizard.exe /uninstall
|
||||||
|
```
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- Le wizard doit être exécuté **en administrateur**.
|
||||||
|
- L’installation de WSL2 nécessite un **redémarrage** de l’ordinateur. Le wizard s’enregistre dans `RunOnce` pour se relancer automatiquement.
|
||||||
|
- Le MSI Podman doit correspondre à l’architecture `x64`.
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>WinExe</OutputType>
|
||||||
|
<TargetFramework>net8.0-windows</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<UseWindowsForms>true</UseWindowsForms>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<RootNamespace>StudioE5.SetupWizard</RootNamespace>
|
||||||
|
<AssemblyName>StudioE5-SetupWizard</AssemblyName>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="Resources\podman-setup.msi">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="Resources\studioE5-agent-setup.exe">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,190 @@
|
|||||||
|
; studioE5 Agent Installer (Inno Setup)
|
||||||
|
; Build with Inno Setup Compiler (ISCC) on Windows.
|
||||||
|
; This installer bundles the agent and Tailscale binaries. It checks
|
||||||
|
; prerequisites and guides the user through installing missing system
|
||||||
|
; components (WSL2 + Podman) before installing studioE5.
|
||||||
|
|
||||||
|
#define MyAppName "studioE5 Agent"
|
||||||
|
#define MyAppVersion "0.3.17"
|
||||||
|
#define MyAppPublisher "studioE5"
|
||||||
|
#define MyAppURL "https://studioe5.edudeploy.com"
|
||||||
|
#define MyAppExeName "studioE5-agent.exe"
|
||||||
|
|
||||||
|
[Setup]
|
||||||
|
AppId={{studioE5-agent-ondemand}
|
||||||
|
AppName={#MyAppName}
|
||||||
|
AppVersion={#MyAppVersion}
|
||||||
|
AppPublisher={#MyAppPublisher}
|
||||||
|
AppPublisherURL={#MyAppURL}
|
||||||
|
AppSupportURL={#MyAppURL}
|
||||||
|
AppUpdatesURL={#MyAppURL}
|
||||||
|
DefaultDirName={autopf}\studioE5-agent
|
||||||
|
DisableProgramGroupPage=yes
|
||||||
|
OutputDir=..\..\installer-output
|
||||||
|
OutputBaseFilename=studioE5-agent-{#MyAppVersion}-setup
|
||||||
|
Compression=lzma
|
||||||
|
SolidCompression=yes
|
||||||
|
WizardStyle=modern
|
||||||
|
PrivilegesRequired=admin
|
||||||
|
ArchitecturesAllowed=x64
|
||||||
|
ArchitecturesInstallIn64BitMode=x64
|
||||||
|
[Languages]
|
||||||
|
Name: "french"; MessagesFile: "compiler:Languages\French.isl"
|
||||||
|
|
||||||
|
[Tasks]
|
||||||
|
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
|
||||||
|
|
||||||
|
[Files]
|
||||||
|
Source: "..\..\agent\studioE5-agent.exe"; DestDir: "{app}"; Flags: ignoreversion
|
||||||
|
Source: "..\..\agent\tailscale-bin\windows\tailscale.exe"; DestDir: "{app}\tailscale-bin\windows"; Flags: ignoreversion
|
||||||
|
Source: "..\..\agent\tailscale-bin\windows\tailscaled.exe"; DestDir: "{app}\tailscale-bin\windows"; Flags: ignoreversion
|
||||||
|
Source: "..\..\agent\tailscale-bin\windows\wintun.dll"; DestDir: "{app}\tailscale-bin\windows"; Flags: ignoreversion
|
||||||
|
Source: "..\..\README.md"; DestDir: "{app}"; Flags: ignoreversion
|
||||||
|
|
||||||
|
[Icons]
|
||||||
|
Name: "{autoprograms}\studioE5 Agent"; Filename: "{app}\{#MyAppExeName}"
|
||||||
|
Name: "{autodesktop}\studioE5 Agent"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
|
||||||
|
|
||||||
|
[Run]
|
||||||
|
Filename: "{app}\{#MyAppExeName}"; Description: "Lancer studioE5 Agent"; Flags: nowait postinstall skipifsilent
|
||||||
|
|
||||||
|
[UninstallRun]
|
||||||
|
Filename: "{cmd}"; Parameters: "/c taskkill /f /im studioE5-agent.exe"; Flags: runhidden waituntilterminated
|
||||||
|
|
||||||
|
[Code]
|
||||||
|
var
|
||||||
|
PrereqPage: TWizardPage;
|
||||||
|
lblStatus: TLabel;
|
||||||
|
btnCheck: TButton;
|
||||||
|
|
||||||
|
function GetPhysicallyInstalledSystemMemoryKB(var TotalMemoryInKilobytes: Int64): Boolean;
|
||||||
|
external 'GetPhysicallyInstalledSystemMemory@kernel32.dll stdcall';
|
||||||
|
|
||||||
|
function GetTotalPhysicalMemoryMB(): Cardinal;
|
||||||
|
var
|
||||||
|
MemKB: Int64;
|
||||||
|
begin
|
||||||
|
if GetPhysicallyInstalledSystemMemoryKB(MemKB) then
|
||||||
|
Result := Cardinal(MemKB div 1024)
|
||||||
|
else
|
||||||
|
Result := 0;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function IsWSL2Installed(): Boolean;
|
||||||
|
var
|
||||||
|
ResultCode: Integer;
|
||||||
|
begin
|
||||||
|
Result := Exec('wsl.exe', '--version', '', SW_HIDE, ewWaitUntilTerminated, ResultCode) and (ResultCode = 0);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function IsPodmanReady(): Boolean;
|
||||||
|
var
|
||||||
|
ResultCode: Integer;
|
||||||
|
begin
|
||||||
|
Result := Exec('podman.exe', 'machine list', '', SW_HIDE, ewWaitUntilTerminated, ResultCode) and (ResultCode = 0);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function GetFreeDiskSpaceMB(const Path: string): Cardinal;
|
||||||
|
var
|
||||||
|
FreeBytes, TotalBytes: Int64;
|
||||||
|
begin
|
||||||
|
if GetDiskFreeSpaceEx(Path, FreeBytes, TotalBytes, nil) then
|
||||||
|
Result := Cardinal(FreeBytes div (1024 * 1024))
|
||||||
|
else
|
||||||
|
Result := 0;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure UpdatePrereqStatus();
|
||||||
|
var
|
||||||
|
Msg: string;
|
||||||
|
RamMB, FreeMB: Cardinal;
|
||||||
|
WSLReady, PodmanReady: Boolean;
|
||||||
|
begin
|
||||||
|
RamMB := GetTotalPhysicalMemoryMB();
|
||||||
|
FreeMB := GetFreeDiskSpaceMB('C:\');
|
||||||
|
WSLReady := IsWSL2Installed();
|
||||||
|
PodmanReady := IsPodmanReady();
|
||||||
|
|
||||||
|
Msg := 'Vérification des prérequis :' + #13#10#13#10;
|
||||||
|
|
||||||
|
if RamMB >= 8192 then
|
||||||
|
Msg := Msg + '✅ Mémoire vive (RAM) : ' + IntToStr(RamMB div 1024) + ' Go' + #13#10
|
||||||
|
else
|
||||||
|
Msg := Msg + '⚠️ Mémoire vive (RAM) : ' + IntToStr(RamMB div 1024) + ' Go (8 Go recommandés)' + #13#10;
|
||||||
|
|
||||||
|
if FreeMB >= 10240 then
|
||||||
|
Msg := Msg + '✅ Espace disque disponible : ' + IntToStr(FreeMB div 1024) + ' Go' + #13#10
|
||||||
|
else
|
||||||
|
Msg := Msg + '⚠️ Espace disque disponible : ' + IntToStr(FreeMB div 1024) + ' Go (10 Go recommandés)' + #13#10;
|
||||||
|
|
||||||
|
if WSLReady then
|
||||||
|
Msg := Msg + '✅ Environnement de virtualisation (WSL2) installé' + #13#10
|
||||||
|
else
|
||||||
|
Msg := Msg + '❌ Environnement de virtualisation (WSL2) non installé' + #13#10;
|
||||||
|
|
||||||
|
if PodmanReady then
|
||||||
|
Msg := Msg + '✅ Service de conteneurs (Podman) prêt' + #13#10
|
||||||
|
else
|
||||||
|
Msg := Msg + '❌ Service de conteneurs (Podman) non prêt' + #13#10;
|
||||||
|
|
||||||
|
Msg := Msg + #13#10;
|
||||||
|
|
||||||
|
if WSLReady and PodmanReady and (RamMB >= 4096) and (FreeMB >= 5120) then
|
||||||
|
Msg := Msg + 'Tous les prérequis sont satisfaits. Vous pouvez installer studioE5 Agent.'
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
Msg := Msg + 'Ordre d''installation recommandé :' + #13#10;
|
||||||
|
if not WSLReady then
|
||||||
|
Msg := Msg + '1. Installer WSL2 : ouvrir PowerShell en administrateur et exécuter : wsl --install --no-distribution' + #13#10;
|
||||||
|
if not PodmanReady then
|
||||||
|
Msg := Msg + '2. Installer Podman : télécharger et exécuter le MSI depuis https://github.com/containers/podman/releases' + #13#10;
|
||||||
|
if not PodmanReady then
|
||||||
|
Msg := Msg + '3. Initialiser Podman : podman machine init && podman machine start' + #13#10;
|
||||||
|
Msg := Msg + #13#10 + 'Après avoir installé les éléments manquants, relancez cet installateur.';
|
||||||
|
end;
|
||||||
|
|
||||||
|
lblStatus.Caption := Msg;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure btnCheckClick(Sender: TObject);
|
||||||
|
begin
|
||||||
|
UpdatePrereqStatus();
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure InitializeWizard();
|
||||||
|
begin
|
||||||
|
PrereqPage := CreateCustomPage(wpWelcome, 'Vérification des prérequis', 'Assurez-vous que votre poste est prêt avant d''installer studioE5 Agent.');
|
||||||
|
|
||||||
|
lblStatus := TLabel.Create(WizardForm);
|
||||||
|
lblStatus.Parent := PrereqPage.Surface;
|
||||||
|
lblStatus.Left := 0;
|
||||||
|
lblStatus.Top := 0;
|
||||||
|
lblStatus.Width := PrereqPage.SurfaceWidth;
|
||||||
|
lblStatus.Height := 220;
|
||||||
|
lblStatus.AutoSize := False;
|
||||||
|
lblStatus.WordWrap := True;
|
||||||
|
|
||||||
|
btnCheck := TButton.Create(WizardForm);
|
||||||
|
btnCheck.Parent := PrereqPage.Surface;
|
||||||
|
btnCheck.Left := 0;
|
||||||
|
btnCheck.Top := lblStatus.Top + lblStatus.Height + 12;
|
||||||
|
btnCheck.Width := 160;
|
||||||
|
btnCheck.Height := 25;
|
||||||
|
btnCheck.Caption := 'Vérifier les prérequis';
|
||||||
|
btnCheck.OnClick := @btnCheckClick;
|
||||||
|
|
||||||
|
UpdatePrereqStatus();
|
||||||
|
end;
|
||||||
|
|
||||||
|
function NextButtonClick(CurPageID: Integer): Boolean;
|
||||||
|
begin
|
||||||
|
Result := True;
|
||||||
|
if CurPageID = PrereqPage.ID then
|
||||||
|
begin
|
||||||
|
if not (IsWSL2Installed() and IsPodmanReady()) then
|
||||||
|
begin
|
||||||
|
MsgBox('Certains prérequis sont manquants. Veuillez les installer avant de continuer.', mbError, MB_OK);
|
||||||
|
Result := False;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
Reference in New Issue
Block a user