From 53b57939e4e9ca9c6fa8fb97e2969e3a7832f738 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Mon, 13 Nov 2023 13:41:58 +0700 Subject: [PATCH] feat(developer): handle errors loading projects Relates to #9948. Prevents loading of projects other than v1.0, v2.0, and also handles error cases when attempting to load projects. --- developer/src/tike/actions/dmActionsMain.pas | 14 +++++++++++++- developer/src/tike/main/UfrmMain.pas | 13 ++++++++++++- ...n.Developer.System.Project.ProjectFile.pas | 19 +++++++++++++++---- ...Developer.System.Project.ProjectLoader.pas | 4 ++++ 4 files changed, 44 insertions(+), 6 deletions(-) diff --git a/developer/src/tike/actions/dmActionsMain.pas b/developer/src/tike/actions/dmActionsMain.pas index 79dd2ea0394..2230d89c58b 100644 --- a/developer/src/tike/actions/dmActionsMain.pas +++ b/developer/src/tike/actions/dmActionsMain.pas @@ -265,6 +265,7 @@ implementation Keyman.System.KeyboardUtils, Keyman.Developer.System.Project.Project, Keyman.Developer.System.Project.ProjectFileType, + Keyman.Developer.System.Project.ProjectLoader, Keyman.Developer.System.ServerAPI, Keyman.Developer.UI.Project.ProjectFileUI, Keyman.Developer.UI.Project.ProjectUI, @@ -613,7 +614,18 @@ procedure TmodActionsMain.OpenProject(FileName: WideString); if not SaveAndCloseAllFiles then Exit; FreeGlobalProjectUI; end; - LoadGlobalProjectUI(ptUnknown, FileName); // I4687 + try + LoadGlobalProjectUI(ptUnknown, FileName); // I4687 + except + on E:EProjectLoader do + begin + // Message will be displayed by LoadGlobalProjectUI + FreeGlobalProjectUI; + frmKeymanDeveloper.ShowProject; + frmKeymanDeveloper.UpdateCaption; + Exit; + end; + end; frmKeymanDeveloper.ProjectMRU.Add(FGlobalProject.FileName); frmKeymanDeveloper.ShowProject; frmKeymanDeveloper.UpdateCaption; diff --git a/developer/src/tike/main/UfrmMain.pas b/developer/src/tike/main/UfrmMain.pas index b8d88d5e3e4..a2fbf9c34c7 100644 --- a/developer/src/tike/main/UfrmMain.pas +++ b/developer/src/tike/main/UfrmMain.pas @@ -479,6 +479,7 @@ implementation Keyman.Developer.System.Project.ProjectFile, Keyman.Developer.System.Project.ProjectFileType, Keyman.Developer.System.Project.WelcomeRenderer, + Keyman.Developer.System.Project.ProjectLoader, Keyman.Developer.System.Project.ProjectLog, Keyman.Developer.System.Project.XmlLdmlProjectFile, Keyman.Developer.UI.Project.ProjectFileUI, @@ -587,7 +588,17 @@ procedure TfrmKeymanDeveloper.FormCreate(Sender: TObject); FActiveProject := ''; if FActiveProject <> '' then - LoadGlobalProjectUI(ptUnknown, FActiveProject); + begin + try + LoadGlobalProjectUI(ptUnknown, FActiveProject); + except + on E:EProjectLoader do + begin + // Message will be displayed by LoadGlobalProjectUI + FreeGlobalProjectUI; + end; + end; + end; InitDock; diff --git a/developer/src/tike/project/Keyman.Developer.System.Project.ProjectFile.pas b/developer/src/tike/project/Keyman.Developer.System.Project.ProjectFile.pas index 9b7b0da5f7a..e5ddbf9e316 100644 --- a/developer/src/tike/project/Keyman.Developer.System.Project.ProjectFile.pas +++ b/developer/src/tike/project/Keyman.Developer.System.Project.ProjectFile.pas @@ -86,7 +86,7 @@ interface TProjectState = (psCreating, psReady, psLoading, psSaving, psDestroying); TProjectType = (ptUnknown, ptKeyboard, ptLexicalModel); // distinct from utilfiletypes.TKeymanProjectType - TProjectVersion = (pv10, pv20); + TProjectVersion = (pvUnknown, pv10, pv20); TProjectOptionsRecord = record BuildPath: string; @@ -114,7 +114,17 @@ TProjectOptions = class function EqualsRecord(source: TProjectOptionsRecord): Boolean; end; -const DefaultProjectOptions: array[TProjectVersion] of TProjectOptionsRecord = (( +const DefaultProjectOptions: array[TProjectVersion] of TProjectOptionsRecord = ( +( // unknown version, this is unused + BuildPath: ''; + SourcePath: ''; + CompilerWarningsAsErrors: False; + WarnDeprecatedCode: False; + CheckFilenameConventions: False; + SkipMetadatafiles: False; + ProjectType: ptKeyboard; + Version: pvUnknown +), ( // 1.0 BuildPath: ''; SourcePath: ''; CompilerWarningsAsErrors: False; @@ -123,7 +133,7 @@ TProjectOptions = class SkipMetadatafiles: True; ProjectType: ptKeyboard; Version: pv10 -), ( +), ( // 2.0 BuildPath: '$PROJECTPATH/build'; SourcePath: '$PROJECTPATH/source'; CompilerWarningsAsErrors: False; @@ -1472,12 +1482,13 @@ function ProjectVersionFromString(s: string): TProjectVersion; begin if SameText(s, '1.0') then Result := pv10 else if SameText(s, '2.0') then Result := pv20 - else Result := pv10; // TODO is this adequate? + else Result := pvUnknown; end; function ProjectVersionToString(pv: TProjectVersion): string; begin case pv of + pvUnknown: Result := ''; pv10: Result := '1.0'; pv20: Result := '2.0'; end; diff --git a/developer/src/tike/project/Keyman.Developer.System.Project.ProjectLoader.pas b/developer/src/tike/project/Keyman.Developer.System.Project.ProjectLoader.pas index 8fcc34ac2be..c68339ab861 100644 --- a/developer/src/tike/project/Keyman.Developer.System.Project.ProjectLoader.pas +++ b/developer/src/tike/project/Keyman.Developer.System.Project.ProjectLoader.pas @@ -121,7 +121,11 @@ procedure TProjectLoader.LoadProjectFromFile; if node <> nil then begin if not VarIsNull(node.ChildValues['Version']) then + begin FProject.Options.Version := ProjectVersionFromString(VarToStr(node.ChildValues['Version'])); + if FProject.Options.Version = pvUnknown then + raise EProjectLoader.Create('This project format is version '+VarToStr(node.ChildValues['Version'])+', which is not supported by this version of Keyman Developer.'); + end; // Set default project options based on what we learned above FProject.Options.Assign(DefaultProjectOptions[FProject.Options.Version]);