diff --git a/changelog.md b/changelog.md index 502905d2..f1dcc1b6 100644 --- a/changelog.md +++ b/changelog.md @@ -8,6 +8,7 @@ improvements may be omitted.)_ __[new features]__ +* Update support for Inno Setup is added. * Update support for Stellarium is added. ## Version 2024.09.30.0 diff --git a/supported_applications.md b/supported_applications.md index 71785527..b9d37b1d 100644 --- a/supported_applications.md +++ b/supported_applications.md @@ -27,6 +27,7 @@ application. * HeidiSQL * HexChat * Inkscape +* Inno Setup * IrfanView * KeePass 2 * LibreOffice diff --git a/updater-test/software/InnoSetup_Tests.cs b/updater-test/software/InnoSetup_Tests.cs new file mode 100644 index 00000000..f9f319ef --- /dev/null +++ b/updater-test/software/InnoSetup_Tests.cs @@ -0,0 +1,70 @@ +/* + This file is part of the updater command line interface. + Copyright (C) 2024 Dirk Stolle + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +using Microsoft.VisualStudio.TestTools.UnitTesting; +using updater.software; + +namespace updater_test.software +{ + /// + /// Test cases for the InnoSetup class. + /// + [TestClass] + public class InnoSetup_Tests : BasicSoftwareTests + { + /// + /// Checks whether info() returns some meaningful data. + /// + [TestMethod] + public void Test_info() + { + _info(new InnoSetup(false)); + } + + + /// + /// Checks whether the class implements the searchForNewer() method. + /// + [TestMethod] + public void Test_implementsSearchForNewer() + { + var inno = new InnoSetup(false); + Assert.IsTrue(inno.implementsSearchForNewer()); + } + + + /// + /// Checks whether searchForNewer() returns something. + /// + [TestMethod] + public void Test_searchForNewer() + { + _searchForNewer(new InnoSetup(false)); + } + + + /// + /// Checks whether the class info is up to date. + /// + [TestMethod] + public void Test_upToDate_info() + { + _upToDate_info(new InnoSetup(false)); + } + } // class +} // namespace diff --git a/updater/software/All.cs b/updater/software/All.cs index cca0d177..92c2eb55 100644 --- a/updater/software/All.cs +++ b/updater/software/All.cs @@ -89,6 +89,7 @@ private static List getUnfiltered(Options opts) result.Add(new HexChat(autoGetNewer)); result.Add(new HeidiSQL(autoGetNewer)); result.Add(new Inkscape(autoGetNewer)); + result.Add(new InnoSetup(autoGetNewer)); result.Add(new IrfanView(autoGetNewer)); result.Add(new KeePass(autoGetNewer)); result.Add(new LibreOffice(autoGetNewer)); diff --git a/updater/software/InnoSetup.cs b/updater/software/InnoSetup.cs new file mode 100644 index 00000000..5a230ebc --- /dev/null +++ b/updater/software/InnoSetup.cs @@ -0,0 +1,205 @@ +/* + This file is part of the updater command line interface. + Copyright (C) 2024 Dirk Stolle + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text.RegularExpressions; +using updater.data; + +namespace updater.software +{ + /// + /// Handles update of Inno Setup (Unicode version). + /// + public class InnoSetup: AbstractSoftware + { + /// + /// NLog.Logger for InnoSetup class + /// + private static readonly NLog.Logger logger = NLog.LogManager.GetLogger(typeof(InnoSetup).FullName); + + + /// + /// publisher name for signed installers of Inno Setup + /// + private const string publisherX509 = "CN=\"Open Source Developer, Martijn Laan\", O=Open Source Developer, L=Aalsmeer, S=Noord-Holland, C=NL"; + + + /// + /// expiration date of certificate + /// + private static readonly DateTime certificateExpiration = new(2025, 4, 17, 9, 58, 13, DateTimeKind.Utc); + + + /// + /// Constructor. + /// + /// whether to automatically get + /// newer information about the software when calling the info() method + public InnoSetup(bool autoGetNewer) + : base(autoGetNewer) + { } + + + /// + /// Gets the currently known information about the software. + /// + /// Returns an AvailableSoftware instance with the known + /// details about the software. + public override AvailableSoftware knownInfo() + { + var installer = new InstallInfoExe( + "https://files.innosetup.nl/innosetup-6.3.3.exe", + HashAlgorithm.SHA256, + "0bcb2a409dea17e305a27a6b09555cabe600e984f88570ab72575cd7e93c95e6", + new Signature(publisherX509, certificateExpiration), + "/ALLUSERS /VERYSILENT /NORESTART"); + return new AvailableSoftware("Inno Setup", + "6.3.3", + "^Inno Setup Version [0-9]+\\.[0-9]+\\.[0-9]+$", + "^Inno Setup Version [0-9]+\\.[0-9]+\\.[0-9]+$", + installer, + installer); + } + + + /// + /// Gets a list of IDs to identify the software. + /// + /// Returns a non-empty array of IDs, where at least one entry is unique to the software. + public override string[] id() + { + return new string[] { "inno-setup", "innosetup" }; + } + + + /// + /// Determines whether the method searchForNewer() is implemented. + /// + /// Returns true, if searchForNewer() is implemented for that + /// class. Returns false, if not. Calling searchForNewer() may throw an + /// exception in the later case. + public override bool implementsSearchForNewer() + { + return true; + } + + + /// + /// Looks for newer versions of the software than the currently known version. + /// + /// Returns an AvailableSoftware instance with the information + /// that was retrieved from the net. + public override AvailableSoftware searchForNewer() + { + logger.Info("Searching for newer version of Inno Setup..."); + var client = HttpClientProvider.Provide(); + string response; + try + { + var task = client.GetStringAsync("https://jrsoftware.org/isdl.php"); + task.Wait(); + response = task.Result; + } + catch (Exception ex) + { + logger.Warn("Error while looking for newer Inno Setup version: " + ex.Message); + return null; + } + + var regEx = new Regex("innosetup\\-([0-9]+\\.[0-9]+\\.[0-9]+)\\.exe"); + var match = regEx.Match(response); + if (!match.Success) + return null; + string version = match.Groups[1].Value; + regEx = new Regex("sha256 hash: ([0-9a-f]{64})"); + match = regEx.Match(response, match.Index); + if (!match.Success) + return null; + var checksum = match.Groups[1].Value; + + var info = knownInfo(); + info.install32Bit.checksum = checksum; + info.install32Bit.downloadUrl = info.install32Bit.downloadUrl.Replace(info.newestVersion, version); + info.install64Bit.checksum = checksum; + info.install64Bit.downloadUrl = info.install64Bit.downloadUrl.Replace(info.newestVersion, version); + info.newestVersion = version; + return info; + } + + + /// + /// Lists names of processes that might block an update, e.g. because + /// the application cannot be updated while it is running. + /// + /// currently installed / detected software version + /// Returns a list of process names that block the upgrade. + public override List blockerProcesses(DetectedSoftware detected) + { + return new List(4) + { + "Compil32", + "ISCC", + "islzma32", + "islzma64" + }; + } + + + /// + /// Determines whether a separate process must be run before the update. + /// + /// currently installed / detected software version + /// Returns true, if a separate process returned by + /// preUpdateProcess() needs to run in preparation of the update. + /// Returns false, if not. Calling preUpdateProcess() may throw an + /// exception in the later case. + public override bool needsPreUpdateProcess(DetectedSoftware detected) + { + return true; + } + + + /// + /// Returns a process that must be run before the update. + /// + /// currently installed / detected software version + /// Returns a Process ready to start that should be run before + /// the update. May return null or may throw, if needsPreUpdateProcess() + /// returned false. + public override List preUpdateProcess(DetectedSoftware detected) + { + if (string.IsNullOrWhiteSpace(detected.installPath)) + { + logger.Error("There is not enough information to uninstall the old Inno Setup version."); + return null; + } + + // Remove enclosing quotes, if any. + if (detected.installPath.StartsWith("\"") && detected.installPath.EndsWith("\"")) + { + detected.installPath = detected.installPath[1..^1]; + } + var proc = new Process(); + proc.StartInfo.FileName = System.IO.Path.Combine(detected.installPath, "unins000.exe"); + proc.StartInfo.Arguments = "/VERYSILENT /NORESTART"; + return new List(1) { proc }; + } + } +}