public void Setup() { // Make sure curl is all set up. Curl.Init(); // Give us a registry to play with. ksp = new DisposableKSP(); registry = ksp.KSP.Registry; registry.ClearAvailable(); registry.ClearDlls(); registry.Installed().Clear(); // Make sure we have a registry we can use. CKAN.Repo.UpdateRegistry(TestData.TestKAN(), registry, ksp.KSP, new NullUser()); // Ready our downloader. async = new CKAN.NetAsyncDownloader(new NullUser()); // General shortcuts cache = ksp.KSP.Cache; }
/// <summary> /// Upgrades the mods listed to the latest versions for the user's KSP. /// Will *re-install* with warning even if an upgrade is not available. /// Throws ModuleNotFoundKraken if module is not installed, or not available. /// </summary> public void Upgrade(IEnumerable <string> identifiers, NetAsyncDownloader netAsyncDownloader) { List <CkanModule> upgrades = new List <CkanModule>(); foreach (string ident in identifiers) { CkanModule latest = registry_manager.registry.LatestAvailable( ident, ksp.Version() ); if (latest == null) { throw new ModuleNotFoundKraken( ident, "Can't upgrade {0}, no modules available", ident ); } upgrades.Add(latest); } Upgrade(upgrades, netAsyncDownloader); }
/// <summary> /// Upgrades the mods listed to the specified versions for the user's KSP. /// Will *re-install* or *downgrade* (with a warning) as well as upgrade. /// Throws ModuleNotFoundKraken if a module is not installed. /// </summary> public void Upgrade(IEnumerable <CkanModule> modules, NetAsyncDownloader netAsyncDownloader) { // Start by making sure we've downloaded everything. DownloadModules(modules, netAsyncDownloader); foreach (CkanModule module in modules) { string ident = module.identifier; Module installed = registry_manager.registry.InstalledModule(ident).Module; if (installed == null) { throw new ModuleNotFoundKraken( ident, "Can't upgrade {0}, it is not installed", ident ); } if (installed.version.IsEqualTo(module.version)) { log.WarnFormat("{0} is already at the latest version, reinstalling", installed.identifier); } else if (installed.version.IsGreaterThan(module.version)) { log.WarnFormat("Downgrading {0} from {1} to {2}", ident, installed.version, module.version); } else { log.InfoFormat("Upgrading {0} to {1}", ident, module.version); } } AddRemove( modules, modules.Select(x => x.identifier) ); }
private bool InstallList(HashSet <string> toInstall, RelationshipResolverOptions options, NetAsyncDownloader downloader) { if (toInstall.Any()) { // 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) { 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( "\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); } } return(true); }
private void InstallMods(object sender, DoWorkEventArgs e) // this probably needs to be refactored { installCanceled = false; ClearLog(); var opts = (KeyValuePair <List <KeyValuePair <CkanModule, GUIModChangeType> >, RelationshipResolverOptions>)e.Argument; ModuleInstaller installer = ModuleInstaller.GetInstance(CurrentInstance, GUI.user); // setup progress callback toInstall = new HashSet <string>(); var toUninstall = new HashSet <string>(); var toUpgrade = new HashSet <string>(); // First compose sets of what the user wants installed, upgraded, and removed. foreach (KeyValuePair <CkanModule, GUIModChangeType> change in opts.Key) { switch (change.Value) { case GUIModChangeType.Remove: toUninstall.Add(change.Key.identifier); break; case GUIModChangeType.Update: toUpgrade.Add(change.Key.identifier); break; case GUIModChangeType.Install: toInstall.Add(change.Key.identifier); break; } } // Now work on satisifying dependencies. var recommended = new Dictionary <string, List <string> >(); var suggested = new Dictionary <string, List <string> >(); foreach (var change in opts.Key) { if (change.Value == GUIModChangeType.Install) { if (change.Key.recommends != null) { foreach (RelationshipDescriptor mod in change.Key.recommends) { try { // if the mod is available for the current KSP version _and_ // the mod is not installed _and_ // the mod is not already in the install list if ( RegistryManager.Instance(manager.CurrentInstance) .registry.LatestAvailable(mod.name, manager.CurrentInstance.Version()) != null && !RegistryManager.Instance(manager.CurrentInstance) .registry.IsInstalled(mod.name) && !toInstall.Contains(mod.name)) { // add it to the list of recommended mods we display to the user if (recommended.ContainsKey(mod.name)) { recommended[mod.name].Add(change.Key.identifier); } else { recommended.Add(mod.name, new List <string> { change.Key.identifier }); } } } // XXX - Don't ignore all krakens! Those things are important! catch (Kraken) { } } } if (change.Key.suggests != null) { foreach (RelationshipDescriptor mod in change.Key.suggests) { try { if ( RegistryManager.Instance(manager.CurrentInstance).registry.LatestAvailable(mod.name, manager.CurrentInstance.Version()) != null && !RegistryManager.Instance(manager.CurrentInstance).registry.IsInstalled(mod.name) && !toInstall.Contains(mod.name)) { if (suggested.ContainsKey(mod.name)) { suggested[mod.name].Add(change.Key.identifier); } else { suggested.Add(mod.name, new List <string> { change.Key.identifier }); } } } // XXX - Don't ignore all krakens! Those things are important! catch (Kraken) { } } } } } // If we're going to install something anyway, then don't list it in the // recommended list, since they can't de-select it anyway. foreach (var item in toInstall) { recommended.Remove(item); } // If there are any mods that would be recommended, prompt the user to make // selections. if (recommended.Any()) { Util.Invoke(this, () => UpdateRecommendedDialog(recommended)); m_TabController.ShowTab("ChooseRecommendedModsTabPage", 3); m_TabController.RenameTab("ChooseRecommendedModsTabPage", "Choose recommended mods"); m_TabController.SetTabLock(true); lock (this) { Monitor.Wait(this); } m_TabController.SetTabLock(false); } m_TabController.HideTab("ChooseRecommendedModsTabPage"); // And now on to suggestions. Again, we don't show anything that's scheduled to // be installed on our suggest list. foreach (var item in toInstall) { suggested.Remove(item); } if (suggested.Any()) { Util.Invoke(this, () => UpdateRecommendedDialog(suggested, true)); m_TabController.ShowTab("ChooseRecommendedModsTabPage", 3); m_TabController.RenameTab("ChooseRecommendedModsTabPage", "Choose suggested mods"); m_TabController.SetTabLock(true); lock (this) { Monitor.Wait(this); } m_TabController.SetTabLock(false); } m_TabController.HideTab("ChooseRecommendedModsTabPage"); if (installCanceled) { m_TabController.HideTab("WaitTabPage"); m_TabController.ShowTab("ManageModsTabPage"); e.Result = new KeyValuePair <bool, List <KeyValuePair <CkanModule, GUIModChangeType> > >(false, opts.Key); return; } // Now let's make all our changes. m_TabController.RenameTab("WaitTabPage", "Installing mods"); m_TabController.ShowTab("WaitTabPage"); m_TabController.SetTabLock(true); using (var transaction = new CkanTransaction()) { var downloader = new NetAsyncDownloader(GUI.user); cancelCallback = () => { downloader.CancelDownload(); installCanceled = true; }; SetDescription("Uninstalling selected mods"); installer.UninstallList(toUninstall); if (installCanceled) { return; } SetDescription("Updating selected mods"); installer.Upgrade(toUpgrade, downloader); // TODO: We should be able to resolve all our provisioning conflicts // before we start installing anything. CKAN.SanityChecker can be used to // pre-check if our changes are going to be consistent. bool resolvedAllProvidedMods = false; while (!resolvedAllProvidedMods) { if (installCanceled) { e.Result = new KeyValuePair <bool, List <KeyValuePair <CkanModule, GUIModChangeType> > >(false, opts.Key); return; } try { 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 <bool, List <KeyValuePair <CkanModule, GUIModChangeType> > >(false, opts.Key); return; } resolvedAllProvidedMods = true; } catch (TooManyModsProvideKraken tooManyProvides) { Util.Invoke(this, () => UpdateProvidedModsDialog(tooManyProvides)); m_TabController.ShowTab("ChooseProvidedModsTabPage", 3); m_TabController.SetTabLock(true); lock (this) { Monitor.Wait(this); } m_TabController.SetTabLock(false); m_TabController.HideTab("ChooseProvidedModsTabPage"); if (installCanceled) { m_TabController.HideTab("WaitTabPage"); m_TabController.ShowTab("ManageModsTabPage"); e.Result = new KeyValuePair <bool, List <KeyValuePair <CkanModule, GUIModChangeType> > >(false, opts.Key); return; } m_TabController.ShowTab("WaitTabPage"); } } if (!installCanceled) { transaction.Complete(); } } e.Result = new KeyValuePair <bool, List <KeyValuePair <CkanModule, GUIModChangeType> > >(true, opts.Key); }
/// <summary> /// Returns a perfectly boring NetAsyncModulesDownloader. /// </summary> public NetAsyncModulesDownloader(IUser user) { modules = new List <CkanModule>(); downloader = new NetAsyncDownloader(user); }
public void Setup() { // Make sure curl is all set up. Curl.Init(); // Give us a registry to play with. ksp = new DisposableKSP(); registry = ksp.KSP.Registry; registry.ClearAvailable(); registry.ClearDlls(); registry.Installed().Clear(); // Make sure we have a registry we can use. CKAN.Repo.UpdateRegistry(TestData.TestKANZip(), registry, ksp.KSP, new NullUser()); // Ready our downloader. async = new CKAN.NetAsyncDownloader(new NullUser()); // General shortcuts cache = ksp.KSP.Cache; }
/// <summary> /// Upgrades the mods listed to the latest versions for the user's KSP. /// Will *re-install* with warning even if an upgrade is not available. /// Throws ModuleNotFoundKraken if module is not installed, or not available. /// </summary> public void Upgrade(IEnumerable<string> identifiers, NetAsyncDownloader netAsyncDownloader) { var options = new RelationshipResolverOptions(); // We do not wish to pull in any suggested or recommended mods. options.with_recommends = false; options.with_suggests = false; var resolver = new RelationshipResolver(identifiers.ToList(), options, registry_manager.registry, ksp.Version()); List<CkanModule> upgrades = resolver.ModList(); Upgrade(upgrades, netAsyncDownloader); }
// this probably needs to be refactored private void InstallMods(object sender, DoWorkEventArgs e) { installCanceled = false; ClearLog(); var opts = (KeyValuePair<ModChanges, RelationshipResolverOptions>) e.Argument; IRegistryQuerier registry = RegistryManager.Instance(manager.CurrentInstance).registry; ModuleInstaller installer = ModuleInstaller.GetInstance(CurrentInstance, GUI.user); // setup progress callback toInstall = new HashSet<string>(); var toUninstall = new HashSet<string>(); var toUpgrade = new HashSet<string>(); // First compose sets of what the user wants installed, upgraded, and removed. foreach (ModChange change in opts.Key) { switch (change.ChangeType) { case GUIModChangeType.Remove: toUninstall.Add(change.Mod.Identifier); break; case GUIModChangeType.Update: toUpgrade.Add(change.Mod.Identifier); break; case GUIModChangeType.Install: toInstall.Add(change.Mod.Identifier); break; } } // Now work on satisifying dependencies. var recommended = new Dictionary<string, List<string>>(); var suggested = new Dictionary<string, List<string>>(); foreach (var change in opts.Key) { if (change.ChangeType == GUIModChangeType.Install) { AddMod(change.Mod.ToModule().recommends, recommended, change.Mod.Identifier, registry); AddMod(change.Mod.ToModule().suggests, suggested, change.Mod.Identifier, registry); } } ShowSelection(recommended); ShowSelection(suggested, true); m_TabController.HideTab("ChooseRecommendedModsTabPage"); if (installCanceled) { m_TabController.HideTab("WaitTabPage"); m_TabController.ShowTab("ManageModsTabPage"); e.Result = new KeyValuePair<bool, ModChanges>(false, opts.Key); return; } // Now let's make all our changes. m_TabController.RenameTab("WaitTabPage", "Status log"); m_TabController.ShowTab("WaitTabPage"); m_TabController.SetTabLock(true); var downloader = new NetAsyncDownloader(GUI.user); cancelCallback = () => { downloader.CancelDownload(); installCanceled = true; }; //Transaction is needed here to revert changes when an installation is cancelled //TODO: Cancellation should be handelt in the ModuleInstaller using (var transaction = CkanTransaction.CreateTransactionScope()) { //Set the result to false/failed in case we return e.Result = new KeyValuePair<bool, ModChanges>(false, opts.Key); SetDescription("Uninstalling selected mods"); if (!WasSuccessful(() => installer.UninstallList(toUninstall))) return; if (installCanceled) return; SetDescription("Updating selected mods"); if (!WasSuccessful(() => installer.Upgrade(toUpgrade, downloader))) return; if (installCanceled) return; // TODO: We should be able to resolve all our provisioning conflicts // before we start installing anything. CKAN.SanityChecker can be used to // pre-check if our changes are going to be consistent. bool resolvedAllProvidedMods = false; while (!resolvedAllProvidedMods) { if (installCanceled) { e.Result = new KeyValuePair<bool, ModChanges>(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<bool, ModChanges>(false, opts.Key); return; } resolvedAllProvidedMods = true; } if (!installCanceled) { transaction.Complete(); } } e.Result = new KeyValuePair<bool, ModChanges>(!installCanceled, opts.Key); }
/// <summary> /// Returns a perfectly boring NetAsyncModulesDownloader. /// </summary> public NetAsyncModulesDownloader(IUser user, FactorioAuthData factorioAuthData = null) { modules = new List <CfanModule>(); downloader = new NetAsyncDownloader(user); this.factorioAuthData = factorioAuthData; }
private bool InstallList(HashSet<string> 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; }
/// <summary> /// Returns a perfectly boring NetAsyncModulesDownloader. /// </summary> public NetAsyncModulesDownloader(IUser user, NetModuleCache cache) { modules = new List <CkanModule>(); downloader = new NetAsyncDownloader(user); this.cache = cache; }
/// <summary> /// Makes sure all the specified mods are downloaded. /// </summary> private void DownloadModules(IEnumerable<CkanModule> mods, NetAsyncDownloader downloader) { List<CkanModule> downloads = mods.Where(module => !ksp.Cache.IsCachedZip(module.download)).ToList(); if (downloads.Count > 0) { downloader.DownloadModules(ksp.Cache, downloads); } }
/// <summary> /// Upgrades or installs the mods listed to the specified versions for the user's KSP. /// Will *re-install* or *downgrade* (with a warning) as well as upgrade. /// Throws ModuleNotFoundKraken if a module is not installed. /// </summary> public void Upgrade(IEnumerable<CkanModule> modules, NetAsyncDownloader netAsyncDownloader) { // Start by making sure we've downloaded everything. DownloadModules(modules, netAsyncDownloader); // Our upgrade involves removing everything that's currently installed, then // adding everything that needs installing (which may involve new mods to // satisfy dependencies). We always know the list passed in is what we need to // install, but we need to calculate what needs to be removed. var to_remove = new List<string>(); // Let's discover what we need to do with each module! foreach (CkanModule module in modules) { string ident = module.identifier; InstalledModule installed_mod = registry_manager.registry.InstalledModule(ident); if (installed_mod == null) { //Maybe ModuleNotInstalled ? if (registry_manager.registry.IsAutodetected(ident)) { throw new ModuleNotFoundKraken(ident, module.version.ToString(), String.Format("Can't upgrade {0} as it was not installed by CKAN. \n Please remove manually before trying to install it.", ident)); } User.RaiseMessage("Installing previously uninstalled mod {0}", ident); } else { // Module already installed. We'll need to remove it first. to_remove.Add(module.identifier); Module installed = installed_mod.Module; if (installed.version.IsEqualTo(module.version)) { log.WarnFormat("{0} is already at the latest version, reinstalling", installed.identifier); } else if (installed.version.IsGreaterThan(module.version)) { log.WarnFormat("Downgrading {0} from {1} to {2}", ident, installed.version, module.version); } else { log.InfoFormat("Upgrading {0} to {1}", ident, module.version); } } } AddRemove( modules, to_remove ); }
/// <summary> /// Installs all modules given a list of identifiers as a transaction. Resolves dependencies. /// This *will* save the registry at the end of operation. /// /// Propagates a BadMetadataKraken if our install metadata is bad. /// Propagates a FileExistsKraken if we were going to overwrite a file. /// Propagates a CancelledActionKraken if the user cancelled the install. /// </summary> // // TODO: Break this up into smaller pieces! It's huge! public void InstallList( ICollection<CkanModule> modules, RelationshipResolverOptions options, IDownloader downloader = null ) { var resolver = new RelationshipResolver(modules, options, registry_manager.registry, ksp.Version()); List<CkanModule> modsToInstall = resolver.ModList(); List<CkanModule> downloads = new List<CkanModule> (); // TODO: All this user-stuff should be happening in another method! // We should just be installing mods as a transaction. User.RaiseMessage("About to install...\n"); foreach (CkanModule module in modsToInstall) { if (!ksp.Cache.IsCachedZip(module.download)) { User.RaiseMessage(" * {0} {1}", module.name, module.version); downloads.Add(module); } else { User.RaiseMessage(" * {0} {1}(cached)", module.name, module.version); } } bool ok = User.RaiseYesNoDialog("\nContinue?"); if (!ok) { throw new CancelledActionKraken("User declined install list"); } User.RaiseMessage(String.Empty); // Just to look tidy. if (downloads.Count > 0) { if (downloader == null) { downloader = new NetAsyncDownloader(User); } downloader.DownloadModules(ksp.Cache, downloads); } // We're about to install all our mods; so begin our transaction. using (TransactionScope transaction = CkanTransaction.CreateTransactionScope()) { for (int i = 0; i < modsToInstall.Count; i++) { int percent_complete = (i * 100) / modsToInstall.Count; User.RaiseProgress(String.Format("Installing mod \"{0}\"", modsToInstall[i]), percent_complete); Install(modsToInstall[i]); } User.RaiseProgress("Updating registry", 70); registry_manager.Save(!options.without_enforce_consistency); User.RaiseProgress("Commiting filesystem changes", 80); transaction.Complete(); } // We can scan GameData as a separate transaction. Installing the mods // leaves everything consistent, and this is just gravy. (And ScanGameData // acts as a Tx, anyway, so we don't need to provide our own.) User.RaiseProgress("Rescanning GameData", 90); if (!options.without_enforce_consistency) { ksp.ScanGameData(); } User.RaiseProgress("Done!\n", 100); }
// this probably needs to be refactored private void InstallMods(object sender, DoWorkEventArgs e) { installCanceled = false; ClearLog(); var opts = (KeyValuePair<ModChanges, RelationshipResolverOptions>) e.Argument; ModuleInstaller installer = ModuleInstaller.GetInstance(CurrentInstance, GUI.user); // setup progress callback toInstall = new HashSet<string>(); var toUninstall = new HashSet<string>(); var toUpgrade = new HashSet<string>(); // First compose sets of what the user wants installed, upgraded, and removed. foreach (KeyValuePair<GUIMod, GUIModChangeType> change in opts.Key) { switch (change.Value) { case GUIModChangeType.Remove: toUninstall.Add(change.Key.Identifier); break; case GUIModChangeType.Update: toUpgrade.Add(change.Key.Identifier); break; case GUIModChangeType.Install: toInstall.Add(change.Key.Identifier); break; } } // Now work on satisifying dependencies. var recommended = new Dictionary<string, List<string>>(); var suggested = new Dictionary<string, List<string>>(); foreach (var change in opts.Key) { if (change.Value == GUIModChangeType.Install) { if (change.Key.ToModule().recommends != null) { foreach (RelationshipDescriptor mod in change.Key.ToModule().recommends) { try { // if the mod is available for the current KSP version _and_ // the mod is not installed _and_ // the mod is not already in the install list if ( RegistryManager.Instance(manager.CurrentInstance) .registry.LatestAvailable(mod.name, manager.CurrentInstance.Version()) != null && !RegistryManager.Instance(manager.CurrentInstance) .registry.IsInstalled(mod.name) && !toInstall.Contains(mod.name)) { // add it to the list of recommended mods we display to the user if (recommended.ContainsKey(mod.name)) { recommended[mod.name].Add(change.Key.Identifier); } else { recommended.Add(mod.name, new List<string> {change.Key.Identifier}); } } } // XXX - Don't ignore all krakens! Those things are important! catch (Kraken) { } } } if (change.Key.ToModule().suggests != null) { foreach (RelationshipDescriptor mod in change.Key.ToModule().suggests) { try { if ( RegistryManager.Instance(manager.CurrentInstance) .registry.LatestAvailable(mod.name, manager.CurrentInstance.Version()) != null && !RegistryManager.Instance(manager.CurrentInstance).registry.IsInstalled(mod.name) && !toInstall.Contains(mod.name)) { if (suggested.ContainsKey(mod.name)) { suggested[mod.name].Add(change.Key.Identifier); } else { suggested.Add(mod.name, new List<string> {change.Key.Identifier}); } } } // XXX - Don't ignore all krakens! Those things are important! catch (Kraken) { } } } } } // If we're going to install something anyway, then don't list it in the // recommended list, since they can't de-select it anyway. foreach (var item in toInstall) { recommended.Remove(item); } // If there are any mods that would be recommended, prompt the user to make // selections. if (recommended.Any()) { Util.Invoke(this, () => UpdateRecommendedDialog(recommended)); m_TabController.ShowTab("ChooseRecommendedModsTabPage", 3); m_TabController.RenameTab("ChooseRecommendedModsTabPage", "Choose recommended mods"); m_TabController.SetTabLock(true); lock (this) { Monitor.Wait(this); } m_TabController.SetTabLock(false); } m_TabController.HideTab("ChooseRecommendedModsTabPage"); // And now on to suggestions. Again, we don't show anything that's scheduled to // be installed on our suggest list. foreach (var item in toInstall) { suggested.Remove(item); } if (suggested.Any()) { Util.Invoke(this, () => UpdateRecommendedDialog(suggested, true)); m_TabController.ShowTab("ChooseRecommendedModsTabPage", 3); m_TabController.RenameTab("ChooseRecommendedModsTabPage", "Choose suggested mods"); m_TabController.SetTabLock(true); lock (this) { Monitor.Wait(this); } m_TabController.SetTabLock(false); } m_TabController.HideTab("ChooseRecommendedModsTabPage"); if (installCanceled) { m_TabController.HideTab("WaitTabPage"); m_TabController.ShowTab("ManageModsTabPage"); e.Result = new KeyValuePair<bool, ModChanges>(false, opts.Key); return; } // Now let's make all our changes. m_TabController.RenameTab("WaitTabPage", "Installing mods"); m_TabController.ShowTab("WaitTabPage"); m_TabController.SetTabLock(true); var downloader = new NetAsyncDownloader(GUI.user); cancelCallback = () => { downloader.CancelDownload(); installCanceled = true; }; //Transaction is needed here to revert changes when an installation is cancelled //TODO: Cancellation should be handelt in the ModuleInstaller using (var transaction = CkanTransaction.CreateTransactionScope()) { //Set the result to false/failed in case we return e.Result = new KeyValuePair<bool, ModChanges>(false, opts.Key); SetDescription("Uninstalling selected mods"); if (!WasSuccessful(() => installer.UninstallList(toUninstall))) return; if (installCanceled) return; SetDescription("Updating selected mods"); if (!WasSuccessful(() => installer.Upgrade(toUpgrade, downloader))) return; if (installCanceled) return; // TODO: We should be able to resolve all our provisioning conflicts // before we start installing anything. CKAN.SanityChecker can be used to // pre-check if our changes are going to be consistent. bool resolvedAllProvidedMods = false; while (!resolvedAllProvidedMods) { if (installCanceled) { e.Result = new KeyValuePair<bool, ModChanges>(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<bool, ModChanges>(false, opts.Key); return; } resolvedAllProvidedMods = true; } if (!installCanceled) { transaction.Complete(); } } e.Result = new KeyValuePair<bool, ModChanges>(!installCanceled, opts.Key); }
private void InstallMods(object sender, DoWorkEventArgs e) // this probably needs to be refactored { installCanceled = false; ClearLog(); var opts = (KeyValuePair <ModChanges, RelationshipResolverOptions>)e.Argument; IRegistryQuerier registry = RegistryManager.Instance(manager.CurrentInstance).registry; ModuleInstaller installer = ModuleInstaller.GetInstance(CurrentInstance, GUI.user); // setup progress callback toInstall = new HashSet <string>(); var toUninstall = new HashSet <string>(); var toUpgrade = new HashSet <string>(); // First compose sets of what the user wants installed, upgraded, and removed. foreach (ModChange change in opts.Key) { switch (change.ChangeType) { case GUIModChangeType.Remove: toUninstall.Add(change.Mod.Identifier); break; case GUIModChangeType.Update: toUpgrade.Add(change.Mod.Identifier); break; case GUIModChangeType.Install: toInstall.Add(change.Mod.Identifier); break; } } // Now work on satisifying dependencies. var recommended = new Dictionary <string, List <string> >(); var suggested = new Dictionary <string, List <string> >(); foreach (var change in opts.Key) { if (change.ChangeType == GUIModChangeType.Install) { AddMod(change.Mod.ToModule().recommends, recommended, change.Mod.Identifier, registry); AddMod(change.Mod.ToModule().suggests, suggested, change.Mod.Identifier, registry); } } ShowSelection(recommended); ShowSelection(suggested, true); m_TabController.HideTab("ChooseRecommendedModsTabPage"); if (installCanceled) { m_TabController.HideTab("WaitTabPage"); m_TabController.ShowTab("ManageModsTabPage"); e.Result = new KeyValuePair <bool, ModChanges>(false, opts.Key); return; } // Now let's make all our changes. m_TabController.RenameTab("WaitTabPage", "Status log"); m_TabController.ShowTab("WaitTabPage"); m_TabController.SetTabLock(true); var downloader = new NetAsyncDownloader(GUI.user); cancelCallback = () => { downloader.CancelDownload(); installCanceled = true; }; //Transaction is needed here to revert changes when an installation is cancelled //TODO: Cancellation should be handelt in the ModuleInstaller using (var transaction = CkanTransaction.CreateTransactionScope()) { //Set the result to false/failed in case we return e.Result = new KeyValuePair <bool, ModChanges>(false, opts.Key); SetDescription("Uninstalling selected mods"); if (!WasSuccessful(() => installer.UninstallList(toUninstall))) { return; } if (installCanceled) { return; } SetDescription("Updating selected mods"); if (!WasSuccessful(() => installer.Upgrade(toUpgrade, downloader))) { return; } if (installCanceled) { return; } // TODO: We should be able to resolve all our provisioning conflicts // before we start installing anything. CKAN.SanityChecker can be used to // pre-check if our changes are going to be consistent. bool resolvedAllProvidedMods = false; while (!resolvedAllProvidedMods) { if (installCanceled) { e.Result = new KeyValuePair <bool, ModChanges>(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 <bool, ModChanges>(false, opts.Key); return; } resolvedAllProvidedMods = true; } if (!installCanceled) { transaction.Complete(); } } e.Result = new KeyValuePair <bool, ModChanges>(!installCanceled, opts.Key); }
/// <summary> /// Installs all modules given a list of identifiers as a transaction. Resolves dependencies. /// This *will* save the registry at the end of operation. /// /// Propagates a BadMetadataKraken if our install metadata is bad. /// Propagates a FileExistsKraken if we were going to overwrite a file. /// Propagates a CancelledActionKraken if the user cancelled the install. /// </summary> // // TODO: Break this up into smaller pieces! It's huge! public void InstallList( ICollection <CkanModule> modules, RelationshipResolverOptions options, IDownloader downloader = null ) { var resolver = new RelationshipResolver(modules, options, registry_manager.registry, ksp.Version()); List <CkanModule> modsToInstall = resolver.ModList(); List <CkanModule> downloads = new List <CkanModule> (); // TODO: All this user-stuff should be happening in another method! // We should just be installing mods as a transaction. User.RaiseMessage("About to install...\n"); foreach (CkanModule module in modsToInstall) { if (!ksp.Cache.IsCachedZip(module.download)) { User.RaiseMessage(" * {0}", module); downloads.Add(module); } else { User.RaiseMessage(" * {0} (cached)", module); } } bool ok = User.RaiseYesNoDialog("\nContinue?"); if (!ok) { throw new CancelledActionKraken("User declined install list"); } User.RaiseMessage(String.Empty); // Just to look tidy. if (downloads.Count > 0) { if (downloader == null) { downloader = new NetAsyncDownloader(User); } downloader.DownloadModules(ksp.Cache, downloads); } // We're about to install all our mods; so begin our transaction. using (TransactionScope transaction = CkanTransaction.CreateTransactionScope()) { for (int i = 0; i < modsToInstall.Count; i++) { int percent_complete = (i * 100) / modsToInstall.Count; User.RaiseProgress(String.Format("Installing mod \"{0}\"", modsToInstall[i]), percent_complete); Install(modsToInstall[i]); } User.RaiseProgress("Updating registry", 70); registry_manager.Save(!options.without_enforce_consistency); User.RaiseProgress("Commiting filesystem changes", 80); transaction.Complete(); } // We can scan GameData as a separate transaction. Installing the mods // leaves everything consistent, and this is just gravy. (And ScanGameData // acts as a Tx, anyway, so we don't need to provide our own.) User.RaiseProgress("Rescanning GameData", 90); if (!options.without_enforce_consistency) { ksp.ScanGameData(); } User.RaiseProgress("Done!\n", 100); }
private void CacheMod(object sender, DoWorkEventArgs e) { ResetProgress(); ClearLog(); NetAsyncDownloader dowloader = new NetAsyncDownloader(m_User); dowloader.DownloadModules(CurrentInstance.Cache, new List<CkanModule> { (CkanModule)e.Argument }); e.Result = e.Argument; }
/// <summary> /// Installs all modules given a list of identifiers as a transaction. Resolves dependencies. /// This *will* save the registry at the end of operation. /// /// Propagates a BadMetadataKraken if our install metadata is bad. /// Propagates a FileExistsKraken if we were going to overwrite a file. /// Propagates a CancelledActionKraken if the user cancelled the install. /// </summary> // // TODO: Break this up into smaller pieces! It's huge! public void InstallList( List <string> modules, RelationshipResolverOptions options, NetAsyncDownloader downloader = null ) { onReportProgress = onReportProgress ?? ((message, progress) => { }); var resolver = new RelationshipResolver(modules, options, registry_manager.registry); List <CkanModule> modsToInstall = resolver.ModList(); List <CkanModule> downloads = new List <CkanModule> (); // TODO: All this user-stuff should be happening in another method! // We should just be installing mods as a transaction. User.WriteLine("About to install...\n"); foreach (CkanModule module in modsToInstall) { if (!ksp.Cache.IsCachedZip(module.download)) { User.WriteLine(" * {0}", module); downloads.Add(module); } else { User.WriteLine(" * {0} (cached)", module); } } bool ok = User.YesNo("\nContinue?", FrontEndType.CommandLine); if (!ok) { throw new CancelledActionKraken("User declined install list"); } User.WriteLine(""); // Just to look tidy. if (downloads.Count > 0) { if (downloader == null) { downloader = new NetAsyncDownloader(); } downloader.DownloadModules(ksp.Cache, downloads, onReportProgress); } // We're about to install all our mods; so begin our transaction. var txoptions = new TransactionOptions(); txoptions.Timeout = TransactionManager.MaximumTimeout; using (TransactionScope transaction = new TransactionScope(TransactionScopeOption.Required, txoptions)) { for (int i = 0; i < modsToInstall.Count; i++) { int percentComplete = (i * 100) / modsToInstall.Count; onReportProgress(String.Format("Installing mod \"{0}\"", modsToInstall[i]), percentComplete); Install(modsToInstall[i]); } onReportProgress("Updating registry", 70); registry_manager.Save(); onReportProgress("Commiting filesystem changes", 80); transaction.Complete(); } // We can scan GameData as a separate transaction. Installing the mods // leaves everything consistent, and this is just gravy. (And ScanGameData // acts as a Tx, anyway, so we don't need to provide our own.) onReportProgress("Rescanning GameData", 90); ksp.ScanGameData(); onReportProgress("Done!", 100); }
public void InstallList( List<string> modules, RelationshipResolverOptions options, NetAsyncDownloader downloader = null ) { var resolver = new RelationshipResolver(modules, options, registry_manager.registry, ksp.Version()); List<CkanModule> modsToInstall = resolver.ModList(); InstallList(modsToInstall, options, downloader); }