diff --git a/.gitignore b/.gitignore index 1deccefe..1b41c376 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ /archive /release /applibs +/res/setup /docs diff --git a/BenchManager/BenchCLI/Properties/AssemblyInfo.cs b/BenchManager/BenchCLI/Properties/AssemblyInfo.cs index 2908700a..97135e18 100644 --- a/BenchManager/BenchCLI/Properties/AssemblyInfo.cs +++ b/BenchManager/BenchCLI/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ // Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern // übernehmen, indem Sie "*" eingeben: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.22.6.0")] -[assembly: AssemblyFileVersion("0.22.6.0")] +[assembly: AssemblyVersion("0.23.0.0")] +[assembly: AssemblyFileVersion("0.23.0.0")] diff --git a/BenchManager/BenchDashboard/ExportForm.Designer.cs b/BenchManager/BenchDashboard/ExportForm.Designer.cs index 77a152d2..507a5929 100644 --- a/BenchManager/BenchDashboard/ExportForm.Designer.cs +++ b/BenchManager/BenchDashboard/ExportForm.Designer.cs @@ -34,6 +34,8 @@ private void InitializeComponent() this.txtTarget = new System.Windows.Forms.TextBox(); this.lblTarget = new System.Windows.Forms.Label(); this.grpContentSelection = new System.Windows.Forms.GroupBox(); + this.lblAppsHint = new System.Windows.Forms.Label(); + this.lblCacheHint = new System.Windows.Forms.Label(); this.chkApps = new System.Windows.Forms.CheckBox(); this.chkCache = new System.Windows.Forms.CheckBox(); this.chkRequiredApps = new System.Windows.Forms.CheckBox(); @@ -51,8 +53,6 @@ private void InitializeComponent() this.panelFooter = new System.Windows.Forms.Panel(); this.btnCancel = new System.Windows.Forms.Button(); this.btnOK = new System.Windows.Forms.Button(); - this.lblCacheHint = new System.Windows.Forms.Label(); - this.lblAppsHint = new System.Windows.Forms.Label(); this.panelContent.SuspendLayout(); this.grpContentSelection.SuspendLayout(); this.panelHead.SuspendLayout(); @@ -102,7 +102,7 @@ private void InitializeComponent() this.lblTarget.AutoSize = true; this.lblTarget.Location = new System.Drawing.Point(19, 67); this.lblTarget.Name = "lblTarget"; - this.lblTarget.Size = new System.Drawing.Size(67, 13); + this.lblTarget.Size = new System.Drawing.Size(68, 13); this.lblTarget.TabIndex = 2; this.lblTarget.Text = "Target Path:"; // @@ -127,6 +127,26 @@ private void InitializeComponent() this.grpContentSelection.TabStop = false; this.grpContentSelection.Text = "Include"; // + // lblAppsHint + // + this.lblAppsHint.AutoSize = true; + this.lblAppsHint.ForeColor = System.Drawing.SystemColors.ControlDarkDark; + this.lblAppsHint.Location = new System.Drawing.Point(148, 187); + this.lblAppsHint.Name = "lblAppsHint"; + this.lblAppsHint.Size = new System.Drawing.Size(376, 13); + this.lblAppsHint.TabIndex = 8; + this.lblAppsHint.Text = "Do not use this option for the *.exe format. It must be smaller then 2GB."; + // + // lblCacheHint + // + this.lblCacheHint.AutoSize = true; + this.lblCacheHint.ForeColor = System.Drawing.SystemColors.ControlDarkDark; + this.lblCacheHint.Location = new System.Drawing.Point(193, 141); + this.lblCacheHint.Name = "lblCacheHint"; + this.lblCacheHint.Size = new System.Drawing.Size(376, 13); + this.lblCacheHint.TabIndex = 8; + this.lblCacheHint.Text = "Do not use this option for the *.exe format. It must be smaller then 2GB."; + // // chkApps // this.chkApps.AutoSize = true; @@ -212,7 +232,7 @@ private void InitializeComponent() this.radClone.AutoSize = true; this.radClone.Location = new System.Drawing.Point(26, 34); this.radClone.Name = "radClone"; - this.radClone.Size = new System.Drawing.Size(383, 17); + this.radClone.Size = new System.Drawing.Size(382, 17); this.radClone.TabIndex = 1; this.radClone.Text = "Clone the Bench environment to a different location in the file system\r\n"; this.radClone.UseVisualStyleBackColor = true; @@ -224,7 +244,7 @@ private void InitializeComponent() this.radExport.Checked = true; this.radExport.Location = new System.Drawing.Point(26, 11); this.radExport.Name = "radExport"; - this.radExport.Size = new System.Drawing.Size(386, 17); + this.radExport.Size = new System.Drawing.Size(385, 17); this.radExport.TabIndex = 0; this.radExport.TabStop = true; this.radExport.Text = "Export the Bench environment as compressed archive (*.zip, *.7z, *.exe)"; @@ -304,26 +324,6 @@ private void InitializeComponent() this.btnOK.UseVisualStyleBackColor = true; this.btnOK.Click += new System.EventHandler(this.OkHandler); // - // lblCacheHint - // - this.lblCacheHint.AutoSize = true; - this.lblCacheHint.ForeColor = System.Drawing.SystemColors.ControlDarkDark; - this.lblCacheHint.Location = new System.Drawing.Point(193, 141); - this.lblCacheHint.Name = "lblCacheHint"; - this.lblCacheHint.Size = new System.Drawing.Size(363, 13); - this.lblCacheHint.TabIndex = 8; - this.lblCacheHint.Text = "Do not use this option for SFX archives. Large *.exe files do not work."; - // - // lblAppsHint - // - this.lblAppsHint.AutoSize = true; - this.lblAppsHint.ForeColor = System.Drawing.SystemColors.ControlDarkDark; - this.lblAppsHint.Location = new System.Drawing.Point(148, 187); - this.lblAppsHint.Name = "lblAppsHint"; - this.lblAppsHint.Size = new System.Drawing.Size(363, 13); - this.lblAppsHint.TabIndex = 8; - this.lblAppsHint.Text = "Do not use this option for SFX archives. Large *.exe files do not work."; - // // ExportForm // this.AcceptButton = this.btnOK; diff --git a/BenchManager/BenchDashboard/ExportForm.cs b/BenchManager/BenchDashboard/ExportForm.cs index 51b34a5e..b3179517 100644 --- a/BenchManager/BenchDashboard/ExportForm.cs +++ b/BenchManager/BenchDashboard/ExportForm.cs @@ -183,7 +183,7 @@ private void BrowseForTargetFile() OverwritePrompt = true, CheckPathExists = true, AddExtension = true, - Filter = "SFX Archive (*.exe)|*.exe|7-Zip Archive (*.7z)|*.7z|ZIP Archive (*.zip)|*.zip", + Filter = "Setup Program (*.exe)|*.exe|7-Zip Archive (*.7z)|*.7z|ZIP Archive (*.zip)|*.zip", FilterIndex = 0, ValidateNames = true, FileName = txtTarget.Text, diff --git a/BenchManager/BenchDashboard/Properties/AssemblyInfo.cs b/BenchManager/BenchDashboard/Properties/AssemblyInfo.cs index 70226ba6..3d6b61a3 100644 --- a/BenchManager/BenchDashboard/Properties/AssemblyInfo.cs +++ b/BenchManager/BenchDashboard/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.22.6.0")] -[assembly: AssemblyFileVersion("0.22.6.0")] +[assembly: AssemblyVersion("0.23.0.0")] +[assembly: AssemblyFileVersion("0.23.0.0")] diff --git a/BenchManager/BenchLib/BenchTasks.cs b/BenchManager/BenchLib/BenchTasks.cs index 9314c2b1..99786deb 100644 --- a/BenchManager/BenchLib/BenchTasks.cs +++ b/BenchManager/BenchLib/BenchTasks.cs @@ -2308,6 +2308,7 @@ private static void InstallPythonPackage(BenchConfiguration config, IProcessExec } var argList = new List(); argList.Add("install"); + argList.Add("--no-warn-script-location"); if (app.IsInstalled) argList.Add("--upgrade"); //argList.Add("--quiet"); if (!app.IsManagedPackageFromRemoteRepo) // python wheel file @@ -3008,7 +3009,7 @@ private static void ExportBenchEnvironment(IBenchManager man, } var sfxArchive = extension == ".exe"; if (sfxArchive) - ExportBenchEnvironmentSfx(man, notify, targetFile, paths); + ExportBenchEnvironmentSetupProgram(man, notify, targetFile, paths); else ExportBenchEnvironmentArchive(man, notify, targetFile, paths); } @@ -3031,58 +3032,113 @@ private static void CopyFileToStream(string file, Stream trg, int bufferSize = 6 } } - private static TextWriter WriteSfxConfig(BenchConfiguration cfg, Stream trg, bool withInfoText, bool userProfileChangeWarning) + private static void WriteSetupText(string targetDir, string title, bool preConfigured, bool userProfileChangeWarning) { var enc = new UTF8Encoding(false); - var w = new StreamWriter(trg, enc, 1024); - w.WriteLine(";!@Install@!UTF-8!"); - if (withInfoText) + File.WriteAllText(Path.Combine(targetDir, "Title.txt"), title, enc); + using (var w = new StreamWriter(Path.Combine(targetDir, "Info.txt"), append: false, encoding: enc)) { - w.WriteLine("Title=\"Bench Transfer Package\""); - w.Write("BeginPrompt=\"This is a pre - configured Bench environment. If you proceed, you will be asked for a target directory to extract and setup the Bench environment.\n\n"); - if (userProfileChangeWarning) + if (preConfigured) { - w.Write("Warning: Because this bench environment is configured to register in the user profile, the environment variables and possibly some registry keys of your user profile will be modified during setup.\n\n"); + w.WriteLine("This is a pre-configured Bench environment."); + w.WriteLine(); + if (userProfileChangeWarning) + { + w.WriteLine("Warning: Because this bench environment is configured to register in the user profile, the environment variables and possibly some registry keys of your user profile will be modified during setup."); + w.WriteLine(); + } + w.WriteLine("See https://winbench.org/ for more info."); + } + else + { + w.WriteLine("This is the standard Bench setup package with the default environment."); } - w.WriteLine("See https://winbench.org/ for more info.\n\nAre you sure you want to extract and setup this Bench environment?\""); } - w.WriteLine(@"RunProgram="".\\auto\\bin\\bench.exe --verbose transfer install"""); - w.Write(";!@InstallEnd@!"); - w.Flush(); - return w; } - private static bool ExportBenchEnvironmentSfx(IBenchManager man, Action notify, string targetFile, string[] paths) + private static bool ExportBenchEnvironmentSetupProgram(IBenchManager man, Action notify, string targetFile, string[] paths) { - var tmpArchive = Path.Combine( + var msbuild = Environment.ExpandEnvironmentVariables("%SystemRoot%\\Microsoft.NET\\Framework64\\v4.0.30319\\msbuild.exe"); + if (!File.Exists(msbuild)) + { + msbuild = Environment.ExpandEnvironmentVariables("%SystemRoot%\\Microsoft.NET\\Framework\\v4.0.30319\\msbuild.exe"); + } + if (!File.Exists(msbuild)) + { + notify(new TaskError("Can not find the MSBuild CLI as part of the .NET Framework 4")); + return false; + } + + var tmpDir = Path.Combine( man.Config.GetStringValue(ConfigPropertyKeys.TempDir), - "bench_export_" + Path.ChangeExtension(Path.GetRandomFileName(), ".7z")); + "bench_setup_" + Path.GetRandomFileName().Replace(".", "")); - if (!ExportBenchEnvironmentArchive(man, notify, tmpArchive, paths)) return false; + Directory.CreateDirectory(tmpDir); + var cleanup = true; - var sfxPath = Path.Combine(Path.Combine(man.Config.BenchRootDir, "res"), "bench.sfx"); try { - using (var s = File.Open(targetFile, FileMode.Create, FileAccess.Write)) + var setupProjectDir = Path.Combine(Path.Combine(man.Config.BenchRootDir, "res"), "setup"); + var fileList = File.ReadAllLines(Path.Combine(setupProjectDir, "files.txt")); + foreach (var file in fileList) { - CopyFileToStream(sfxPath, s); - var userConfigDir = man.Config.GetStringValue(ConfigPropertyKeys.UserConfigDir); - var includeUserConfig = Seq(paths).Any(p => string.Equals(userConfigDir, - Path.Combine(man.Config.BenchRootDir, p), StringComparison.InvariantCultureIgnoreCase)); - WriteSfxConfig(man.Config, s, - withInfoText: includeUserConfig, - userProfileChangeWarning: man.Config.GetBooleanValue(ConfigPropertyKeys.RegisterInUserProfile)); - CopyFileToStream(tmpArchive, s); + if (string.IsNullOrWhiteSpace(file)) continue; + File.Copy(Path.Combine(setupProjectDir, file), Path.Combine(tmpDir, file)); } - File.Delete(tmpArchive); + + var userConfigDir = man.Config.GetStringValue(ConfigPropertyKeys.UserConfigDir); + var includeUserConfig = Seq(paths).Any(p => string.Equals(userConfigDir, + Path.Combine(man.Config.BenchRootDir, p), StringComparison.InvariantCultureIgnoreCase)); + + WriteSetupText(tmpDir, "Bench Setup", + preConfigured: includeUserConfig, + userProfileChangeWarning: man.Config.GetBooleanValue(ConfigPropertyKeys.RegisterInUserProfile)); + var tmpArchive = Path.Combine(tmpDir, "Bench.zip"); + + if (!ExportBenchEnvironmentArchive(man, notify, tmpArchive, paths)) return false; + + if (File.Exists(targetFile)) File.Delete(targetFile); + + var execHost = man.ProcessExecutionHost; + var result = execHost.RunProcess(man.Env, tmpDir, msbuild, + string.Join(" ", + "-nologo", + "-verbosity:normal", + "-t:Clean;PrepareResources;Compile", + "-p:Configuration=Release", + "-fileLogger", + "-fileLoggerParameters:logfile=build.log;verbosity=detailed", + "BenchSetup.csproj"), + ProcessMonitoring.ExitCode); + if (result.ExitCode != 0) + { + notify(new TaskError("MSBuild exited with error. Exit status: " + result.ExitCode)); + return false; + } + + var setupExe = Path.Combine(tmpDir, "obj", "Release", "BenchSetup.exe"); + if (!File.Exists(setupExe)) + { + cleanup = false; + notify(new TaskError("Compiling the transfer package failed.")); + return false; + } + File.Move(setupExe, targetFile); } catch (Exception e) { - notify(new TaskError( - "Failed to export the Bench environment.", + notify(new TaskError("Failed to export the Bench environment.", exception: e)); return false; } + finally + { + if (cleanup) + { + Directory.Delete(tmpDir, true); + } + } + return true; } @@ -3109,7 +3165,6 @@ private static bool ExportBenchEnvironmentArchive(IBenchManager man, Action + + + + Debug + AnyCPU + {DA29F93F-382F-46FD-93DD-AA0EF6D87BD5} + WinExe + Mastersign.Bench.Setup + BenchSetup + v4.6.2 + 512 + true + true + + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + BenchSetup.ico + + + app.manifest + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/BenchSetup/BenchSetup.ico b/BenchSetup/BenchSetup.ico new file mode 100644 index 00000000..96697c6f Binary files /dev/null and b/BenchSetup/BenchSetup.ico differ diff --git a/BenchSetup/BenchSetup.sln b/BenchSetup/BenchSetup.sln new file mode 100644 index 00000000..2ba68c7c --- /dev/null +++ b/BenchSetup/BenchSetup.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.9.34701.34 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BenchSetup", "BenchSetup.csproj", "{DA29F93F-382F-46FD-93DD-AA0EF6D87BD5}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {DA29F93F-382F-46FD-93DD-AA0EF6D87BD5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DA29F93F-382F-46FD-93DD-AA0EF6D87BD5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DA29F93F-382F-46FD-93DD-AA0EF6D87BD5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DA29F93F-382F-46FD-93DD-AA0EF6D87BD5}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {B90C45AA-9BC9-4E33-9E3B-A0C9FFA521CA} + EndGlobalSection +EndGlobal diff --git a/BenchSetup/Commandline.txt b/BenchSetup/Commandline.txt new file mode 100644 index 00000000..1e2be728 --- /dev/null +++ b/BenchSetup/Commandline.txt @@ -0,0 +1 @@ +auto\bin\bench.exe --verbose manage initialize \ No newline at end of file diff --git a/BenchSetup/Header.png b/BenchSetup/Header.png new file mode 100644 index 00000000..d0595f14 Binary files /dev/null and b/BenchSetup/Header.png differ diff --git a/BenchSetup/Info.txt b/BenchSetup/Info.txt new file mode 100644 index 00000000..7d93a1d8 --- /dev/null +++ b/BenchSetup/Info.txt @@ -0,0 +1,3 @@ +This is the template info text with a reasonable length. + +It contains some sentences to represent a real info text, that has enough space to contain some important information for the user of the Bench environment. diff --git a/BenchSetup/Program.cs b/BenchSetup/Program.cs new file mode 100644 index 00000000..afa6a56d --- /dev/null +++ b/BenchSetup/Program.cs @@ -0,0 +1,386 @@ +using System; +using System.Collections.Specialized; +using System.Configuration; +using System.Diagnostics; +using System.Drawing; +using System.IO; +using System.IO.Compression; +using System.Text; +using System.Windows.Forms; + +namespace Mastersign.Bench.Setup +{ + internal static class Program + { + [STAThread] + static void Main(string[] args) + { + var section = ConfigurationManager.GetSection("System.Windows.Forms.ApplicationConfigurationSection") as NameValueCollection; + if (section != null) + { + section["DpiAwareness"] = "system"; + } + + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + var form = CreateForm(); + Application.Run(form); + } + + static string DefaultTargetDir + { + get { return Environment.GetEnvironmentVariable("SystemDrive") + @"\Bench"; } + } + + static Stream GetResourceStream(string path) + { + var assembly = typeof(Program).Assembly; + var ns = typeof(Program).Namespace; + return assembly.GetManifestResourceStream(ns + "." + path); + } + + static string GetResourceText(string path) + { + using (var s = GetResourceStream(path)) + using (var r = new StreamReader(s, Encoding.UTF8)) + { + return r.ReadToEnd(); + } + } + + static Form CreateForm() + { + var defaultFont = new Font("Segoe UI", 9f, FontStyle.Regular); + var form = new Form + { + AutoScaleMode = AutoScaleMode.Font, + AutoScaleDimensions = new SizeF(6F, 13F), + Text = "Bench Setup", + Icon = new Icon(GetResourceStream("BenchSetup.ico")), + Width = 484, + Height = 320, + ShowIcon = true, + ShowInTaskbar = true, + StartPosition = FormStartPosition.CenterScreen, + MaximizeBox = false, + MinimizeBox = false, + Padding = Padding.Empty, + FormBorderStyle = FormBorderStyle.FixedDialog, + }; + form.SuspendLayout(); + + var layout = new TableLayoutPanel + { + Dock = DockStyle.Fill, + Margin = Padding.Empty, + }; + layout.SuspendLayout(); + layout.RowCount = 5; + layout.RowStyles.Add(new RowStyle { SizeType = SizeType.AutoSize }); + layout.RowStyles.Add(new RowStyle { SizeType = SizeType.Percent, Height = 100 }); + layout.RowStyles.Add(new RowStyle { SizeType = SizeType.AutoSize }); + layout.RowStyles.Add(new RowStyle { SizeType = SizeType.AutoSize }); + layout.RowStyles.Add(new RowStyle { SizeType = SizeType.AutoSize }); + layout.ColumnCount = 3; + layout.ColumnStyles.Add(new ColumnStyle { SizeType = SizeType.AutoSize }); + layout.ColumnStyles.Add(new ColumnStyle { SizeType = SizeType.Percent, Width = 100 }); + layout.ColumnStyles.Add(new ColumnStyle { SizeType = SizeType.AutoSize }); + + var header = new TableLayoutPanel + { + Height = 96, + Dock = DockStyle.Fill, + BackgroundImage = new Bitmap(GetResourceStream("Header.png")), + BackgroundImageLayout = ImageLayout.None, + Margin = Padding.Empty, + }; + layout.Controls.Add(header); + layout.SetRow(header, 0); + layout.SetColumn(header, 0); + layout.SetColumnSpan(header, 3); + + var titleText = new Label + { + Text = GetResourceText("Title.txt"), + Font = new Font("Segoe UI", 18f, FontStyle.Regular), + Margin = new Padding(24), + AutoSize = true, + BackColor = Color.Transparent, + MaximumSize = new Size(form.ClientSize.Width - 48, header.Height - 48), + AutoEllipsis = true, + }; + header.Controls.Add(titleText); + + var infoTextContainer = new TableLayoutPanel + { + AutoScroll = true, + AutoScrollMargin = new Size(0, 0), + Dock = DockStyle.Fill, + Margin = Padding.Empty, + Padding = new Padding(0), + Font = defaultFont, + BackColor = SystemColors.Window, + }; + infoTextContainer.SuspendLayout(); + infoTextContainer.RowCount = 1; + infoTextContainer.RowStyles.Add(new RowStyle(SizeType.AutoSize)); + infoTextContainer.ColumnCount = 1; + infoTextContainer.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize)); + layout.Controls.Add(infoTextContainer); + layout.SetRow(infoTextContainer, 1); + layout.SetColumn(infoTextContainer, 0); + layout.SetColumnSpan(infoTextContainer, 3); + + var infoText = new Label + { + Text = GetResourceText("Info.txt"), + Dock = DockStyle.Left, + AutoSize = true, + Margin = new Padding(8, 8, 8, 0), + MaximumSize = new Size(form.ClientSize.Width - 32, int.MaxValue), + }; + infoTextContainer.Controls.Add(infoText); + infoTextContainer.SetRow(infoText, 0); + infoTextContainer.SetColumn(infoText, 0); + + var targetTopMargin = 8; + var targetLabel = new Label + { + Text = "Target Directory:", + Margin = new Padding(8, 6 + targetTopMargin, 0, 0), + Padding = Padding.Empty, + AutoSize = true, + Font = defaultFont, + }; + layout.Controls.Add(targetLabel); + layout.SetRow(targetLabel, 2); + layout.SetColumn(targetLabel, 0); + + var targetTextBox = new TextBox + { + Text = DefaultTargetDir, + Font = defaultFont, + Dock = DockStyle.Fill, + Margin = new Padding(0, 1 + targetTopMargin, 0, 0), + }; + layout.Controls.Add(targetTextBox); + layout.SetRow(targetTextBox, 2); + layout.SetColumn(targetTextBox, 1); + + var browseButton = new Button + { + Text = "...", + Margin = new Padding(1, 0 + targetTopMargin, 16, 0), + Padding = Padding.Empty, + Size = new Size(30, 25), + Font = defaultFont, + Dock = DockStyle.Fill, + }; + layout.Controls.Add(browseButton); + layout.SetRow(browseButton, 2); + layout.SetColumn(browseButton, 2); + + var startButton = new Button + { + Text = "Extract", + Margin = new Padding(16, 8, 16, 16), + Padding = new Padding(6, 4, 6, 4), + Size = new Size(64, 32), + Font = defaultFont, + Dock = DockStyle.Right, + }; + layout.Controls.Add(startButton); + layout.SetRow(startButton, 3); + layout.SetColumnSpan(startButton, 3); + + infoTextContainer.ResumeLayout(); + layout.ResumeLayout(); + form.Controls.Add(layout); + form.AcceptButton = startButton; + form.ResumeLayout(); + + form.Resize += delegate + { + titleText.MaximumSize = new Size(form.ClientSize.Width - 48, header.Height - 48); + infoText.MaximumSize = new Size(form.ClientSize.Width - 32, int.MaxValue); + }; + + form.KeyPreview = true; + form.KeyDown += (sender, ea) => + { + if (ea.KeyCode == Keys.Escape) { form.Close(); } + }; + + browseButton.Click += delegate + { + var sysRootPath = Environment.GetEnvironmentVariable("SystemDrive") + "\\"; + var dlg = new FolderBrowserDialog + { + Description = + "Choose the target directory for the Bench environment. " + + "You probably have to create a new directory for that." + Environment.NewLine + + "A good default location is: " + sysRootPath + "Bench", + ShowNewFolderButton = true, + RootFolder = Environment.SpecialFolder.MyComputer, + SelectedPath = targetTextBox.Text, + }; + if (dlg.ShowDialog(form) != DialogResult.OK) return; + targetTextBox.Text = dlg.SelectedPath; + }; + + startButton.Click += delegate + { + layout.Enabled = false; + try + { + Setup(form, targetTextBox.Text); + } + finally + { + layout.Enabled = true; + } + form.Close(); + }; + + return form; + } + + static void Setup(Form mainForm, string targetDir, bool interactive = true, bool force = false) + { + var a = new ZipArchive(GetResourceStream("Bench.zip")); + var collision = false; + if (Directory.Exists(targetDir)) + { + foreach (var entry in a.Entries) + { + if (File.Exists(Path.Combine(targetDir, entry.FullName))) + { + collision = true; + break; + } + } + if (collision) + { + if (!force) + { + if (interactive) + { + if (MessageBox.Show(mainForm, + "The target directory already contains Bench files." + + " Do you want to replace existing files?", + "Bench Setup", + MessageBoxButtons.YesNo, + MessageBoxIcon.Warning) != DialogResult.Yes) + { + MessageBox.Show(mainForm, + "Bench Setup cancelled.", + "Bench Setup", MessageBoxButtons.OK, + MessageBoxIcon.Information); + Environment.Exit(1); + } + } + else + { + Environment.Exit(1); + } + } + + foreach (var entry in a.Entries) + { + var filePath = Path.Combine(targetDir, entry.FullName); + if (!File.Exists(filePath)) continue; + try + { + File.Delete(filePath); + } + catch (Exception ex) + { + if (interactive) + { + MessageBox.Show(mainForm, + "Failed to delete file in target directory:" + Environment.NewLine + + ex.Message + Environment.NewLine + + Environment.NewLine + + filePath + Environment.NewLine + + Environment.NewLine + + "Bench Setup cancelled.", + "Bench Setup", + MessageBoxButtons.OK, + MessageBoxIcon.Error); + } + Environment.Exit(2); + } + } + } + } + else + { + Directory.CreateDirectory(targetDir); + } + try + { + a.ExtractToDirectory(targetDir); + } + catch (Exception ex) + { + if (interactive) + { + MessageBox.Show(mainForm, + "Failed to extract Bench files:" + Environment.NewLine + + ex.Message, + "Bench Setup", + MessageBoxButtons.OK, + MessageBoxIcon.Error); + } + Environment.Exit(3); + } + + var benchExe = Path.Combine(targetDir, "auto", "bin", "bench.exe"); + if (!File.Exists(benchExe)) + { + MessageBox.Show(mainForm, + "Can not find Bench CLI in the extracted environment." + Environment.NewLine + + Environment.NewLine + + benchExe + Environment.NewLine + + Environment.NewLine + + "The transfer package is probably incomplete. Setup cancelled.", + "Bench Setup", + MessageBoxButtons.OK, + MessageBoxIcon.Error); + Environment.Exit(4); + } + + var commandline = GetResourceText("Commandline.txt").Trim(); + var parts = commandline.Split(new char[] { ' ' }, 2, StringSplitOptions.RemoveEmptyEntries); + var exe = parts[0]; + if (!Path.IsPathRooted(exe)) + { + exe = Path.Combine(targetDir, exe); + } + var args = parts.Length > 1 ? parts[1] : string.Empty; + try + { + Process.Start(new ProcessStartInfo + { + WorkingDirectory = targetDir, + FileName = exe, + Arguments = args, + }); + } + catch (Exception ex) + { + MessageBox.Show(mainForm, + "Starting setup of the Bench environment failed." + Environment.NewLine + + Environment.NewLine + + ex.GetType().FullName + ":" + Environment.NewLine + + ex.Message + Environment.NewLine + + Environment.NewLine + + "Setup cancelled.", + "Bench Setup", + MessageBoxButtons.OK, + MessageBoxIcon.Error); + Environment.Exit(5); + } + } + } +} diff --git a/BenchSetup/Title.txt b/BenchSetup/Title.txt new file mode 100644 index 00000000..4e01674f --- /dev/null +++ b/BenchSetup/Title.txt @@ -0,0 +1 @@ +Bench Setup \ No newline at end of file diff --git a/BenchSetup/app.manifest b/BenchSetup/app.manifest new file mode 100644 index 00000000..0d41a7e1 --- /dev/null +++ b/BenchSetup/app.manifest @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + true + + + + + + + + + diff --git a/BenchSetup/build-test.cmd b/BenchSetup/build-test.cmd new file mode 100644 index 00000000..9da28432 --- /dev/null +++ b/BenchSetup/build-test.cmd @@ -0,0 +1,6 @@ +@ECHO OFF +CALL "%SystemRoot%\Microsoft.NET\Framework64\v4.0.30319\msbuild.exe" "%~dp0\BenchSetup.csproj" -nologo -verbosity:minimal -t:Clean;PrepareResources;Compile -p:Configuration=Release +MOVE "%~dp0\obj\Release\BenchSetup.exe" "%~dp0\BenchSetup.exe" +RMDIR /S /Q "%~dp0\obj" +RMDIR /S /Q "%~dp0\bin" +PAUSE diff --git a/BenchSetup/files.txt b/BenchSetup/files.txt new file mode 100644 index 00000000..417dce62 --- /dev/null +++ b/BenchSetup/files.txt @@ -0,0 +1,9 @@ +files.txt + +BenchSetup.csproj +app.manifest +BenchSetup.ico +Header.png +Commandline.txt +AssemblyInfo.cs +Program.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index d750eeaf..bce712c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,14 @@ Add a link to the GitHub diff like [Unreleased]: https://github.com/winbench/bench/compare/master...dev +## [0.23.0] - 2024-04-12 + +[0.23.0]: https://github.com/winbench/bench/compare/v0.22.6...v0.23.0 + +### Changed +* Replaced 7Zip SFX setup / transfer package with custom setup program +* Setup program is now signed + ## [0.22.6] - 2023-04-17 [0.22.6]: https://github.com/winbench/bench/compare/v0.22.5...v0.22.6 diff --git a/build/build-debug.ps1 b/build/build-debug.ps1 index 54e5aff2..d832be50 100644 --- a/build/build-debug.ps1 +++ b/build/build-debug.ps1 @@ -3,4 +3,4 @@ param ( ) $Script:thisDir = Split-Path $MyInvocation.MyCommand.Path -Parent -& "$thisDir\build.ps1" -Mode Debug -MsBuildVerbosity $MsBuildVerbosity -NoRelease +& "$thisDir\build.ps1" -Mode Debug -MsBuildVerbosity $MsBuildVerbosity -NoRelease -NoSign diff --git a/build/build.ps1 b/build/build.ps1 index c55f4bbf..86fdb675 100644 --- a/build/build.ps1 +++ b/build/build.ps1 @@ -1,6 +1,7 @@ param ( $Mode = "Release", $MsBuildVerbosity = "minimal", + [switch]$NoSign, [switch]$NoRelease ) @@ -171,7 +172,7 @@ if ($buildError -ne 0) echo "" echo "Copying build artifacts to $rootDir\$buildTargetDir ..." if (Test-Path "$rootDir\$buildTargetDir") { del "$rootDir\$buildTargetDir" -Recurse -Force } -$_ = mkdir "$rootDir\$buildTargetDir" +mkdir "$rootDir\$buildTargetDir" | Out-Null foreach ($artifact in $buildArtifacts) { echo " $artifact" @@ -183,6 +184,11 @@ if ($Mode -eq "Debug") { cp "$rootDir\res\Invoke-AppVersionCheck.ps1" "$rootDir\$buildTargetDir\cav.ps1" } +# Update setup project +echo "" +echo "Updating setup project sources ..." +& "$myDir\update-setup-sources.ps1" + $today = [DateTime]::Now.ToString("yyyy-MM-dd") if (!$NoRelease) @@ -223,24 +229,29 @@ if (!$NoRelease) if (Test-Path $zipFile) { del $zipFile } cp $taggedZipFile $zipFile - # Create SFX release + # Create Setup EXE release cd "$rootDir" $taggedName = "$releaseDir\${releaseFileName}Setup_$today" - $taggedSfxFile = "${taggedName}.exe" + $taggedSetupExeFile = "${taggedName}.exe" if ($suffix -gt 0) { - $taggedSfxFile = "${taggedName}_${suffix}.exe" + $taggedSetupExeFile = "${taggedName}_${suffix}.exe" } - .\auto\bin\bench.exe --verbose transfer export --include SystemOnly $taggedSfxFile + .\auto\bin\bench.exe --verbose transfer export --include SystemOnly $taggedSetupExeFile if ($?) { - $sfxFile = "$releaseDir\${releaseFileName}Setup.exe" - cp $taggedSfxFile $sfxFile -Force + if (!$NoSign) { + echo "" + echo "Signing setup program..." + & "$PSScriptRoot\sign.ps1" $taggedSetupExeFile + } + $setupExeFile = "$releaseDir\${releaseFileName}Setup.exe" + cp $taggedSetupExeFile $setupExeFile -Force } echo "" echo "Latest release: `"$zipFile`" ($([IO.Path]::GetFileName($taggedZipFile)))" - echo "Latest release: `"$sfxFile`" ($([IO.Path]::GetFileName($taggedSfxFile)))" + echo "Latest release: `"$setupExeFile`" ($([IO.Path]::GetFileName($taggedSetupExeFile)))" # Clean staging folder #del $stageDir -Recurse -Force diff --git a/build/sign.ps1 b/build/sign.ps1 new file mode 100644 index 00000000..6452a256 --- /dev/null +++ b/build/sign.ps1 @@ -0,0 +1,72 @@ +param( + [string[]]$TargetFiles +) + +$ErrorActionPreference = 'Stop' +$TimeServer = "http://timestamp.sectigo.com" + +$signToolSearchPath = "${env:ProgramFiles(x86)}\Windows Kits\10\bin\*\x64\signtool.exe" + +[string]$signtool = Get-ChildItem $signToolSearchPath -ErrorAction SilentlyContinue ` + | Sort-Object -Property FullName ` + | Select-Object -Last 1 + +if (!$signtool) { + Write-Warning "SignTool.exe not found. You need to install a Windows SDK." + exit 1 +} + +$certFile = Get-ChildItem "$PSScriptRoot\..\*.pfx" ` + | Sort-Object -Property Name ` + | Select-Object -First 1 +if (!$certFile) { + Write-Warning "No PFX file found in the project root." + Write-Host "This script needs a certificate with private key as a PFX file in the project root to work." + exit 1 +} + +function ConvertFrom-SecureToPlain { + param([Parameter(Mandatory=$true)][System.Security.SecureString] $SecurePassword) + # Create a "password pointer" + $passwordPointer = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecurePassword) + # Get the plain text version of the password + $plainTextPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto($passwordPointer) + # Free the pointer + [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($passwordPointer) + # Return the plain text password + $plainTextPassword +} + +$pfxPassword = Read-Host -AsSecureString "PFX Password" + +$unsignedTargets = @() +Write-Output "Searching for files without signature..." +foreach ($f in $TargetFiles) { + [string]$result = & $signtool Verify /pa /tw $f 2>&1 + if ($LASTEXITCODE) { + if ($result.Contains("No signature found")) { + $unsignedTargets += $f + Write-Output "- $f" + } else { + Write-Warning "- $f failed to verify signature" + & $signtool Verify /pa /tw $f + Write-Warning "Exit Code: $LASTEXITCODE" + } + } else { + Write-Output "- $f already signed" + } +} +Write-Output "Signing files..." +foreach ($f in $unsignedTargets) { + Write-Output "- $f" + $backup = "$f.bak" + if (!(Test-Path $backup)) { Copy-Item $f $backup } + & $signtool sign ` + /f $certFile /p $(ConvertFrom-SecureToPlain $pfxPassword) ` + /fd sha256 /td sha256 /tr $TimeServer ` + $f + if ($LASTEXITCODE) { + Write-Warning "Signing failed." + exit 1 + } +} diff --git a/build/update-setup-sources.ps1 b/build/update-setup-sources.ps1 new file mode 100644 index 00000000..671fbfc9 --- /dev/null +++ b/build/update-setup-sources.ps1 @@ -0,0 +1,18 @@ +$myDir = $PSScriptRoot +$rootDir = [IO.Path]::GetDirectoryName($myDir) +$srcDir = "$rootDir\BenchSetup" +$trgDir = "$rootDir\res\setup" +pushd + +if (!(Test-Path $trgDir)) { mkdir $trgDir | Out-Null } + +cd $srcDir +[string[]]$fileList = Get-Content "files.txt" +echo "Setup project sources" +foreach ($f in $fileList) { + if (!$f) { continue } + echo "- $f" + cp $f "$trgDir\" -Force +} + +popd \ No newline at end of file diff --git a/res/bench-install.bat b/res/bench-install.bat index 823947f8..a4d43b05 100644 --- a/res/bench-install.bat +++ b/res/bench-install.bat @@ -7,7 +7,7 @@ SetLocal :: https://winbench.org/guide/setup/ :: -SET VERSION=0.22.6 +SET VERSION=0.23.0 SET TAG=v%VERSION% SET ROOT=%~dp0 IF [%1] NEQ [] SET ROOT=%~dpnx1\ diff --git a/res/bench.sfx b/res/bench.sfx deleted file mode 100644 index 23d99426..00000000 Binary files a/res/bench.sfx and /dev/null differ diff --git a/res/version.txt b/res/version.txt index 9a5d734c..2ba6141d 100644 --- a/res/version.txt +++ b/res/version.txt @@ -1 +1 @@ -0.22.6 \ No newline at end of file +0.23.0 \ No newline at end of file