public void UpdateRegistryTarGz() { CKAN.Repo.UpdateRegistry(TestData.TestKANTarGz(), registry, ksp.KSP, new NullUser()); // Test we've got an expected module. CKAN.CkanModule far = registry.LatestAvailable("FerramAerospaceResearch", new CKAN.KSPVersion("0.25.0")); Assert.AreEqual("v0.14.3.2", far.version.ToString()); }
public void SetUp() { _testModule = TestData.DogeCoinFlag_101_module(); _instance = new DisposableKSP(); _registry = CKAN.RegistryManager.Instance(_instance.KSP).registry; _installer = CKAN.ModuleInstaller.GetInstance(_instance.KSP, NullUser.User); _gameDataDir = _instance.KSP.GameData(); _registry.AddAvailable(_testModule); var testModFile = TestData.DogeCoinFlagZip(); _instance.KSP.Cache.Store(_testModule.download, testModFile); _installer.InstallList( new List <string>() { _testModule.identifier }, new RelationshipResolverOptions() ); }
public override bool WithinBounds(CkanModule otherModule) { return(otherModule.ProvidesList.Contains(name) && WithinBounds(otherModule.version)); }
public bool IsCached(CkanModule m) { return(cache.IsCached(m.download)); }
private void UpdateModInfo(GUIMod gui_module) { CkanModule module = gui_module.ToModule(); Util.Invoke(MetadataModuleNameTextBox, () => MetadataModuleNameTextBox.Text = module.name); UpdateTagsAndLabels(module); Util.Invoke(MetadataModuleAbstractLabel, () => MetadataModuleAbstractLabel.Text = module.@abstract); Util.Invoke(MetadataModuleDescriptionTextBox, () => { MetadataModuleDescriptionTextBox.Text = module.description ?.Replace("\r\n", "\n").Replace("\n", Environment.NewLine); MetadataModuleDescriptionTextBox.ScrollBars = string.IsNullOrWhiteSpace(module.description) ? ScrollBars.None : ScrollBars.Vertical; }); Util.Invoke(MetadataModuleVersionTextBox, () => MetadataModuleVersionTextBox.Text = gui_module.LatestVersion.ToString()); Util.Invoke(MetadataModuleLicenseTextBox, () => MetadataModuleLicenseTextBox.Text = string.Join(", ", module.license)); Util.Invoke(MetadataModuleAuthorTextBox, () => MetadataModuleAuthorTextBox.Text = gui_module.Authors); Util.Invoke(MetadataIdentifierTextBox, () => MetadataIdentifierTextBox.Text = module.identifier); Util.Invoke(MetadataModuleReleaseStatusTextBox, () => { if (module.release_status == null) { ReleaseLabel.Visible = false; MetadataModuleReleaseStatusTextBox.Visible = false; MetaDataLowerLayoutPanel.LayoutSettings.RowStyles[3].Height = 0; } else { ReleaseLabel.Visible = true; MetadataModuleReleaseStatusTextBox.Visible = true; MetaDataLowerLayoutPanel.LayoutSettings.RowStyles[3].Height = 30; MetadataModuleReleaseStatusTextBox.Text = module.release_status.ToString(); } }); Util.Invoke(MetadataModuleGameCompatibilityTextBox, () => MetadataModuleGameCompatibilityTextBox.Text = gui_module.GameCompatibilityLong); Util.Invoke(ModInfoTabControl, () => { // Mono doesn't draw TabPage.ImageIndex, so fake it const string fakeStopSign = "<!> "; ComponentResourceManager resources = new SingleAssemblyComponentResourceManager(typeof(ModInfo)); resources.ApplyResources(RelationshipTabPage, "RelationshipTabPage"); resources.ApplyResources(AllModVersionsTabPage, "AllModVersionsTabPage"); if (gui_module.IsIncompatible) { if (!module.IsCompatibleKSP(manager.CurrentInstance.VersionCriteria())) { AllModVersionsTabPage.Text = fakeStopSign + AllModVersionsTabPage.Text; } else { RelationshipTabPage.Text = fakeStopSign + RelationshipTabPage.Text; } } }); Util.Invoke(ReplacementTextBox, () => { if (module.replaced_by == null) { ReplacementLabel.Visible = false; ReplacementTextBox.Visible = false; MetaDataLowerLayoutPanel.LayoutSettings.RowStyles[6].Height = 0; } else { ReplacementLabel.Visible = true; ReplacementTextBox.Visible = true; MetaDataLowerLayoutPanel.LayoutSettings.RowStyles[6].Height = 30; ReplacementTextBox.Text = module.replaced_by.ToString(); } }); Util.Invoke(MetaDataLowerLayoutPanel, () => { ClearResourceLinks(); var res = module.resources; if (res != null) { AddResourceLink(Properties.Resources.ModInfoHomepageLabel, res.homepage); AddResourceLink(Properties.Resources.ModInfoSpaceDockLabel, res.spacedock); AddResourceLink(Properties.Resources.ModInfoCurseLabel, res.curse); AddResourceLink(Properties.Resources.ModInfoRepositoryLabel, res.repository); AddResourceLink(Properties.Resources.ModInfoBugTrackerLabel, res.bugtracker); AddResourceLink(Properties.Resources.ModInfoContinuousIntegrationLabel, res.ci); AddResourceLink(Properties.Resources.ModInfoLicenseLabel, res.license); AddResourceLink(Properties.Resources.ModInfoManualLabel, res.manual); AddResourceLink(Properties.Resources.ModInfoMetanetkanLabel, res.metanetkan); AddResourceLink(Properties.Resources.ModInfoRemoteAvcLabel, res.remoteAvc); AddResourceLink(Properties.Resources.ModInfoStoreLabel, res.store); AddResourceLink(Properties.Resources.ModInfoSteamStoreLabel, res.steamstore); } }); }
// this probably needs to be refactored private void InstallMods(object sender, DoWorkEventArgs e) { installCanceled = false; Wait.ClearLog(); var opts = (KeyValuePair <ModChanges, RelationshipResolverOptions>)e.Argument; RegistryManager registry_manager = RegistryManager.Instance(manager.CurrentInstance); Registry registry = registry_manager.registry; ModuleInstaller installer = ModuleInstaller.GetInstance(CurrentInstance, Manager.Cache, currentUser); // Avoid accumulating multiple event handlers installer.onReportModInstalled -= OnModInstalled; installer.onReportModInstalled += OnModInstalled; // setup progress callback // this will be the final list of mods we want to install HashSet <CkanModule> toInstall = new HashSet <CkanModule>(); 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); break; case GUIModChangeType.Replace: ModuleReplacement repl = registry.GetReplacement(change.Mod, CurrentInstance.VersionCriteria()); if (repl != null) { toUninstall.Add(repl.ToReplace.identifier); toInstall.Add(repl.ReplaceWith); } break; } } // Prompt for recommendations and suggestions, if any if (installer.FindRecommendations( opts.Key.Where(ch => ch.ChangeType == GUIModChangeType.Install) .Select(ch => ch.Mod) .ToHashSet(), toInstall, registry, out Dictionary <CkanModule, Tuple <bool, List <string> > > recommendations, out Dictionary <CkanModule, List <string> > suggestions, out Dictionary <CkanModule, HashSet <string> > supporters )) { tabController.ShowTab("ChooseRecommendedModsTabPage", 3); ChooseRecommendedMods.LoadRecommendations( registry, CurrentInstance.VersionCriteria(), Manager.Cache, recommendations, suggestions, supporters); tabController.SetTabLock(true); var result = ChooseRecommendedMods.Wait(); if (result == null) { installCanceled = true; } else { toInstall.UnionWith(result); } tabController.SetTabLock(false); tabController.HideTab("ChooseRecommendedModsTabPage"); } if (installCanceled) { tabController.ShowTab("ManageModsTabPage"); e.Result = new KeyValuePair <bool, ModChanges>(false, opts.Key); return; } // Now let's make all our changes. Util.Invoke(this, () => { // Need to be on the GUI thread to get the translated string tabController.RenameTab("WaitTabPage", Properties.Resources.MainInstallWaitTitle); }); ShowWaitDialog(); tabController.SetTabLock(true); IDownloader downloader = new NetAsyncModulesDownloader(currentUser, Manager.Cache); cancelCallback = () => { downloader.CancelDownload(); installCanceled = true; }; HashSet <string> possibleConfigOnlyDirs = null; // checks if all actions were successfull bool processSuccessful = false; bool resolvedAllProvidedMods = false; // uninstall/installs/upgrades until every list is empty // if the queue is NOT empty, resolvedAllProvidedMods is set to false until the action is done while (!resolvedAllProvidedMods) { try { e.Result = new KeyValuePair <bool, ModChanges>(false, opts.Key); if (toUninstall.Count > 0) { processSuccessful = false; if (!installCanceled) { installer.UninstallList(toUninstall, ref possibleConfigOnlyDirs, registry_manager, false, toInstall); processSuccessful = true; } } if (toUpgrade.Count > 0) { processSuccessful = false; if (!installCanceled) { installer.Upgrade(toUpgrade, downloader, ref possibleConfigOnlyDirs, registry_manager); processSuccessful = true; } } if (toInstall.Count > 0) { processSuccessful = false; if (!installCanceled) { installer.InstallList(toInstall, opts.Value, registry_manager, downloader, false); processSuccessful = true; } } HandlePossibleConfigOnlyDirs(registry, possibleConfigOnlyDirs); e.Result = new KeyValuePair <bool, ModChanges>(processSuccessful, opts.Key); if (installCanceled) { return; } resolvedAllProvidedMods = true; } catch (TooManyModsProvideKraken k) { // Prompt user to choose which mod to use tabController.ShowTab("ChooseProvidedModsTabPage", 3); ChooseProvidedMods.LoadProviders(k.requested, k.modules, Manager.Cache); tabController.SetTabLock(true); CkanModule chosen = ChooseProvidedMods.Wait(); // Close the selection prompt tabController.SetTabLock(false); tabController.HideTab("ChooseProvidedModsTabPage"); if (chosen != null) { // User picked a mod, queue it up for installation toInstall.Add(chosen); // DON'T return so we can loop around and try the above InstallList call again tabController.ShowTab("WaitTabPage"); } else { // User cancelled, get out tabController.ShowTab("ManageModsTabPage"); e.Result = new KeyValuePair <bool, ModChanges>(false, opts.Key); return; } } } }
private static CkanModule ProcessRegistryMetadataFromJSON(string metadata, string filename) { log.DebugFormat("Converting metadata from JSON."); try { CkanModule module = CkanModule.FromJson(metadata); // FromJson can return null for the empty string if (module != null) { log.DebugFormat("Found {0} version {1}", module.identifier, module.version); } return(module); } catch (Exception exception) { // Alas, we can get exceptions which *wrap* our exceptions, // because json.net seems to enjoy wrapping rather than propagating. // See KSP-CKAN/CKAN-meta#182 as to why we need to walk the whole // exception stack. bool handled = false; while (exception != null) { if (exception is UnsupportedKraken || exception is BadMetadataKraken) { // Either of these can be caused by data meant for future // clients, so they're not really warnings, they're just // informational. log.InfoFormat("Skipping {0} : {1}", filename, exception.Message); // I'd *love a way to "return" from the catch block. handled = true; break; } // Look further down the stack. exception = exception.InnerException; } // If we haven't handled our exception, then it really was exceptional. if (handled == false) { if (exception == null) { // Had exception, walked exception tree, reached leaf, got stuck. log.ErrorFormat("Error processing {0} (exception tree leaf)", filename); } else { // In case whatever's calling us is lazy in error reporting, we'll // report that we've got an issue here. log.ErrorFormat("Error processing {0} : {1}", filename, exception.Message); } throw; } return(null); } }
/// <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> public void InstallList(ICollection <CkanModule> modules, RelationshipResolverOptions options, IDownloader downloader = null) { // TODO: Break this up into smaller pieces! It's huge! var resolver = new RelationshipResolver(modules, options, registry_manager.registry, ksp.VersionCriteria()); var modsToInstall = resolver.ModList().ToList(); 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...\r\n"); foreach (CkanModule module in modsToInstall) { if (!ksp.Cache.IsMaybeCachedZip(module)) { User.RaiseMessage(" * {0} {1} ({2}, {3})", module.name, module.version, module.download.Host, CkanModule.FmtSize(module.download_size) ); downloads.Add(module); } else { User.RaiseMessage(" * {0} {1} (cached)", module.name, module.version); } } bool ok = User.RaiseYesNoDialog("\r\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 NetAsyncModulesDownloader(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("Committing 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!\r\n", 100); }
/// <summary> /// Removes the given module from the registry of available modules. /// Does *nothing* if the module was not present to begin with.</summary> public void RemoveAvailable(CkanModule module) { RemoveAvailable(module.identifier, module.version); }
/// <summary> /// Create a CkanModule object that represents the currently installed /// mod list as a metapackage. /// </summary> /// <param name="recommends">If true, put the mods in the recommends relationship, otherwise use depends</param> /// <param name="with_versions">If true, set the installed mod versions in the relationships</param> /// <returns> /// The CkanModule object /// </returns> public CkanModule GenerateModpack(bool recommends = false, bool with_versions = true) { string kspInstanceName = ksp.Name; string name = $"installed-{kspInstanceName}"; var module = new CkanModule( // v1.18 to allow Unlicense new ModuleVersion("v1.18"), Identifier.Sanitize(name), name, $"A list of modules installed on the {kspInstanceName} KSP instance", null, new List <string>() { System.Environment.UserName }, new List <License>() { new License("unknown") }, new ModuleVersion(DateTime.UtcNow.ToString("yyyy.MM.dd.hh.mm.ss")), null, "metapackage" ) { download_content_type = "application/zip", release_date = DateTime.Now, }; List <RelationshipDescriptor> mods = registry.Installed(false, false) .Where(kvp => { // Skip unavailable modules (custom .ckan files) try { var avail = registry.LatestAvailable(kvp.Key, null, null); return(!avail.IsDLC); } catch { return(false); } }) // Case insensitive sort by identifier .OrderBy(kvp => kvp.Key, StringComparer.OrdinalIgnoreCase) .Select(kvp => (RelationshipDescriptor) new ModuleRelationshipDescriptor() { name = kvp.Key, version = with_versions ? kvp.Value : null }) .ToList(); if (recommends) { module.recommends = mods; } else { module.depends = mods; } return(module); }
/// <summary> /// Initialize a GUIMod based on just an identifier /// </summary> /// <param name="identifier">The id of the module to represent</param> /// <param name="registry">CKAN registry object for current game instance</param> /// <param name="current_ksp_version">Current game version</param> /// <param name="incompatible">If true, mark this module as incompatible</param> public GUIMod(string identifier, IRegistryQuerier registry, KspVersionCriteria current_ksp_version, bool incompatible = false) { Identifier = identifier; IsIncompatible = incompatible; IsAutodetected = registry.IsAutodetected(identifier); DownloadCount = registry.DownloadCount(identifier); if (registry.IsAutodetected(identifier)) { IsInstalled = true; } ModuleVersion latest_version = null; try { latest_version = registry.LatestAvailable(identifier, current_ksp_version)?.version; } catch (ModuleNotFoundKraken) { } // Let's try to find the compatibility for this mod. If it's not in the registry at // all (because it's a DarkKAN mod) then this might fail. CkanModule latest_available_for_any_ksp = null; try { latest_available_for_any_ksp = registry.LatestAvailable(identifier, null); } catch { } // If there's known information for this mod in any form, calculate the highest compatible // KSP. if (latest_available_for_any_ksp != null) { KSPCompatibility = registry.LatestCompatibleKSP(identifier)?.ToYalovString() ?? "Unknown"; KSPCompatibilityLong = $"{KSPCompatibility} (using mod version {latest_available_for_any_ksp.version})"; } else { // No idea what this mod is, sorry! KSPCompatibility = KSPCompatibilityLong = "unknown"; } if (latest_version != null) { LatestVersion = latest_version.ToString(); } else if (latest_available_for_any_ksp != null) { LatestVersion = latest_available_for_any_ksp.version.ToString(); } else { LatestVersion = "-"; } // If we have a homepage provided, use that; otherwise use the spacedock page, curse page or the github repo so that users have somewhere to get more info than just the abstract. Homepage = "N/A"; SearchableIdentifier = CkanModule.nonAlphaNums.Replace(Identifier, ""); }
public void LoadProviders(string message, List <CkanModule> modules, NetModuleCache cache) { Util.Invoke(this, () => { ChooseProvidedModsLabel.Text = message; ChooseProvidedModsListView.Items.Clear(); ChooseProvidedModsListView.Items.AddRange(modules .Select(module => new ListViewItem(new string[] { cache.IsMaybeCachedZip(module) ? string.Format(Properties.Resources.MainChangesetCached, module.name, module.version) : string.Format(Properties.Resources.MainChangesetHostSize, module.name, module.version, module.download.Host ?? "", CkanModule.FmtSize(module.download_size)), module.@abstract }) { Tag = module, Checked = false }) .ToArray()); ChooseProvidedModsListView.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent); ChooseProvidedModsContinueButton.Enabled = false; }); }
/// <summary> /// This function returns a changeset based on the selections of the user. /// Currently returns null if a conflict is detected. /// </summary> /// <param name="registry"></param> /// <param name="changeSet"></param> /// <param name="installer">A module installer for the current KSP install</param> /// <param name="version">The version of the current KSP install</param> public async Task <IEnumerable <ModChange> > ComputeChangeSetFromModList( IRegistryQuerier registry, HashSet <ModChange> changeSet, ModuleInstaller installer, KspVersionCriteria version) { var modules_to_install = new HashSet <CkanModule>(); var modules_to_remove = new HashSet <CkanModule>(); foreach (var change in changeSet) { switch (change.ChangeType) { case GUIModChangeType.None: break; case GUIModChangeType.Update: case GUIModChangeType.Install: //TODO: Fix //This will give us a mod with a wrong version! modules_to_install.Add(change.Mod.ToCkanModule()); break; case GUIModChangeType.Remove: modules_to_remove.Add(change.Mod); break; case GUIModChangeType.Replace: ModuleReplacement repl = registry.GetReplacement(change.Mod.ToModule(), version); if (repl != null) { modules_to_remove.Add(repl.ToReplace); modules_to_install.Add(repl.ReplaceWith); } break; default: throw new ArgumentOutOfRangeException(); } } var installed_modules = registry.InstalledModules.Select(imod => imod.Module).ToDictionary(mod => mod.identifier, mod => mod); foreach (var dependency in registry.FindReverseDependencies( modules_to_remove .Select(mod => mod.identifier) .Except(modules_to_install.Select(m => m.identifier)) )) { //TODO This would be a good place to have a event that alters the row's graphics to show it will be removed CkanModule module_by_version = registry.GetModuleByVersion(installed_modules[dependency].identifier, installed_modules[dependency].version) ?? registry.InstalledModule(dependency).Module; changeSet.Add(new ModChange(new GUIMod(module_by_version, registry, version), GUIModChangeType.Remove, null)); modules_to_remove.Add(module_by_version); } foreach (var im in registry.FindRemovableAutoInstalled( registry.InstalledModules.Where(im => !modules_to_remove.Any(m => m.identifier == im.identifier)) )) { changeSet.Add(new ModChange(new GUIMod(im.Module, registry, version), GUIModChangeType.Remove, new SelectionReason.NoLongerUsed())); modules_to_remove.Add(im.Module); } bool handled_all_too_many_provides = false; while (!handled_all_too_many_provides) { //Can't await in catch clause - doesn't seem to work in mono. Hence this flag TooManyModsProvideKraken kraken; try { new RelationshipResolver( modules_to_install, modules_to_remove, RelationshipResolver.DependsOnlyOpts(), registry, version); handled_all_too_many_provides = true; continue; } catch (TooManyModsProvideKraken k) { kraken = k; } //Shouldn't get here unless there is a kraken. var mod = await too_many_provides(kraken); if (mod != null) { modules_to_install.Add(mod); } else { //TODO Is could be a new type of Kraken. throw kraken; } } var resolver = new RelationshipResolver( modules_to_install, modules_to_remove, RelationshipResolver.DependsOnlyOpts(), registry, version); changeSet.UnionWith( resolver.ModList() .Select(m => new ModChange(new GUIMod(m, registry, version), GUIModChangeType.Install, resolver.ReasonFor(m)))); return(changeSet); }
public static Dictionary <GUIMod, string> ComputeConflictsFromModList(IRegistryQuerier registry, IEnumerable <ModChange> change_set, KspVersionCriteria ksp_version) { var modules_to_install = new HashSet <string>(); var modules_to_remove = new HashSet <string>(); var options = new RelationshipResolverOptions { without_toomanyprovides_kraken = true, proceed_with_inconsistencies = true, without_enforce_consistency = true, with_recommends = false }; foreach (var change in change_set) { switch (change.ChangeType) { case GUIModChangeType.None: break; case GUIModChangeType.Install: modules_to_install.Add(change.Mod.Identifier); break; case GUIModChangeType.Remove: modules_to_remove.Add(change.Mod.Identifier); break; case GUIModChangeType.Update: break; case GUIModChangeType.Replace: ModuleReplacement repl = registry.GetReplacement(change.Mod.ToModule(), ksp_version); if (repl != null) { modules_to_remove.Add(repl.ToReplace.identifier); modules_to_install.Add(repl.ReplaceWith.identifier); } break; default: throw new ArgumentOutOfRangeException(); } } // Only check mods that would exist after the changes are made. IEnumerable <CkanModule> installed = registry.InstalledModules.Where( im => !modules_to_remove.Contains(im.Module.identifier) ).Select(im => im.Module); // Convert ONLY modules_to_install with CkanModule.FromIDandVersion, // because it may not find already-installed modules. IEnumerable <CkanModule> mods_to_check = installed.Union( modules_to_install.Except(modules_to_remove).Select( name => CkanModule.FromIDandVersion(registry, name, ksp_version) ) ); var resolver = new RelationshipResolver( mods_to_check, change_set.Where(ch => ch.ChangeType == GUIModChangeType.Remove) .Select(ch => ch.Mod.ToModule()), options, registry, ksp_version ); return(resolver.ConflictList.ToDictionary(item => new GUIMod(item.Key, registry, ksp_version), item => item.Value)); }
public InvalidModuleAttributesException(string why, CkanModule module = null) : base(why) { this.why = why; this.module = module; }
public void UpdateModContentsTree(CkanModule module, bool force = false) { ModInfo.UpdateModContentsTree(module, force); }
/// <summary> /// Returns the path to a cached copy of a module if it exists, or downloads /// and returns the downloaded copy otherwise. /// /// If no filename is provided, the module's standard name will be used. /// Chcecks the CKAN cache first. /// </summary> public string CachedOrDownload(CkanModule module, string filename = null) { return(CachedOrDownload(module, Cache, filename)); }
private void DeSerialisationFixes(StreamingContext context) { // Our context is our KSP install. KSP ksp = (KSP)context.Context; // Older registries didn't have the installed_files list, so we create one // if absent. if (installed_files == null) { log.Warn("Older registry format detected, adding installed files manifest..."); ReindexInstalled(); } // If we have no registry version at all, then we're from the pre-release period. // We would check for a null here, but ints *can't* be null. if (registry_version == 0) { log.Warn("Older registry format detected, normalising paths..."); var normalised_installed_files = new Dictionary <string, string>(); foreach (KeyValuePair <string, string> tuple in installed_files) { string path = KSPPathUtils.NormalizePath(tuple.Key); if (Path.IsPathRooted(path)) { path = ksp.ToRelativeGameDir(path); normalised_installed_files[path] = tuple.Value; } else { // Already relative. normalised_installed_files[path] = tuple.Value; } } installed_files = normalised_installed_files; // Now update all our module file manifests. foreach (InstalledModule module in installed_modules.Values) { module.Renormalise(ksp); } // Our installed dlls have contained relative paths since forever, // and the next `ckan scan` will fix them anyway. (We can't scan here, // because that needs a registry, and we chicken-egg.) log.Warn("Registry upgrade complete"); } // Fix control lock, which previously was indexed with an invalid identifier. if (registry_version < 2) { InstalledModule control_lock_entry; const string old_ident = "001ControlLock"; const string new_ident = "ControlLock"; if (installed_modules.TryGetValue("001ControlLock", out control_lock_entry)) { if (ksp == null) { throw new Kraken("Internal bug: No KSP instance provided on registry deserialisation"); } log.WarnFormat("Older registry detected. Reindexing {0} as {1}. This may take a moment.", old_ident, new_ident); // Remove old record. installed_modules.Remove(old_ident); // Extract the old module metadata CkanModule control_lock_mod = control_lock_entry.Module; // Change to the correct ident. control_lock_mod.identifier = new_ident; // Prepare to re-index. var new_control_lock_installed = new InstalledModule( ksp, control_lock_mod, control_lock_entry.Files ); // Re-insert into registry. installed_modules[new_control_lock_installed.identifier] = new_control_lock_installed; // Re-index files. ReindexInstalled(); } } // If we spot a default repo with the old .zip URL, flip it to the new .tar.gz URL // Any other repo we leave *as-is*, even if it's the github meta-repo, as it's been // custom-added by our user. Repository default_repo; var oldDefaultRepo = new Uri("https://github.com/KSP-CKAN/CKAN-meta/archive/master.zip"); if (repositories != null && repositories.TryGetValue(Repository.default_ckan_repo_name, out default_repo) && default_repo.uri == oldDefaultRepo) { log.InfoFormat("Updating default metadata URL from {0} to {1}", oldDefaultRepo, Repository.default_ckan_repo_uri); repositories["default"].uri = Repository.default_ckan_repo_uri; } registry_version = LATEST_REGISTRY_VERSION; }
/// <summary> /// Downloads the given mod to the cache. Returns the filename it was saved to. /// </summary> public string Download(CkanModule module, string filename) { User.RaiseProgress(String.Format("Downloading \"{0}\"", module.download), 0); return(Download(module, filename, Cache)); }
private string SerializeCurrentInstall(bool recommends = false, bool with_versions = true) { var pack = GenerateModpack(recommends, with_versions); return(CkanModule.ToJson(pack)); }
private void OnModInstalled(CkanModule mod) { AddStatusMessage(string.Format(Properties.Resources.MainInstallModSuccess, mod.name)); LabelsAfterInstall(mod); }
private void UpdateProvidedModsDialog(TooManyModsProvideKraken tooManyProvides, TaskCompletionSource <CkanModule> task) { toomany_source = task; ChooseProvidedModsLabel.Text = String.Format( Properties.Resources.MainInstallProvidedBy, tooManyProvides.requested ); ChooseProvidedModsListView.Items.Clear(); ChooseProvidedModsListView.ItemChecked += ChooseProvidedModsListView_ItemChecked; foreach (CkanModule module in tooManyProvides.modules) { ListViewItem item = new ListViewItem() { Tag = module, Checked = false, Text = Manager.Cache.IsMaybeCachedZip(module) ? string.Format(Properties.Resources.MainChangesetCached, module.name, module.version) : string.Format(Properties.Resources.MainChangesetHostSize, module.name, module.version, module.download.Host ?? "", CkanModule.FmtSize(module.download_size)) }; ListViewItem.ListViewSubItem description = new ListViewItem.ListViewSubItem() { Text = module.@abstract }; item.SubItems.Add(description); ChooseProvidedModsListView.Items.Add(item); } ChooseProvidedModsListView.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent); ChooseProvidedModsContinueButton.Enabled = false; }
private void OnModInstalled(CkanModule mod) { AddStatusMessage("Module \"{0}\" successfully installed", mod.name); }
// this probably needs to be refactored private void InstallMods(object sender, DoWorkEventArgs e) { installCanceled = false; Wait.ClearLog(); var opts = (KeyValuePair <ModChanges, RelationshipResolverOptions>)e.Argument; RegistryManager registry_manager = RegistryManager.Instance(manager.CurrentInstance); Registry registry = registry_manager.registry; ModuleInstaller installer = ModuleInstaller.GetInstance(CurrentInstance, Manager.Cache, currentUser); // Avoid accumulating multiple event handlers installer.onReportModInstalled -= OnModInstalled; installer.onReportModInstalled += OnModInstalled; // setup progress callback // this will be the final list of mods we want to install HashSet <CkanModule> toInstall = new HashSet <CkanModule>(); 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); break; case GUIModChangeType.Replace: ModuleReplacement repl = registry.GetReplacement(change.Mod, CurrentInstance.VersionCriteria()); if (repl != null) { toUninstall.Add(repl.ToReplace.identifier); toInstall.Add(repl.ReplaceWith); } break; } } // Prompt for recommendations and suggestions, if any if (installer.FindRecommendations( opts.Key.Where(ch => ch.ChangeType == GUIModChangeType.Install) .Select(ch => ch.Mod) .ToHashSet(), toInstall, registry, out Dictionary <CkanModule, Tuple <bool, List <string> > > recommendations, out Dictionary <CkanModule, List <string> > suggestions, out Dictionary <CkanModule, HashSet <string> > supporters )) { tabController.ShowTab("ChooseRecommendedModsTabPage", 3); ChooseRecommendedMods.LoadRecommendations(Manager.Cache, recommendations, suggestions, supporters); tabController.SetTabLock(true); var result = ChooseRecommendedMods.Wait(); if (result == null) { installCanceled = true; } else { toInstall.UnionWith(result); } tabController.SetTabLock(false); tabController.HideTab("ChooseRecommendedModsTabPage"); } if (installCanceled) { tabController.ShowTab("ManageModsTabPage"); e.Result = new KeyValuePair <bool, ModChanges>(false, opts.Key); return; } // Now let's make all our changes. tabController.RenameTab("WaitTabPage", Properties.Resources.MainInstallWaitTitle); ShowWaitDialog(); tabController.SetTabLock(true); IDownloader downloader = new NetAsyncModulesDownloader(currentUser, Manager.Cache); cancelCallback = () => { downloader.CancelDownload(); installCanceled = true; }; HashSet <string> possibleConfigOnlyDirs = null; // checks if all actions were successfull bool processSuccessful = false; bool resolvedAllProvidedMods = false; // uninstall/installs/upgrades until every list is empty // if the queue is NOT empty, resolvedAllProvidedMods is set to false until the action is done while (!resolvedAllProvidedMods) { try { e.Result = new KeyValuePair <bool, ModChanges>(false, opts.Key); if (toUninstall.Count > 0) { processSuccessful = false; if (!installCanceled) { installer.UninstallList(toUninstall, ref possibleConfigOnlyDirs, registry_manager, false, toInstall.Select(m => m.identifier)); processSuccessful = true; } } if (toUpgrade.Count > 0) { processSuccessful = false; if (!installCanceled) { installer.Upgrade(toUpgrade, downloader, ref possibleConfigOnlyDirs, registry_manager); processSuccessful = true; } } if (toInstall.Count > 0) { processSuccessful = false; if (!installCanceled) { installer.InstallList(toInstall, opts.Value, registry_manager, downloader, false); processSuccessful = true; } } HandlePossibleConfigOnlyDirs(registry, possibleConfigOnlyDirs); e.Result = new KeyValuePair <bool, ModChanges>(processSuccessful, opts.Key); if (installCanceled) { return; } resolvedAllProvidedMods = true; } catch (TooManyModsProvideKraken k) { // Prompt user to choose which mod to use CkanModule chosen = TooManyModsProvideCore(k); // Close the selection prompt tabController.HideTab("ChooseProvidedModsTabPage"); if (chosen != null) { // User picked a mod, queue it up for installation toInstall.Add(chosen); // DON'T return so we can loop around and try the above InstallList call again tabController.ShowTab("WaitTabPage"); } else { // User cancelled, get out tabController.ShowTab("ManageModsTabPage"); e.Result = new KeyValuePair <bool, ModChanges>(false, opts.Key); return; } } catch (DependencyNotSatisfiedKraken ex) { currentUser.RaiseMessage(Properties.Resources.MainInstallDepNotSatisfied, ex.parent, ex.module); return; } catch (ModuleNotFoundKraken ex) { currentUser.RaiseMessage(Properties.Resources.MainInstallNotFound, ex.module); return; } catch (BadMetadataKraken ex) { currentUser.RaiseMessage(Properties.Resources.MainInstallBadMetadata, ex.module, ex.Message); return; } catch (FileExistsKraken ex) { if (ex.owningModule != null) { currentUser.RaiseMessage( Properties.Resources.MainInstallFileExists, ex.filename, ex.installingModule, ex.owningModule, Meta.GetVersion() ); } else { currentUser.RaiseMessage( Properties.Resources.MainInstallUnownedFileExists, ex.installingModule, ex.filename ); } currentUser.RaiseMessage(Properties.Resources.MainInstallGameDataReverted); return; } catch (InconsistentKraken ex) { // The prettiest Kraken formats itself for us. currentUser.RaiseMessage(ex.InconsistenciesPretty); return; } catch (CancelledActionKraken) { return; } catch (MissingCertificateKraken kraken) { // Another very pretty kraken. currentUser.RaiseMessage(kraken.ToString()); return; } catch (DownloadThrottledKraken kraken) { string msg = kraken.ToString(); currentUser.RaiseMessage(msg); if (YesNoDialog(string.Format(Properties.Resources.MainInstallOpenSettingsPrompt, msg), Properties.Resources.MainInstallOpenSettings, Properties.Resources.MainInstallNo)) { // Launch the URL describing this host's throttling practices, if any if (kraken.infoUrl != null) { Utilities.ProcessStartURL(kraken.infoUrl.ToString()); } // Now pretend they clicked the menu option for the settings Enabled = false; new SettingsDialog(currentUser).ShowDialog(); Enabled = true; } return; } catch (ModuleDownloadErrorsKraken kraken) { currentUser.RaiseMessage(kraken.ToString()); currentUser.RaiseError(kraken.ToString()); return; } catch (DirectoryNotFoundKraken kraken) { currentUser.RaiseMessage("\r\n{0}", kraken.Message); return; } catch (DllNotFoundException) { if (currentUser.RaiseYesNoDialog(Properties.Resources.MainInstallLibCurlMissing)) { Utilities.ProcessStartURL("https://github.com/KSP-CKAN/CKAN/wiki/libcurl"); } throw; } } }
private TreeNode UpdateModDependencyGraphRecursively(TreeNode parentNode, CkanModule module, RelationshipType relationship, int depth, bool virtualProvides = false) { if (module == null || (depth > 0 && dependencyGraphRootModule == module) || (alreadyVisited.Contains(module))) { return(null); } alreadyVisited.Add(module); string nodeText = module.name; if (virtualProvides) { nodeText = String.Format("provided by - {0}", module.name); } var node = parentNode == null ? new TreeNode(nodeText) : parentNode.Nodes.Add(nodeText); node.Name = module.name; IEnumerable <RelationshipDescriptor> relationships = null; switch (relationship) { case RelationshipType.Depends: relationships = module.depends; break; case RelationshipType.Recommends: relationships = module.recommends; break; case RelationshipType.Suggests: relationships = module.suggests; break; case RelationshipType.Supports: relationships = module.supports; break; case RelationshipType.Conflicts: relationships = module.conflicts; break; } if (relationships == null) { return(node); } foreach (RelationshipDescriptor dependency in relationships) { IRegistryQuerier registry = RegistryManager.Instance(manager.CurrentInstance).registry; try { try { var dependencyModule = registry.LatestAvailable (dependency.name, manager.CurrentInstance.Version()); UpdateModDependencyGraphRecursively(node, dependencyModule, relationship, depth + 1); } catch (ModuleNotFoundKraken) { List <CkanModule> dependencyModules = registry.LatestAvailableWithProvides (dependency.name, manager.CurrentInstance.Version()); if (dependencyModules == null) { continue; } var newNode = node.Nodes.Add(dependency.name + " (virtual)"); newNode.ForeColor = Color.Gray; foreach (var dep in dependencyModules) { UpdateModDependencyGraphRecursively(newNode, dep, relationship, depth + 1, true); } } } catch (Exception) { } } if (virtualProvides) { node.Collapse(true); } else { node.ExpandAll(); } return(node); }
public BadMetadataKraken(CkanModule module, string reason = null, Exception innerException = null) : base(reason, innerException) { this.module = module; }
public bool IsCached(CkanModule m, out string outFilename) { return(cache.IsCached(m.download, out outFilename)); }
/// <summary> /// Release the kraken /// </summary> /// <param name="module">Module to check against path</param> /// <param name="Path">Path to the file to check against module</param> /// <param name="reason">Human-readable description of the problem</param> public InvalidModuleFileKraken(CkanModule module, string path, string reason = null) : base(reason) { this.module = module; this.path = path; }
public ModuleIsDLCKraken(CkanModule module, string reason = null) : base(reason) { this.module = module; }
public abstract bool WithinBounds(CkanModule otherModule);