From 717a86257a27016bc2d63f4ffad587b1ca2a0821 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Mon, 20 Jul 2020 08:32:33 +1000 Subject: [PATCH 1/5] feat(windows): strip ' (1)' from filename in setup --- .../setup/Keyman.Setup.System.InstallInfo.pas | 16 +- windows/src/unit-tests/Makefile | 6 +- .../Keyman.System.Test.InstallInfoTest.pas | 152 +++ windows/src/unit-tests/windows-setup/Makefile | 20 + .../windows-setup/WindowsSetupTest.dpr | 79 ++ .../windows-setup/WindowsSetupTest.dproj | 1050 +++++++++++++++++ .../windows-setup/WindowsSetupTest.res | Bin 0 -> 1328 bytes 7 files changed, 1319 insertions(+), 4 deletions(-) create mode 100644 windows/src/unit-tests/windows-setup/Keyman.System.Test.InstallInfoTest.pas create mode 100644 windows/src/unit-tests/windows-setup/Makefile create mode 100644 windows/src/unit-tests/windows-setup/WindowsSetupTest.dpr create mode 100644 windows/src/unit-tests/windows-setup/WindowsSetupTest.dproj create mode 100644 windows/src/unit-tests/windows-setup/WindowsSetupTest.res diff --git a/windows/src/desktop/setup/Keyman.Setup.System.InstallInfo.pas b/windows/src/desktop/setup/Keyman.Setup.System.InstallInfo.pas index b27342407a..d351cb2f2b 100644 --- a/windows/src/desktop/setup/Keyman.Setup.System.InstallInfo.pas +++ b/windows/src/desktop/setup/Keyman.Setup.System.InstallInfo.pas @@ -124,7 +124,7 @@ type destructor Destroy; override; procedure LoadSetupInf(const SetupInfPath: string); - procedure LocatePackagesFromFilename(const Filename: string); + procedure LocatePackagesFromFilename(Filename: string); procedure LocatePackagesFromParameter(const Param: string); procedure LocatePackagesInPath(const path: string); @@ -328,13 +328,23 @@ begin end; end; -procedure TInstallInfo.LocatePackagesFromFilename(const Filename: string); +procedure TInstallInfo.LocatePackagesFromFilename(Filename: string); var n: Integer; res: TArray; id, FBCP47: string; + m: TMatch; begin - res := TRegEx.Split(ExtractFileName(ChangeFileExt(Filename, '')), '\.'); + // Get just the base filename + Filename := ExtractFileName(ChangeFileExt(Filename, '')); + + // Strip " (1)" appended for multiple downloads of same file by most browsers + m := TRegEx.Match(Filename, '^(keyman-setup.+) \(\d+\)$'); + if m.Success then + Filename := m.Groups[1].Value; + + // Look for our recognised pattern of keyman-setup.package_id.bcp47... + res := TRegEx.Split(Filename, '\.'); if (Length(res) < 2) or (res[0].ToLower <> 'keyman-setup') then // No packages embedded in filename Exit; diff --git a/windows/src/unit-tests/Makefile b/windows/src/unit-tests/Makefile index 049ec57af1..9cce6c9e4a 100644 --- a/windows/src/unit-tests/Makefile +++ b/windows/src/unit-tests/Makefile @@ -5,7 +5,7 @@ # ---------------------------------------------------------------------- TARGETS=keyboard-info keyboard-js-info keyboard-package-versions \ - kmx-file-languages package-info new-tests jsonutil + kmx-file-languages package-info new-tests jsonutil windows-setup test: $(MAKE) -DTARGET=test $(TARGETS) @@ -38,6 +38,10 @@ jsonutil: cd $(ROOT)\src\unit-tests\jsonutil $(MAKE) $(TARGET) +windows-setup: + cd $(ROOT)\src\unit-tests\windows-setup + $(MAKE) $(TARGET) + new-tests: cd $(ROOT)\src\test\unit-tests $(MAKE) $(TARGET) diff --git a/windows/src/unit-tests/windows-setup/Keyman.System.Test.InstallInfoTest.pas b/windows/src/unit-tests/windows-setup/Keyman.System.Test.InstallInfoTest.pas new file mode 100644 index 0000000000..3ac68ab1c5 --- /dev/null +++ b/windows/src/unit-tests/windows-setup/Keyman.System.Test.InstallInfoTest.pas @@ -0,0 +1,152 @@ +unit Keyman.System.Test.InstallInfoTest; + +interface + +uses + System.Classes, + System.SysUtils, + DUnitX.TestFramework; + +type + [TestFixture] + TInstallInfoTest = class(TObject) + public + [Test] + procedure TestLocatePackagesFromFilename; + + [Test] + procedure TestLocatePackagesFromParameter; + end; + +implementation + +uses + Keyman.Setup.System.InstallInfo; + +{ TInstallInfoTest } + +procedure TInstallInfoTest.TestLocatePackagesFromFilename; +var + ii: TInstallInfo; +begin + ii := TInstallInfo.Create(''); + try + // It should match a standard pattern + ii.LocatePackagesFromFilename('c:\foo\keyman-setup.khmer_angkor.km.exe'); + Assert.AreEqual(1, ii.Packages.Count); + Assert.AreEqual('khmer_angkor', ii.Packages[0].ID); + Assert.AreEqual('km', ii.Packages[0].BCP47); + finally + ii.Free; + end; + + ii := TInstallInfo.Create(''); + try + // It should match a standard pattern + ii.LocatePackagesFromFilename('c:\foo\keyman-setup.khmer_angkor.km.sil_euro_latin.fr.exe'); + Assert.AreEqual(2, ii.Packages.Count); + Assert.AreEqual('khmer_angkor', ii.Packages[0].ID); + Assert.AreEqual('km', ii.Packages[0].BCP47); + Assert.AreEqual('sil_euro_latin', ii.Packages[1].ID); + Assert.AreEqual('fr', ii.Packages[1].BCP47); + finally + ii.Free; + end; + + ii := TInstallInfo.Create(''); + try + // It should strip off " (1)" suffixes when these are added by web browser + ii.LocatePackagesFromFilename('c:\foo\keyman-setup.khmer_angkor.km (1).exe'); + Assert.AreEqual(1, ii.Packages.Count); + Assert.AreEqual('khmer_angkor', ii.Packages[0].ID); + Assert.AreEqual('km', ii.Packages[0].BCP47); + finally + ii.Free; + end; + + ii := TInstallInfo.Create(''); + try + // It should give an empty BCP 47 tag if one is not provided + ii.LocatePackagesFromFilename('c:\foo\keyman-setup.khmer_angkor.exe'); + Assert.AreEqual(1, ii.Packages.Count); + Assert.AreEqual('khmer_angkor', ii.Packages[0].ID); + Assert.IsEmpty(ii.Packages[0].BCP47); + finally + ii.Free; + end; + + ii := TInstallInfo.Create(''); + try + // It should only match on keyman-setup + ii.LocatePackagesFromFilename('c:\foo\setup.khmer_angkor.km.exe'); + Assert.AreEqual(0, ii.Packages.Count, 'setup.khmer_angkor.km.exe'); + finally + ii.Free; + end; + + ii := TInstallInfo.Create(''); + try + // It should match packages with less common characters in filename + ii.LocatePackagesFromFilename('c:\foo\keyman-setup.khmer angkor.km.exe'); + Assert.AreEqual(1, ii.Packages.Count); + Assert.AreEqual('khmer angkor', ii.Packages[0].ID); + Assert.AreEqual('km', ii.Packages[0].BCP47); + finally + ii.Free; + end; + + ii := TInstallInfo.Create(''); + try + // It should match packages with less common characters in filename + ii.LocatePackagesFromFilename('c:\foo\keyman-setup.khmer-angkor.km.exe'); + Assert.AreEqual(1, ii.Packages.Count); + Assert.AreEqual('khmer-angkor', ii.Packages[0].ID); + Assert.AreEqual('km', ii.Packages[0].BCP47); + finally + ii.Free; + end; +end; + +procedure TInstallInfoTest.TestLocatePackagesFromParameter; +var + ii: TInstallInfo; +begin + ii := TInstallInfo.Create(''); + try + // It should match a standard pattern + ii.LocatePackagesFromParameter('khmer_angkor=km'); + Assert.AreEqual(1, ii.Packages.Count); + Assert.AreEqual('khmer_angkor', ii.Packages[0].ID); + Assert.AreEqual('km', ii.Packages[0].BCP47); + finally + ii.Free; + end; + + ii := TInstallInfo.Create(''); + try + // It should match a standard pattern + ii.LocatePackagesFromParameter('khmer_angkor=km,sil_euro_latin=fr'); + Assert.AreEqual(2, ii.Packages.Count); + Assert.AreEqual('khmer_angkor', ii.Packages[0].ID); + Assert.AreEqual('km', ii.Packages[0].BCP47); + Assert.AreEqual('sil_euro_latin', ii.Packages[1].ID); + Assert.AreEqual('fr', ii.Packages[1].BCP47); + finally + ii.Free; + end; + + ii := TInstallInfo.Create(''); + try + // It should give an empty BCP 47 tag if one is not provided + ii.LocatePackagesFromParameter('khmer_angkor'); + Assert.AreEqual(1, ii.Packages.Count); + Assert.AreEqual('khmer_angkor', ii.Packages[0].ID); + Assert.IsEmpty(ii.Packages[0].BCP47); + finally + ii.Free; + end; +end; + +initialization + TDUnitX.RegisterTestFixture(TInstallInfoTest); +end. diff --git a/windows/src/unit-tests/windows-setup/Makefile b/windows/src/unit-tests/windows-setup/Makefile new file mode 100644 index 0000000000..0083f5977b --- /dev/null +++ b/windows/src/unit-tests/windows-setup/Makefile @@ -0,0 +1,20 @@ +# +# Test various components of Keyman for Windows Setup +# +# NOTE: The .dproj needs $(CI) added to the Delphi Compiler/Conditional defines (All +# configurations - all platforms) section in order for the CI flag to be passed in. +# (It's best to make this change in Delphi IDE). +# + +!include ..\..\Defines.mak + +test: build + -$(WIN32_TARGET_PATH)\WindowsSetupTest.exe -b -exit:continue + +build: + $(DELPHI_MSBUILD) /p:CI=CI WindowsSetupTest.dproj + +clean: def-clean + -rd /s/q Win32 + +!include ..\..\Target.mak diff --git a/windows/src/unit-tests/windows-setup/WindowsSetupTest.dpr b/windows/src/unit-tests/windows-setup/WindowsSetupTest.dpr new file mode 100644 index 0000000000..af57c0d7a8 --- /dev/null +++ b/windows/src/unit-tests/windows-setup/WindowsSetupTest.dpr @@ -0,0 +1,79 @@ +program WindowsSetupTest; + +{$IFNDEF TESTINSIGHT} +{$APPTYPE CONSOLE} +{$ENDIF}{$STRONGLINKTYPES ON} +uses + System.SysUtils, + {$IFDEF TESTINSIGHT} + TestInsight.DUnitX, + {$ENDIF } + DUnitX.Loggers.Console, + DUnitX.Loggers.Xml.NUnit, + DUnitX.TestFramework, + Keyman.System.Test.InstallInfoTest in 'Keyman.System.Test.InstallInfoTest.pas', + Keyman.Setup.System.InstallInfo in '..\..\desktop\setup\Keyman.Setup.System.InstallInfo.pas', + PackageInfo in '..\..\global\delphi\general\PackageInfo.pas', + utilfiletypes in '..\..\global\delphi\general\utilfiletypes.pas', + StockFileNames in '..\..\global\delphi\cust\StockFileNames.pas', + utilstr in '..\..\global\delphi\general\utilstr.pas', + Unicode in '..\..\global\delphi\general\Unicode.pas', + JsonUtil in '..\..\global\delphi\general\JsonUtil.pas', + KeymanVersion in '..\..\global\delphi\general\KeymanVersion.pas', + utildir in '..\..\global\delphi\general\utildir.pas', + utilsystem in '..\..\global\delphi\general\utilsystem.pas', + RegistryKeys in '..\..\global\delphi\general\RegistryKeys.pas', + utilexecute in '..\..\global\delphi\general\utilexecute.pas', + GetOsVersion in '..\..\global\delphi\general\GetOsVersion.pas', + VersionInfo in '..\..\global\delphi\general\VersionInfo.pas', + SetupStrings in '..\..\desktop\setup\SetupStrings.pas', + kmpinffile in '..\..\global\delphi\general\kmpinffile.pas', + PackageFileFormats in '..\..\global\delphi\general\PackageFileFormats.pas'; + +var + runner : ITestRunner; + results : IRunResults; + logger : ITestLogger; + nunitLogger : ITestLogger; +begin + +{$R *.res} + +{$IFDEF TESTINSIGHT} + TestInsight.DUnitX.RunRegisteredTests; + exit; +{$ENDIF} + try + //Check command line options, will exit if invalid + TDUnitX.CheckCommandLine; + //Create the test runner + runner := TDUnitX.CreateRunner; + //Tell the runner to use RTTI to find Fixtures + runner.UseRTTI := True; + //tell the runner how we will log things + //Log to the console window + logger := TDUnitXConsoleLogger.Create(true); + runner.AddLogger(logger); + //Generate an NUnit compatible XML File + nunitLogger := TDUnitXXMLNUnitFileLogger.Create(TDUnitX.Options.XMLOutputFile); + runner.AddLogger(nunitLogger); + runner.FailsOnNoAsserts := False; //When true, Assertions must be made during tests; + + //Run tests + results := runner.Execute; + if not results.AllPassed then + System.ExitCode := EXIT_ERRORS; + + {$IFNDEF CI} + //We don't want this happening when running under CI. + if TDUnitX.Options.ExitBehavior = TDUnitXExitBehavior.Pause then + begin + System.Write('Done.. press key to quit.'); + System.Readln; + end; + {$ENDIF} + except + on E: Exception do + System.Writeln(E.ClassName, ': ', E.Message); + end; +end. diff --git a/windows/src/unit-tests/windows-setup/WindowsSetupTest.dproj b/windows/src/unit-tests/windows-setup/WindowsSetupTest.dproj new file mode 100644 index 0000000000..bb2f9c024d --- /dev/null +++ b/windows/src/unit-tests/windows-setup/WindowsSetupTest.dproj @@ -0,0 +1,1050 @@ + + + {206EED94-2B40-4658-B643-A34D02D17F43} + 18.8 + None + WindowsSetupTest.dpr + True + Debug + Win32 + 1 + Console + + + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Cfg_1 + true + true + + + true + Base + true + + + true + Cfg_2 + true + true + + + .\$(Platform)\$(Config) + .\$(Platform)\$(Config) + false + false + false + false + false + System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace) + WindowsSetupTest + + + $(BDS)\bin\Artwork\Android\FM_LauncherIcon_36x36.png + $(BDS)\bin\Artwork\Android\FM_LauncherIcon_48x48.png + $(BDS)\bin\Artwork\Android\FM_LauncherIcon_72x72.png + $(BDS)\bin\Artwork\Android\FM_LauncherIcon_96x96.png + $(BDS)\bin\Artwork\Android\FM_LauncherIcon_144x144.png + $(BDS)\bin\Artwork\Android\FM_SplashImage_426x320.png + $(BDS)\bin\Artwork\Android\FM_SplashImage_470x320.png + $(BDS)\bin\Artwork\Android\FM_SplashImage_640x480.png + $(BDS)\bin\Artwork\Android\FM_SplashImage_960x720.png + $(BDS)\bin\Artwork\Android\FM_NotificationIcon_24x24.png + $(BDS)\bin\Artwork\Android\FM_NotificationIcon_36x36.png + $(BDS)\bin\Artwork\Android\FM_NotificationIcon_48x48.png + $(BDS)\bin\Artwork\Android\FM_NotificationIcon_72x72.png + $(BDS)\bin\Artwork\Android\FM_NotificationIcon_96x96.png + + + $(BDS)\bin\Artwork\Android\FM_LauncherIcon_36x36.png + $(BDS)\bin\Artwork\Android\FM_LauncherIcon_48x48.png + $(BDS)\bin\Artwork\Android\FM_LauncherIcon_72x72.png + $(BDS)\bin\Artwork\Android\FM_LauncherIcon_96x96.png + $(BDS)\bin\Artwork\Android\FM_LauncherIcon_144x144.png + $(BDS)\bin\Artwork\Android\FM_SplashImage_426x320.png + $(BDS)\bin\Artwork\Android\FM_SplashImage_470x320.png + $(BDS)\bin\Artwork\Android\FM_SplashImage_640x480.png + $(BDS)\bin\Artwork\Android\FM_SplashImage_960x720.png + $(BDS)\bin\Artwork\Android\FM_NotificationIcon_24x24.png + $(BDS)\bin\Artwork\Android\FM_NotificationIcon_36x36.png + $(BDS)\bin\Artwork\Android\FM_NotificationIcon_48x48.png + $(BDS)\bin\Artwork\Android\FM_NotificationIcon_72x72.png + $(BDS)\bin\Artwork\Android\FM_NotificationIcon_96x96.png + + + DBXSqliteDriver;IndyIPCommon;RESTComponents;bindcompdbx;DBXInterBaseDriver;vcl;IndyIPServer;vclactnband;vclFireDAC;IndySystem;tethering;svnui;mbColorLibD10;dsnapcon;FireDACADSDriver;scFontCombo;DCPdelphi2009;FireDACMSAccDriver;fmxFireDAC;vclimg;Jcl;FireDAC;vcltouch;JvCore;vcldb;bindcompfmx;svn;FireDACSqliteDriver;FireDACPgDriver;inetdb;CEF4Delphi;soaprtl;DbxCommonDriver;fmx;FireDACIBDriver;fmxdae;xmlrtl;soapmidas;fmxobj;vclwinx;rtl;DbxClientDriver;CustomIPTransport;vcldsnap;dbexpress;IndyCore;vclx;bindcomp;appanalytics;dsnap;FireDACCommon;IndyIPClient;bindcompvcl;RESTBackendComponents;VCLRESTComponents;soapserver;dbxcds;VclSmp;JvDocking;adortl;JclVcl;vclie;bindengine;DBXMySQLDriver;CloudService;dsnapxml;FireDACMySQLDriver;dbrtl;IndyProtocols;inetdbxpress;keyman_components;FireDACCommonODBC;FireDACCommonDriver;inet;fmxase;$(DCC_UsePackage) + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) + Debug + CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= + 1033 + true + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png + $(BDS)\bin\default_app.manifest + + + DBXSqliteDriver;IndyIPCommon;RESTComponents;bindcompdbx;DBXInterBaseDriver;vcl;IndyIPServer;vclactnband;vclFireDAC;IndySystem;tethering;dsnapcon;FireDACADSDriver;FireDACMSAccDriver;fmxFireDAC;vclimg;Jcl;FireDAC;vcltouch;vcldb;bindcompfmx;FireDACSqliteDriver;FireDACPgDriver;inetdb;soaprtl;DbxCommonDriver;fmx;FireDACIBDriver;fmxdae;xmlrtl;soapmidas;fmxobj;vclwinx;rtl;DbxClientDriver;CustomIPTransport;vcldsnap;dbexpress;IndyCore;vclx;bindcomp;appanalytics;dsnap;FireDACCommon;IndyIPClient;bindcompvcl;RESTBackendComponents;VCLRESTComponents;soapserver;dbxcds;VclSmp;adortl;JclVcl;vclie;bindengine;DBXMySQLDriver;CloudService;dsnapxml;FireDACMySQLDriver;dbrtl;IndyProtocols;inetdbxpress;FireDACCommonODBC;FireDACCommonDriver;inet;fmxase;$(DCC_UsePackage) + true + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png + + + DEBUG;$(DCC_Define) + true + false + true + true + true + + + false + 1033 + $(BDS)\bin\default_app.manifest + + + false + RELEASE;$(DCC_Define) + 0 + 0 + + + 1033 + $(BDS)\bin\default_app.manifest + + + + MainSource + + + + + + + + + + + + + + + + + + + + + Cfg_2 + Base + + + Base + + + Cfg_1 + Base + + + + Delphi.Personality.12 + Application + + + + WindowsSetupTest.dpr + + + File c:\projects\keyman\app\windows\lib\EmbeddedWebBrowser_XE.bpl not found + Microsoft Office 2000 Sample Automation Server Wrapper Components + Microsoft Office XP Sample Automation Server Wrapper Components + + + + + + true + + + + + true + + + + + true + + + + + WindowsSetupTest.exe + true + + + + + 1 + + + Contents\MacOS + 1 + + + 0 + + + + + classes + 1 + + + classes + 1 + + + + + res\xml + 1 + + + res\xml + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + library\lib\armeabi + 1 + + + library\lib\armeabi + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + library\lib\mips + 1 + + + library\lib\mips + 1 + + + + + library\lib\armeabi-v7a + 1 + + + library\lib\arm64-v8a + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + res\values-v21 + 1 + + + res\values-v21 + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable-xxhdpi + 1 + + + res\drawable-xxhdpi + 1 + + + + + res\drawable-ldpi + 1 + + + res\drawable-ldpi + 1 + + + + + res\drawable-mdpi + 1 + + + res\drawable-mdpi + 1 + + + + + res\drawable-hdpi + 1 + + + res\drawable-hdpi + 1 + + + + + res\drawable-xhdpi + 1 + + + res\drawable-xhdpi + 1 + + + + + res\drawable-mdpi + 1 + + + res\drawable-mdpi + 1 + + + + + res\drawable-hdpi + 1 + + + res\drawable-hdpi + 1 + + + + + res\drawable-xhdpi + 1 + + + res\drawable-xhdpi + 1 + + + + + res\drawable-xxhdpi + 1 + + + res\drawable-xxhdpi + 1 + + + + + res\drawable-xxxhdpi + 1 + + + res\drawable-xxxhdpi + 1 + + + + + res\drawable-small + 1 + + + res\drawable-small + 1 + + + + + res\drawable-normal + 1 + + + res\drawable-normal + 1 + + + + + res\drawable-large + 1 + + + res\drawable-large + 1 + + + + + res\drawable-xlarge + 1 + + + res\drawable-xlarge + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + 1 + + + Contents\MacOS + 1 + + + 0 + + + + + Contents\MacOS + 1 + .framework + + + Contents\MacOS + 1 + .framework + + + 0 + + + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 0 + .dll;.bpl + + + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 0 + .bpl + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + Contents\Resources\StartUp\ + 0 + + + Contents\Resources\StartUp\ + 0 + + + 0 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + 1 + + + 1 + + + + + ..\ + 1 + + + ..\ + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + ..\ + 1 + + + ..\ + 1 + + + + + Contents + 1 + + + Contents + 1 + + + + + Contents\Resources + 1 + + + Contents\Resources + 1 + + + + + library\lib\armeabi-v7a + 1 + + + library\lib\arm64-v8a + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + Contents\MacOS + 1 + + + Contents\MacOS + 1 + + + 0 + + + + + library\lib\armeabi-v7a + 1 + + + + + 1 + + + 1 + + + + + Assets + 1 + + + Assets + 1 + + + + + Assets + 1 + + + Assets + 1 + + + + + + + + + + + + + + + False + False + True + False + + + 12 + + + + + diff --git a/windows/src/unit-tests/windows-setup/WindowsSetupTest.res b/windows/src/unit-tests/windows-setup/WindowsSetupTest.res new file mode 100644 index 0000000000000000000000000000000000000000..cf363dded6d021191b6e5aa73064b1645321480f GIT binary patch literal 1328 zcmbtU-*3|}5H^UHOxin-ChuP2*h!Nq-86{}RT|pF#&~w(^JbABB~H6dh(C$Hv0PdT zEmAdLiB7To-Q9Qoaymi?p=gW6%5b^$e1EmZU!%{9B^DA7PghTV{7_eP4xO`YGxqsG z=u>FQR@>%w?0>vIW2sMFuNtkYwt=z#2+lt~+TY8Sb5Ix6BgF)b8~d}aIdtV6)XK5i zmR;*w)3dUz50$GA=G>>XYODd*-)ylh!v~+acruCbk$HG2&HHZV`blHjzbpV_F$@D8 zl(WwEkE<;nbns<{Wr4oz?A%sx3vP{VqNfiS*rQD6Fo$ZHYsg1wHSEW}a+7A>eumE9 zz-IQOEWx2ZMpX`eL&2IN4|ekB!Dg*_@axKh{;2F!^|r7T-sNcxw%mu`aYXm`yj)GE zl`Sz(+bj>f{0(E*cR(j^X#rJxPi>{Mbq$p#iVgoD;Qw;z@3lo0xga4) Date: Mon, 20 Jul 2020 09:03:25 +1000 Subject: [PATCH 2/5] fix(windows): re-add license to setup --- windows/src/desktop/setup/UfrmHTML.dfm | 1 + windows/src/desktop/setup/UfrmHTML.pas | 25 +++++++++++++++ windows/src/desktop/setup/UfrmRunDesktop.pas | 6 ++-- windows/src/desktop/setup/setup.dpr | 3 +- windows/src/desktop/setup/setup.dproj | 1 + .../general/Keyman.System.MITLicense.pas | 31 +++++++++++++++++++ 6 files changed, 63 insertions(+), 4 deletions(-) create mode 100644 windows/src/global/delphi/general/Keyman.System.MITLicense.pas diff --git a/windows/src/desktop/setup/UfrmHTML.dfm b/windows/src/desktop/setup/UfrmHTML.dfm index 4cbd86602e..bf06766734 100644 --- a/windows/src/desktop/setup/UfrmHTML.dfm +++ b/windows/src/desktop/setup/UfrmHTML.dfm @@ -14,6 +14,7 @@ object frmHTML: TfrmHTML KeyPreview = True OldCreateOrder = False Position = poScreenCenter + OnDestroy = FormDestroy DesignSize = ( 666 313) diff --git a/windows/src/desktop/setup/UfrmHTML.pas b/windows/src/desktop/setup/UfrmHTML.pas index 74e2e29276..bb9cd44fd2 100644 --- a/windows/src/desktop/setup/UfrmHTML.pas +++ b/windows/src/desktop/setup/UfrmHTML.pas @@ -51,13 +51,18 @@ type procedure cmdForwardClick(Sender: TObject); procedure webCommandStateChange(ASender: TObject; Command: Integer; Enable: WordBool); + procedure FormDestroy(Sender: TObject); + private + FFilename: string; public procedure ShowFile(const FileName: WideString); + procedure ShowText(const Text: string); end; implementation uses + utildir, utilexecute; {$R *.DFM} @@ -70,6 +75,20 @@ begin web.Navigate(FileName); end; +procedure TfrmHTML.ShowText(const Text: string); +var + stream: TStringStream; +begin + FFilename := KGetTempFileName('.txt'); + stream := TStringStream.Create(Text, TEncoding.UTF8); + try + stream.SaveToFile(FFilename); + finally + stream.Free; + end; + ShowFile(FFileName); +end; + procedure TfrmHTML.webCommandStateChange(ASender: TObject; Command: Integer; Enable: WordBool); begin @@ -102,5 +121,11 @@ begin web.ExecWB(OLECMDID_PRINT, 0); end; +procedure TfrmHTML.FormDestroy(Sender: TObject); +begin + if FFileName <> '' then + System.SysUtils.DeleteFile(FFileName); +end; + end. diff --git a/windows/src/desktop/setup/UfrmRunDesktop.pas b/windows/src/desktop/setup/UfrmRunDesktop.pas index 0581913f2b..376b22987e 100644 --- a/windows/src/desktop/setup/UfrmRunDesktop.pas +++ b/windows/src/desktop/setup/UfrmRunDesktop.pas @@ -137,6 +137,7 @@ uses OnlineConstants, SFX, SetupStrings, + Keyman.System.MITLicense, Keyman.System.UpgradeRegistryKeys, KeymanVersion, RegistryHelpers, @@ -643,9 +644,7 @@ procedure TfrmRunDesktop.lblLicenseClick(Sender: TObject); begin with TfrmHTML.Create(Self) do // I2606 try - Assert(FALSE, 'TODO: show linked in license content'); - // TODO: -// ShowFile(FInstallInfo.LicenseFileName); // I3476 + ShowText(SKeymanMITLicense); ShowModal; finally Free; @@ -976,6 +975,7 @@ begin end; lblStatus.Caption := Text; + lblStatus.Update; Update; end; diff --git a/windows/src/desktop/setup/setup.dpr b/windows/src/desktop/setup/setup.dpr index b6adcee416..5a51f507e3 100644 --- a/windows/src/desktop/setup/setup.dpr +++ b/windows/src/desktop/setup/setup.dpr @@ -43,7 +43,8 @@ uses kmpinffile in '..\..\global\delphi\general\kmpinffile.pas', PackageFileFormats in '..\..\global\delphi\general\PackageFileFormats.pas', Keyman.Setup.System.ResourceDownloader in 'Keyman.Setup.System.ResourceDownloader.pas', - httpuploader in '..\..\global\delphi\general\httpuploader.pas'; + httpuploader in '..\..\global\delphi\general\httpuploader.pas', + Keyman.System.MITLicense in '..\..\global\delphi\general\Keyman.System.MITLicense.pas'; {$R icons.res} {$R version.res} diff --git a/windows/src/desktop/setup/setup.dproj b/windows/src/desktop/setup/setup.dproj index 7f40292059..3de007f8fa 100644 --- a/windows/src/desktop/setup/setup.dproj +++ b/windows/src/desktop/setup/setup.dproj @@ -143,6 +143,7 @@ + Cfg_2 Base diff --git a/windows/src/global/delphi/general/Keyman.System.MITLicense.pas b/windows/src/global/delphi/general/Keyman.System.MITLicense.pas new file mode 100644 index 0000000000..9d5210719d --- /dev/null +++ b/windows/src/global/delphi/general/Keyman.System.MITLicense.pas @@ -0,0 +1,31 @@ +unit Keyman.System.MITLicense; + +interface + +const + SKeymanMITLicense = +'The MIT License'#13#10+ +#13#10+ +'Copyright (c) 2017-2020 SIL International'#13#10+ +#13#10+ +'Permission is hereby granted, free of charge, to any person obtaining a copy'#13#10+ +'of this software and associated documentation files (the "Software"), to deal'#13#10+ +'in the Software without restriction, including without limitation the rights'#13#10+ +'to use, copy, modify, merge, publish, distribute, sublicense, and/or sell'#13#10+ +'copies of the Software, and to permit persons to whom the Software is'#13#10+ +'furnished to do so, subject to the following conditions:'#13#10+ +#13#10+ +'The above copyright notice and this permission notice shall be included in all'#13#10+ +'copies or substantial portions of the Software.'#13#10+ +#13#10+ +'THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR'#13#10+ +'IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,'#13#10+ +'FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE'#13#10+ +'AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER'#13#10+ +'LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,'#13#10+ +'OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE'#13#10+ +'SOFTWARE.'#13#10; + +implementation + +end. From d569e7880d50246f91e1ea9c55352f0416b2171e Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Mon, 20 Jul 2020 09:23:57 +1000 Subject: [PATCH 3/5] feat(windows): setup select tier from filename or parameter --- .../setup/Keyman.Setup.System.InstallInfo.pas | 27 +++++++-- ...eyman.Setup.System.OnlineResourceCheck.pas | 2 +- windows/src/desktop/setup/bootstrapmain.pas | 23 ++++++-- .../Keyman.System.Test.InstallInfoTest.pas | 56 ++++++++++++++++--- 4 files changed, 87 insertions(+), 21 deletions(-) diff --git a/windows/src/desktop/setup/Keyman.Setup.System.InstallInfo.pas b/windows/src/desktop/setup/Keyman.Setup.System.InstallInfo.pas index d351cb2f2b..79d5676e2a 100644 --- a/windows/src/desktop/setup/Keyman.Setup.System.InstallInfo.pas +++ b/windows/src/desktop/setup/Keyman.Setup.System.InstallInfo.pas @@ -117,6 +117,7 @@ type FIsNewerAvailable: Boolean; FTempPath: string; FShouldInstallKeyman: Boolean; + FTier: string; function GetBestMsi: TInstallInfoFileLocation; function GetPackageMetadata(const KmpFilename: string; p: TPackage): Boolean; public @@ -124,7 +125,7 @@ type destructor Destroy; override; procedure LoadSetupInf(const SetupInfPath: string); - procedure LocatePackagesFromFilename(Filename: string); + procedure LocatePackagesAndTierFromFilename(Filename: string); procedure LocatePackagesFromParameter(const Param: string); procedure LocatePackagesInPath(const path: string); @@ -152,6 +153,8 @@ type property StartDisabled: Boolean read FStartDisabled; property StartWithConfiguration: Boolean read FStartWithConfiguration; + property Tier: string read FTier write FTier; + property ShouldInstallKeyman: Boolean read FShouldInstallKeyman write FShouldInstallKeyman; end; @@ -181,6 +184,7 @@ begin FMsiLocations := TInstallInfoFileLocations.Create; FPackages := TInstallInfoPackages.Create; FStrings := TStringList.Create; + FTier := KeymanVersion.CKeymanVersionInfo.Tier; FShouldInstallKeyman := True; end; @@ -328,27 +332,38 @@ begin end; end; -procedure TInstallInfo.LocatePackagesFromFilename(Filename: string); +procedure TInstallInfo.LocatePackagesAndTierFromFilename(Filename: string); +const + SKeymanSetupPrefix = 'keyman-setup'; + SKeymanSetup_Alpha = SKeymanSetupPrefix+'-'+TIER_ALPHA; + SKeymanSetup_Beta = SKeymanSetupPrefix+'-'+TIER_BETA; + SKeymanSetup_Stable = SKeymanSetupPrefix+'-'+TIER_STABLE; var n: Integer; res: TArray; - id, FBCP47: string; + p, id, FBCP47: string; m: TMatch; begin // Get just the base filename Filename := ExtractFileName(ChangeFileExt(Filename, '')); // Strip " (1)" appended for multiple downloads of same file by most browsers - m := TRegEx.Match(Filename, '^(keyman-setup.+) \(\d+\)$'); + m := TRegEx.Match(Filename, '^('+SKeymanSetupPrefix+'.+) \(\d+\)$'); if m.Success then Filename := m.Groups[1].Value; // Look for our recognised pattern of keyman-setup.package_id.bcp47... res := TRegEx.Split(Filename, '\.'); - if (Length(res) < 2) or (res[0].ToLower <> 'keyman-setup') then - // No packages embedded in filename + if (Length(res) < 1) or not res[0].ToLower.StartsWith(SKeymanSetupPrefix) then + // No packages embedded in filename, or not a recognised filename pattern Exit; + // Look for an embedded tier in the filename, if not set, use default + p := res[0].ToLower; + if p.Equals(SKeymanSetup_Stable) then FTier := TIER_STABLE + else if p.Equals(SKeymanSetup_Beta) then FTier := TIER_BETA + else if p.Equals(SKeymanSetup_Alpha) then FTier := TIER_ALPHA; + n := 1; while n < Length(res) do begin diff --git a/windows/src/desktop/setup/Keyman.Setup.System.OnlineResourceCheck.pas b/windows/src/desktop/setup/Keyman.Setup.System.OnlineResourceCheck.pas index 8f82c4a4d2..599563b27c 100644 --- a/windows/src/desktop/setup/Keyman.Setup.System.OnlineResourceCheck.pas +++ b/windows/src/desktop/setup/Keyman.Setup.System.OnlineResourceCheck.pas @@ -46,7 +46,7 @@ begin try http.Request.SetURL(MakeAPIURL(API_Path_UpdateCheck_Windows)); http.Fields.Add('version', AnsiString(currentVersion)); - http.Fields.Add('tier', AnsiString(KeymanVersion.CKeymanVersionInfo.Tier)); + http.Fields.Add('tier', AnsiString(AInstallInfo.Tier)); http.Fields.Add('update', '0'); // This is probably a fresh install of a package, not an update for pack in AInstallInfo.Packages do http.Fields.Add(AnsiString('package_'+pack.ID), AnsiString(pack.Locations.LatestVersion)); diff --git a/windows/src/desktop/setup/bootstrapmain.pas b/windows/src/desktop/setup/bootstrapmain.pas index be5714d4b6..f79e373a37 100644 --- a/windows/src/desktop/setup/bootstrapmain.pas +++ b/windows/src/desktop/setup/bootstrapmain.pas @@ -92,7 +92,7 @@ procedure InstallKeyboardsInOldVersion(const ShellPath: string); forward; procedure DoExtractOnly(FSilent: Boolean; const FExtractOnly_Path: string); forward; function CreateTempDir: string; forward; procedure RemoveTempDir(const path: string); forward; -procedure ProcessCommandLine(var FPromptForReboot, FSilent, FForceOffline, FExtractOnly, FContinueSetup, FStartAfterInstall, FDisableUpgradeFrom6Or7Or8: Boolean; var FPackages, FExtractPath: string); forward; +procedure ProcessCommandLine(var FPromptForReboot, FSilent, FForceOffline, FExtractOnly, FContinueSetup, FStartAfterInstall, FDisableUpgradeFrom6Or7Or8: Boolean; var FPackages, FExtractPath, FTier: string); forward; procedure SetExitVal(c: Integer); forward; function IsKeymanDesktop7Installed: string; forward; function IsKeymanDesktop8Installed: string; forward; @@ -116,7 +116,7 @@ var FPromptForReboot: Boolean; // I3355 // I3500 FSilent: Boolean; FForceOffline: Boolean; - FPackages, FExtractOnly_Path: string; + FTier, FPackages, FExtractOnly_Path: string; BEGIN CoInitializeEx(nil, COINIT_APARTMENTTHREADED); try @@ -132,7 +132,7 @@ BEGIN { Display the dialog } - ProcessCommandLine(FPromptForReboot, FSilent, FForceOffline, FExtractOnly, FContinueSetup, FStartAfterInstall, FDisableUpgradeFrom6Or7Or8, FPackages, FExtractOnly_Path); // I2738, I2847 // I3355 // I3500 // I4293 + ProcessCommandLine(FPromptForReboot, FSilent, FForceOffline, FExtractOnly, FContinueSetup, FStartAfterInstall, FDisableUpgradeFrom6Or7Or8, FPackages, FExtractOnly_Path, FTier); // I2738, I2847 // I3355 // I3500 // I4293 GetRunTools.Silent := FSilent; if FExtractOnly then @@ -162,7 +162,7 @@ BEGIN // it to download khmer_angkor from the Keyman cloud and install it // for bcp47 tag km. See the setup documentation for more // examples. - FInstallInfo.LocatePackagesFromFilename(ParamStr(0)); + FInstallInfo.LocatePackagesAndTierFromFilename(ParamStr(0)); // Additionally, packages can be specified on the command line, with // the -p parameter, e.g. -p khmer_angkor=km,sil_euro_latin=fr @@ -176,6 +176,10 @@ BEGIN // this executable FInstallInfo.LocatePackagesInPath(ProgramPath); + // Lookup a tier from command line parameter + if FTier <> '' then + FInstallInfo.Tier := FTier; + GetRunTools.CheckInternetConnectedState; if not FForceOffline and GetRunTools.Online then @@ -381,7 +385,7 @@ begin DeletePath(ExcludeTrailingPathDelimiter(path)); // I3476 end; -procedure ProcessCommandLine(var FPromptForReboot, FSilent, FForceOffline, FExtractOnly, FContinueSetup, FStartAfterInstall, FDisableUpgradeFrom6Or7Or8: Boolean; var FPackages, FExtractPath: string); // I2847 // I3355 // I3500 // I4293 +procedure ProcessCommandLine(var FPromptForReboot, FSilent, FForceOffline, FExtractOnly, FContinueSetup, FStartAfterInstall, FDisableUpgradeFrom6Or7Or8: Boolean; var FPackages, FExtractPath, FTier: string); // I2847 // I3355 // I3500 // I4293 var i: Integer; begin @@ -428,6 +432,15 @@ begin // e.g. -p khmer_angkor=km,sil_euro_latin=fr Inc(i); FPackages := ParamStr(i); + end + else if SameText(ParamStr(i), '-t') then + begin + Inc(i); + FTier := ParamStr(i).ToLower.Trim; + if not FTier.Equals(TIER_ALPHA) and not FTier.Equals(TIER_BETA) and not FTier.Equals(TIER_STABLE) then + begin + FTier := ''; + end; end; Inc(i); end; diff --git a/windows/src/unit-tests/windows-setup/Keyman.System.Test.InstallInfoTest.pas b/windows/src/unit-tests/windows-setup/Keyman.System.Test.InstallInfoTest.pas index 3ac68ab1c5..da41760af3 100644 --- a/windows/src/unit-tests/windows-setup/Keyman.System.Test.InstallInfoTest.pas +++ b/windows/src/unit-tests/windows-setup/Keyman.System.Test.InstallInfoTest.pas @@ -12,7 +12,7 @@ type TInstallInfoTest = class(TObject) public [Test] - procedure TestLocatePackagesFromFilename; + procedure TestLocatePackagesAndTierFromFilename; [Test] procedure TestLocatePackagesFromParameter; @@ -21,18 +21,56 @@ type implementation uses + KeymanVersion, Keyman.Setup.System.InstallInfo; { TInstallInfoTest } -procedure TInstallInfoTest.TestLocatePackagesFromFilename; +procedure TInstallInfoTest.TestLocatePackagesAndTierFromFilename; var ii: TInstallInfo; begin ii := TInstallInfo.Create(''); try // It should match a standard pattern - ii.LocatePackagesFromFilename('c:\foo\keyman-setup.khmer_angkor.km.exe'); + ii.LocatePackagesAndTierFromFilename('c:\foo\keyman-setup.khmer_angkor.km.exe'); + Assert.AreEqual(CKeymanVersionInfo.Tier, ii.Tier); + Assert.AreEqual(1, ii.Packages.Count); + Assert.AreEqual('khmer_angkor', ii.Packages[0].ID); + Assert.AreEqual('km', ii.Packages[0].BCP47); + finally + ii.Free; + end; + + ii := TInstallInfo.Create(''); + try + // It should match a standard pattern with a tier + ii.LocatePackagesAndTierFromFilename('c:\foo\keyman-setup-alpha.khmer_angkor.km.exe'); + Assert.AreEqual(TIER_ALPHA, ii.Tier); + Assert.AreEqual(1, ii.Packages.Count); + Assert.AreEqual('khmer_angkor', ii.Packages[0].ID); + Assert.AreEqual('km', ii.Packages[0].BCP47); + finally + ii.Free; + end; + + ii := TInstallInfo.Create(''); + try + // It should match a standard pattern with a tier + ii.LocatePackagesAndTierFromFilename('c:\foo\keyman-setup-beta.khmer_angkor.km.exe'); + Assert.AreEqual(TIER_BETA, ii.Tier); + Assert.AreEqual(1, ii.Packages.Count); + Assert.AreEqual('khmer_angkor', ii.Packages[0].ID); + Assert.AreEqual('km', ii.Packages[0].BCP47); + finally + ii.Free; + end; + + ii := TInstallInfo.Create(''); + try + // It should match a standard pattern with a tier + ii.LocatePackagesAndTierFromFilename('c:\foo\keyman-setup-stable.khmer_angkor.km.exe'); + Assert.AreEqual(TIER_STABLE, ii.Tier); Assert.AreEqual(1, ii.Packages.Count); Assert.AreEqual('khmer_angkor', ii.Packages[0].ID); Assert.AreEqual('km', ii.Packages[0].BCP47); @@ -43,7 +81,7 @@ begin ii := TInstallInfo.Create(''); try // It should match a standard pattern - ii.LocatePackagesFromFilename('c:\foo\keyman-setup.khmer_angkor.km.sil_euro_latin.fr.exe'); + ii.LocatePackagesAndTierFromFilename('c:\foo\keyman-setup.khmer_angkor.km.sil_euro_latin.fr.exe'); Assert.AreEqual(2, ii.Packages.Count); Assert.AreEqual('khmer_angkor', ii.Packages[0].ID); Assert.AreEqual('km', ii.Packages[0].BCP47); @@ -56,7 +94,7 @@ begin ii := TInstallInfo.Create(''); try // It should strip off " (1)" suffixes when these are added by web browser - ii.LocatePackagesFromFilename('c:\foo\keyman-setup.khmer_angkor.km (1).exe'); + ii.LocatePackagesAndTierFromFilename('c:\foo\keyman-setup.khmer_angkor.km (1).exe'); Assert.AreEqual(1, ii.Packages.Count); Assert.AreEqual('khmer_angkor', ii.Packages[0].ID); Assert.AreEqual('km', ii.Packages[0].BCP47); @@ -67,7 +105,7 @@ begin ii := TInstallInfo.Create(''); try // It should give an empty BCP 47 tag if one is not provided - ii.LocatePackagesFromFilename('c:\foo\keyman-setup.khmer_angkor.exe'); + ii.LocatePackagesAndTierFromFilename('c:\foo\keyman-setup.khmer_angkor.exe'); Assert.AreEqual(1, ii.Packages.Count); Assert.AreEqual('khmer_angkor', ii.Packages[0].ID); Assert.IsEmpty(ii.Packages[0].BCP47); @@ -78,7 +116,7 @@ begin ii := TInstallInfo.Create(''); try // It should only match on keyman-setup - ii.LocatePackagesFromFilename('c:\foo\setup.khmer_angkor.km.exe'); + ii.LocatePackagesAndTierFromFilename('c:\foo\setup.khmer_angkor.km.exe'); Assert.AreEqual(0, ii.Packages.Count, 'setup.khmer_angkor.km.exe'); finally ii.Free; @@ -87,7 +125,7 @@ begin ii := TInstallInfo.Create(''); try // It should match packages with less common characters in filename - ii.LocatePackagesFromFilename('c:\foo\keyman-setup.khmer angkor.km.exe'); + ii.LocatePackagesAndTierFromFilename('c:\foo\keyman-setup.khmer angkor.km.exe'); Assert.AreEqual(1, ii.Packages.Count); Assert.AreEqual('khmer angkor', ii.Packages[0].ID); Assert.AreEqual('km', ii.Packages[0].BCP47); @@ -98,7 +136,7 @@ begin ii := TInstallInfo.Create(''); try // It should match packages with less common characters in filename - ii.LocatePackagesFromFilename('c:\foo\keyman-setup.khmer-angkor.km.exe'); + ii.LocatePackagesAndTierFromFilename('c:\foo\keyman-setup.khmer-angkor.km.exe'); Assert.AreEqual(1, ii.Packages.Count); Assert.AreEqual('khmer-angkor', ii.Packages[0].ID); Assert.AreEqual('km', ii.Packages[0].BCP47); From 2dc7f02431df5b0b902c9109cf1556d45b034e5c Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Mon, 20 Jul 2020 10:39:50 +1000 Subject: [PATCH 4/5] feat(windows): setup will retry if offline during initial install steps --- windows/src/desktop/setup/SetupStrings.pas | 10 +++- windows/src/desktop/setup/TntDialogHelp.pas | 8 ++- windows/src/desktop/setup/bootstrapmain.pas | 61 +++++++++++++++++---- 3 files changed, 64 insertions(+), 15 deletions(-) diff --git a/windows/src/desktop/setup/SetupStrings.pas b/windows/src/desktop/setup/SetupStrings.pas index df40de90c8..17161f7d90 100644 --- a/windows/src/desktop/setup/SetupStrings.pas +++ b/windows/src/desktop/setup/SetupStrings.pas @@ -87,7 +87,9 @@ type { Download dialog } ssDownloadingTitle, - ssDownloadingText + ssDownloadingText, + + ssOffline ); const @@ -157,7 +159,11 @@ const {ssOptionsDefaultLanguage} 'Default language', {ssDownloadingTitle} 'Downloading %0:s', // %0:s: filename - {ssDownloadingText} 'Downloading %0:s' // %0:s: filename + {ssDownloadingText} 'Downloading %0:s', // %0:s: filename + + {ssOffline} 'Keyman Setup could not connect to keyman.com to download additional resources.'#13#10#13#10+ + 'Please check that you are online, and give Keyman Setup permission to access the Internet in your firewall settings.'#13#10#13#10+ + 'Click Abort to exit Setup, Retry to try and download resources again, or Ignore to continue offline.' ); diff --git a/windows/src/desktop/setup/TntDialogHelp.pas b/windows/src/desktop/setup/TntDialogHelp.pas index 1dc05a4765..e414f9f1a8 100644 --- a/windows/src/desktop/setup/TntDialogHelp.pas +++ b/windows/src/desktop/setup/TntDialogHelp.pas @@ -91,13 +91,19 @@ begin IDCANCEL: Result := mrCancel; IDYES: Result := mrYes; IDNO: Result := mrNo; + IDABORT: Result := mrAbort; + IDIGNORE: Result := mrIgnore; + IDRETRY: Result := mrRetry; else Result := mrOk; end; end; procedure ShowMessageW(const Message: WideString); begin - Tnt_MessageBoxW(GetActiveWindow, PWideChar(Message), PChar(FInstallInfo.Text(ssMessageBoxTitle)), MB_OK); + if Assigned(FInstallInfo) then + Tnt_MessageBoxW(GetActiveWindow, PWideChar(Message), PChar(FInstallInfo.Text(ssMessageBoxTitle)), MB_OK) + else + Tnt_MessageBoxW(GetActiveWindow, PWideChar(Message), PChar('Setup'), MB_OK); end; end. diff --git a/windows/src/desktop/setup/bootstrapmain.pas b/windows/src/desktop/setup/bootstrapmain.pas index f79e373a37..98906b61b3 100644 --- a/windows/src/desktop/setup/bootstrapmain.pas +++ b/windows/src/desktop/setup/bootstrapmain.pas @@ -96,6 +96,7 @@ procedure ProcessCommandLine(var FPromptForReboot, FSilent, FForceOffline, FExtr procedure SetExitVal(c: Integer); forward; function IsKeymanDesktop7Installed: string; forward; function IsKeymanDesktop8Installed: string; forward; +function GetResourcesFromOnline(FSilent: Boolean; var FForceOffline: Boolean): Boolean; forward; var FNiceExitCodes: Boolean = True; // always, now @@ -122,14 +123,12 @@ BEGIN try try Vcl.Forms.Application.Icon.LoadFromResourceID(hInstance, 1); // I2611 + InitCommonControl(ICC_PROGRESS_CLASS); + FTempPath := CreateTempDir; try - FTempPath := CreateTempDir; + FInstallInfo := TInstallInfo.Create(FTempPath); try - InitCommonControl(ICC_PROGRESS_CLASS); - - FInstallInfo := TInstallInfo.Create(FTempPath); - { Display the dialog } ProcessCommandLine(FPromptForReboot, FSilent, FForceOffline, FExtractOnly, FContinueSetup, FStartAfterInstall, FDisableUpgradeFrom6Or7Or8, FPackages, FExtractOnly_Path, FTier); // I2738, I2847 // I3355 // I3500 // I4293 @@ -180,11 +179,12 @@ BEGIN if FTier <> '' then FInstallInfo.Tier := FTier; - GetRunTools.CheckInternetConnectedState; - - if not FForceOffline and GetRunTools.Online then - // TODO: retry strategies (and prompt around firewall etc) - TOnlineResourceCheck.QueryServer(FSilent, FInstallInfo); + // Try and get information from online + if not GetResourcesFromOnline(FSilent, FForceOffline) then + begin + SetExitVal(ERROR_FILE_NOT_FOUND); + Exit; + end; // This loads setup.inf, if present, for various additional strings and settings // The bundled installer usually contains a setup.inf. @@ -230,13 +230,13 @@ BEGIN Free; end; finally - RemoveTempDir(FTempPath); + FreeAndNil(FInstallInfo); end; SetExitVal(ERROR_SUCCESS); finally - FInstallInfo.Free; + RemoveTempDir(FTempPath); end; except on e:Exception do @@ -254,6 +254,43 @@ BEGIN end; end; +function GetResourcesFromOnline(FSilent: Boolean; var FForceOffline: Boolean): Boolean; +begin + if FForceOffline then + Exit(True); + repeat + try + GetRunTools.CheckInternetConnectedState; + + if GetRunTools.Online then + TOnlineResourceCheck.QueryServer(FSilent, FInstallInfo); + + // We've succeeded. + Exit(True); + except + on E:Exception do + begin + GetRunTools.LogInfo('Could not connect to site: '+E.Message); + if FSilent then + begin + // We log and attempt to continue + FForceOffline := True; + end + else + begin + case MessageDlgW(FInstallInfo.Text(ssOffline), mtError, mbAbortRetryIgnore, 0) of + mrAbort: Exit(False); + mrRetry: Continue; + mrIgnore: FForceOffline := True; + end; + end; + end; + end; + until FForceOffline; + + Result := True; +end; + function CheckForOldVersionScenario: Boolean; // I4460 var OldKMShellPath: string; From 77933c7abad6f45ce69f882d5f1ca9f43e60ba2a Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Mon, 20 Jul 2020 11:14:13 +1000 Subject: [PATCH 5/5] feat(windows): disable defaults options when Keyman already installed --- windows/src/desktop/setup/UfrmInstallOptions.pas | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/windows/src/desktop/setup/UfrmInstallOptions.pas b/windows/src/desktop/setup/UfrmInstallOptions.pas index afe0d7104b..396b5393a2 100644 --- a/windows/src/desktop/setup/UfrmInstallOptions.pas +++ b/windows/src/desktop/setup/UfrmInstallOptions.pas @@ -102,6 +102,8 @@ uses { TfrmInstallOptions } procedure TfrmInstallOptions.FormCreate(Sender: TObject); +var + FAllowOptions: Boolean; begin Caption := FInstallInfo.Text(ssOptionsTitle); chkStartWithWindows.Caption := FInstallInfo.Text(ssOptionsStartWithWindows); @@ -117,6 +119,12 @@ begin lblSelectModulesToInstall.Caption := FInstallInfo.Text(ssOptionsTitleSelectModulesToInstall); lblAssociatedKeyboardLanguage.Caption := FInstallInfo.Text(ssOptionsTitleAssociatedKeyboardLanguage); + FAllowOptions := not FInstallInfo.IsInstalled and FInstallInfo.IsNewerAvailable; + lblDefaultKeymanSettings.Visible := FAllowOptions; + chkAutomaticallyReportUsage.Visible := FAllowOptions; + chkCheckForUpdates.Visible := FAllowOptions; + chkStartWithWindows.Visible := FAllowOptions; + SetupDynamicOptions; end; @@ -241,8 +249,8 @@ begin end else case FInstallInfo.BestMsi.LocationType of - iilLocal: Text := FInstallInfo.Text(ssOptionsInstallKeyman, [FInstallInfo.BestMsi.Version]); - iilOnline: Text := FInstallInfo.Text(ssOptionsDownloadInstallKeyman, [FInstallInfo.BestMsi.Version, FormatFileSize(FInstallInfo.BestMsi.Size)]); + iilLocal: Text := FInstallInfo.Text(ssOptionsUpgradeKeyman, [FInstallInfo.BestMsi.Version]); + iilOnline: Text := FInstallInfo.Text(ssOptionsDownloadUpgradeKeyman, [FInstallInfo.BestMsi.Version, FormatFileSize(FInstallInfo.BestMsi.Size)]); end; end else if FInstallInfo.IsInstalled then