From d196dc5392c6a85b38fb5f2f174ca618ab45cf1c Mon Sep 17 00:00:00 2001 From: Richard Lake Date: Mon, 22 Jun 2015 17:47:36 +0930 Subject: [PATCH 1/2] Expand error handling in MainInstall. Create helper method to wrap ModuleInstaller.UninstallList/Upgrade/InstallList as they share many of their errors. --- GUI/MainInstall.cs | 179 ++++++++++++++++++++++++--------------------- 1 file changed, 96 insertions(+), 83 deletions(-) diff --git a/GUI/MainInstall.cs b/GUI/MainInstall.cs index 6ba5eacbdd..4713e210e0 100644 --- a/GUI/MainInstall.cs +++ b/GUI/MainInstall.cs @@ -202,13 +202,16 @@ private void InstallMods(object sender, DoWorkEventArgs e) // this probably need installCanceled = true; }; - + //Set the result to false/failed in case we return + e.Result = new KeyValuePair>>(false, opts.Key); SetDescription("Uninstalling selected mods"); - installer.UninstallList(toUninstall); + if (!WasSuccessful(() => installer.UninstallList(toUninstall))) + return; if (installCanceled) return; SetDescription("Updating selected mods"); - installer.Upgrade(toUpgrade, downloader); + if (!WasSuccessful(() => installer.Upgrade(toUpgrade, downloader))) + return; // TODO: We should be able to resolve all our provisioning conflicts @@ -239,94 +242,104 @@ private void InstallMods(object sender, DoWorkEventArgs e) // this probably need e.Result = new KeyValuePair>>(true, opts.Key); } - private bool InstallList(HashSet toInstall, RelationshipResolverOptions options, - NetAsyncDownloader downloader) + /// + /// Helper function to wrap around calls to ModuleInstaller. + /// Handles some of the possible krakens and displays user friendly messages for them. + /// + private static bool WasSuccessful(Action action) { - if (toInstall.Any()) + try { - // actual magic happens here, we run the installer with our mod list - ModuleInstaller.GetInstance(manager.CurrentInstance, GUI.user).onReportModInstalled = OnModInstalled; - cancelCallback = downloader.CancelDownload; - try - { - ModuleInstaller.GetInstance(manager.CurrentInstance, GUI.user) - .InstallList(toInstall.ToList(), options, downloader); - } - catch (ModuleNotFoundKraken ex) + action(); + } + catch (ModuleNotFoundKraken ex) + { + GUI.user.RaiseMessage( + "Module {0} required, but not listed in index, or not available for your version of KSP", + ex.module); + return false; + } + catch (BadMetadataKraken ex) + { + GUI.user.RaiseMessage("Bad metadata detected for module {0}: {1}", ex.module, ex.Message); + return false; + } + catch (FileExistsKraken ex) + { + if (ex.owning_module != null) { GUI.user.RaiseMessage( - "Module {0} required, but not listed in index, or not available for your version of KSP", - ex.module); - return false; + "\nOh no! We tried to overwrite a file owned by another mod!\n" + + "Please try a `ckan update` and try again.\n\n" + + "If this problem re-occurs, then it maybe a packaging bug.\n" + + "Please report it at:\n\n" + + "https://github.com/KSP-CKAN/CKAN-meta/issues/new\n\n" + + "Please including the following information in your report:\n\n" + + "File : {0}\n" + + "Installing Mod : {1}\n" + + "Owning Mod : {2}\n" + + "CKAN Version : {3}\n", + ex.filename, ex.installing_module, ex.owning_module, + Meta.Version() + ); } - catch (BadMetadataKraken ex) + else { - GUI.user.RaiseMessage("Bad metadata detected for module {0}: {1}", ex.module, ex.Message); - return false; + GUI.user.RaiseMessage( + "\n\nOh no!\n\n" + + "It looks like you're trying to install a mod which is already installed,\n" + + "or which conflicts with another mod which is already installed.\n\n" + + "As a safety feature, the CKAN will *never* overwrite or alter a file\n" + + "that it did not install itself.\n\n" + + "If you wish to install {0} via the CKAN,\n" + + "then please manually uninstall the mod which owns:\n\n" + + "{1}\n\n" + "and try again.\n", + ex.installing_module, ex.filename + ); } - catch (FileExistsKraken ex) - { - if (ex.owning_module != null) - { - GUI.user.RaiseMessage( - "\nOh no! We tried to overwrite a file owned by another mod!\n" + - "Please try a `ckan update` and try again.\n\n" + - "If this problem re-occurs, then it maybe a packaging bug.\n" + - "Please report it at:\n\n" + - "https://github.com/KSP-CKAN/CKAN-meta/issues/new\n\n" + - "Please including the following information in your report:\n\n" + - "File : {0}\n" + - "Installing Mod : {1}\n" + - "Owning Mod : {2}\n" + - "CKAN Version : {3}\n", - ex.filename, ex.installing_module, ex.owning_module, - Meta.Version() - ); - } - else - { - GUI.user.RaiseMessage( - "\n\nOh no!\n\n" + - "It looks like you're trying to install a mod which is already installed,\n" + - "or which conflicts with another mod which is already installed.\n\n" + - "As a safety feature, the CKAN will *never* overwrite or alter a file\n" + - "that it did not install itself.\n\n" + - "If you wish to install {0} via the CKAN,\n" + - "then please manually uninstall the mod which owns:\n\n" + - "{1}\n\n" + "and try again.\n", - ex.installing_module, ex.filename - ); - } - GUI.user.RaiseMessage("Your GameData has been returned to its original state.\n"); - return false; - } - catch (InconsistentKraken ex) - { - // The prettiest Kraken formats itself for us. - GUI.user.RaiseMessage(ex.InconsistenciesPretty); - return false; - } - catch (CancelledActionKraken) - { - return false; - } - catch (MissingCertificateKraken kraken) - { - // Another very pretty kraken. - GUI.user.RaiseMessage(kraken.ToString()); - return false; - } - catch (DownloadErrorsKraken) - { - // User notified in InstallList - return false; - } - catch (DirectoryNotFoundKraken kraken) - { - GUI.user.RaiseMessage("\n{0}", kraken.Message); - return false; - } + GUI.user.RaiseMessage("Your GameData has been returned to its original state.\n"); + return false; + } + catch (InconsistentKraken ex) + { + // The prettiest Kraken formats itself for us. + GUI.user.RaiseMessage(ex.InconsistenciesPretty); + return false; + } + catch (CancelledActionKraken) + { + return false; + } + catch (MissingCertificateKraken kraken) + { + // Another very pretty kraken. + GUI.user.RaiseMessage(kraken.ToString()); + return false; + } + catch (DownloadErrorsKraken) + { + // User notified in InstallList + return false; + } + catch (DirectoryNotFoundKraken kraken) + { + GUI.user.RaiseMessage("\n{0}", kraken.Message); + return false; + } + return true; + } + private bool InstallList(HashSet toInstall, RelationshipResolverOptions options, + NetAsyncDownloader downloader) + { + if (toInstall.Any()) + { + // actual magic happens here, we run the installer with our mod list + var module_installer = ModuleInstaller.GetInstance(manager.CurrentInstance, GUI.user); + module_installer.onReportModInstalled = OnModInstalled; + cancelCallback = downloader.CancelDownload; + return WasSuccessful( + () => module_installer.InstallList(toInstall.ToList(), options, downloader)); } return true; From 9f59bafa50477536938632202ae5d7209b67b6a0 Mon Sep 17 00:00:00 2001 From: Richard Lake Date: Mon, 22 Jun 2015 20:42:12 +0930 Subject: [PATCH 2/2] Create a typedef to simplify code. --- GUI/MainInstall.cs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/GUI/MainInstall.cs b/GUI/MainInstall.cs index 4713e210e0..69d1c0f285 100644 --- a/GUI/MainInstall.cs +++ b/GUI/MainInstall.cs @@ -8,6 +8,7 @@ namespace CKAN { + using ModChanges = List>; public partial class Main { private BackgroundWorker m_InstallWorker; @@ -27,7 +28,7 @@ private void InstallMods(object sender, DoWorkEventArgs e) // this probably need ClearLog(); var opts = - (KeyValuePair>, RelationshipResolverOptions>) e.Argument; + (KeyValuePair) e.Argument; ModuleInstaller installer = ModuleInstaller.GetInstance(CurrentInstance, GUI.user); // setup progress callback @@ -184,7 +185,7 @@ private void InstallMods(object sender, DoWorkEventArgs e) // this probably need { m_TabController.HideTab("WaitTabPage"); m_TabController.ShowTab("ManageModsTabPage"); - e.Result = new KeyValuePair>>(false, opts.Key); + e.Result = new KeyValuePair(false, opts.Key); return; } @@ -203,7 +204,7 @@ private void InstallMods(object sender, DoWorkEventArgs e) // this probably need }; //Set the result to false/failed in case we return - e.Result = new KeyValuePair>>(false, opts.Key); + e.Result = new KeyValuePair(false, opts.Key); SetDescription("Uninstalling selected mods"); if (!WasSuccessful(() => installer.UninstallList(toUninstall))) return; @@ -224,22 +225,20 @@ private void InstallMods(object sender, DoWorkEventArgs e) // this probably need { if (installCanceled) { - e.Result = new KeyValuePair>>(false, - opts.Key); + e.Result = new KeyValuePair(false,opts.Key); return; } var ret = InstallList(toInstall, opts.Value, downloader); if (!ret) { // install failed for some reason, error message is already displayed to the user - e.Result = new KeyValuePair>>(false, - opts.Key); + e.Result = new KeyValuePair(false,opts.Key); return; } resolvedAllProvidedMods = true; } - e.Result = new KeyValuePair>>(true, opts.Key); + e.Result = new KeyValuePair(true, opts.Key); } /// @@ -355,7 +354,7 @@ private void PostInstallMods(object sender, RunWorkerCompletedEventArgs e) UpdateModsList(); m_TabController.SetTabLock(false); - var result = (KeyValuePair>>) e.Result; + var result = (KeyValuePair) e.Result; if (result.Key) {