public void SetUp() { _testModule = TestData.DogeCoinFlag_101_module(); _instance = new DisposableKSP(); _nullUser = new NullUser(); _config = new FakeConfiguration(_instance.KSP, _instance.KSP.Name); _manager = new GameInstanceManager(_nullUser, _config); _registryManager = CKAN.RegistryManager.Instance(_instance.KSP); _registry = _registryManager.registry; _installer = CKAN.ModuleInstaller.GetInstance(_instance.KSP, _manager.Cache, _nullUser); _gameDir = _instance.KSP.GameDir(); _gameDataDir = _instance.KSP.game.PrimaryModDirectory(_instance.KSP); _registry.AddAvailable(_testModule); var testModFile = TestData.DogeCoinFlagZip(); _manager.Cache.Store(_testModule, testModFile); HashSet <string> possibleConfigOnlyDirs = null; _installer.InstallList( new List <string>() { _testModule.identifier }, new RelationshipResolverOptions(), _registryManager, ref possibleConfigOnlyDirs ); }
public void SetUp() { _testModule = TestData.DogeCoinFlag_101_module(); _nullUser = new NullUser(); _manager = new KSPManager(_nullUser); _instance = new DisposableKSP(); _registryManager = CKAN.RegistryManager.Instance(_instance.KSP); _registry = _registryManager.registry; _installer = CKAN.ModuleInstaller.GetInstance(_instance.KSP, _manager.Cache, _nullUser); _gameDataDir = _instance.KSP.GameData(); _registry.AddAvailable(_testModule); var testModFile = TestData.DogeCoinFlagZip(); _manager.Cache.Store(_testModule, testModFile); _installer.InstallList( new List <string>() { _testModule.identifier }, new RelationshipResolverOptions(), _registryManager ); }
public void Setup() { ksp = new DisposableKSP(); registry = CKAN.RegistryManager.Instance(ksp.KSP).registry; registry.ClearAvailable(); registry.ClearDlls(); registry.Installed().Clear(); }
public void Setup() { // Make a fake KSP install temp_ksp = new DisposableKSP(null, test_registry); // Easy short-cut registry = temp_ksp.KSP.Registry; }
public void Setup() { registry = CKAN.Registry.Empty(); options = RelationshipResolver.DefaultOpts(); generator = new RandomModuleGenerator(new Random(0451)); //Sanity checker means even incorrect RelationshipResolver logic was passing options.without_enforce_consistency = true; }
public void Setup() { ksp = new DisposableKSP(); registry = ksp.KSP.Registry; registry.ClearAvailable(); registry.ClearDlls(); registry.Installed().Clear(); }
public void Constructor_WithoutModules_AlwaysReturns() { registry = CKAN.Registry.Empty(); options = RelationshipResolver.DefaultOpts(); Assert.DoesNotThrow(() => new RelationshipResolver(new List <string>(), options, registry, null)); }
public void Setup() { ksp = new DisposableKSP(); registry = ksp.KSP.Registry; registry.ClearAvailable(); registry.ClearPreexistingModules(); registry.Installed().Clear(); }
public void Constructor_WithoutModules_AlwaysReturns() { registry = CKAN.Registry.Empty(); options = RelationshipResolver.DefaultOpts(); Assert.DoesNotThrow(() => new RelationshipResolver(new List<string>(), options, registry, null)); }
/// <summary> /// Attempts to convert the module_names to ckan modules via CkanModule.FromIDandVersion and then calls RelationshipResolver.ctor(IEnumerable{CkanModule}, Registry, KSPVersion)"/> /// </summary> /// <param name="module_names"></param> /// <param name="options"></param> /// <param name="registry"></param> /// <param name="kspversion"></param> public RelationshipResolver(IEnumerable<string> module_names, RelationshipResolverOptions options, Registry registry, KSPVersion kspversion) : this(module_names.Select(name => CkanModule.FromIDandVersion(registry, name, kspversion)).ToList(), options, registry, kspversion) { // Does nothing, just calls the other overloaded constructor }
internal static void ProcessRegistryMetadataFromJSON(string metadata, Registry registry, string filename) { log.DebugFormat("Converting metadata from JSON."); try { CkanModule module = CkanModule.FromJson(metadata); log.InfoFormat("Found {0} version {1}", module.identifier, module.version); registry.AddAvailable(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; } } }
public void Setup() { ksp = new DisposableKSP(); manager = CKAN.RegistryManager.Instance(ksp.KSP); registry = manager.registry; registry.ClearDlls(); registry.Installed().Clear(); CKAN.Repo.Update(manager, ksp.KSP, new NullUser(), TestData.TestKANZip()); }
public void Setup() { ksp = new DisposableKSP(); registry = ksp.KSP.Registry; registry.ClearAvailable(); registry.ClearPreexistingModules(); registry.Installed().Clear(); Repo.UpdateRegistry(TestData.TestKANTarGz(), registry, ksp.KSP, new NullUser()); }
public void Setup() { ksp = new DisposableKSP(); registry = ksp.KSP.Registry; registry.ClearAvailable(); registry.ClearDlls(); registry.Installed().Clear(); CKAN.Repo.UpdateRegistry(TestData.TestKAN(), registry, ksp.KSP, new NullUser()); }
public void Setup() { ksp = new DisposableKSP(); registry = ksp.KSP.Registry; registry.ClearAvailable(); registry.ClearDlls(); registry.Installed().Clear(); Repo.UpdateRegistry(TestData.TestKANZip(), registry, ksp.KSP, new NullUser()); }
/// <summary> /// Creates a new Relationship resolver. /// </summary> /// <param name="options"><see cref="RelationshipResolverOptions"/></param> /// <param name="registry">The registry to use</param> /// <param name="kspversion">The version of the install that the registry corresponds to</param> public RelationshipResolver(RelationshipResolverOptions options, Registry registry, KSPVersion kspversion) { this.registry = registry; this.kspversion = kspversion; this.options = options; installed_modules = new HashSet<Module>(registry.InstalledModules.Select(i_module => i_module.Module)); var installed_relationship = new SelectionReason.Installed(); foreach (var module in installed_modules) { reasons.Add(module, installed_relationship); } }
public void EnforceSizeLimit_OverLimit_FileRemoved() { // Arrange CKAN.Registry registry = CKAN.Registry.Empty(); long fileSize = new FileInfo(TestData.DogeCoinFlagZip()).Length; // Act Uri url = new Uri("http://kitte.nz/"); cache.Store(url, TestData.DogeCoinFlagZip()); cache.EnforceSizeLimit(fileSize - 100, registry); // Assert Assert.IsFalse(cache.IsCached(url)); }
public void Setup() { manager = new KSPManager(new NullUser()); // Give us a registry to play with. ksp = new DisposableKSP(); registry_manager = CKAN.RegistryManager.Instance(ksp.KSP); registry = registry_manager.registry; registry.ClearDlls(); registry.Installed().Clear(); // Make sure we have a registry we can use. CKAN.Repo.Update(registry_manager, ksp.KSP, new NullUser(), TestData.TestKANZip()); // Ready our downloader. async = new CKAN.NetAsyncModulesDownloader(new NullUser(), manager.Cache); // General shortcuts cache = manager.Cache; }
public void Setup() { // Make sure curl is all set up. Curl.Init(); // Give us a registry to play with. ksp = new DisposableKSP(); registry = CKAN.RegistryManager.Instance(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.NetAsyncModulesDownloader(new NullUser()); // General shortcuts cache = ksp.KSP.Cache; }
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.NetAsyncModulesDownloader(new NullUser()); // General shortcuts cache = ksp.KSP.Cache; }
public void Setup() { // Provide an empty registry before each test. registry = CKAN.Registry.Empty(); Assert.IsNotNull(registry); }
public void Empty() { CKAN.Registry registry = CKAN.Registry.Empty(); Assert.IsInstanceOf <CKAN.Registry>(registry); }
/// <summary> /// Updates the supplied registry from the supplied zip file. /// This will *clear* the registry of available modules first. /// This does not *save* the registry. For that, you probably want Repo.Update /// </summary> internal static void UpdateRegistryFromTarGz(string path, Registry registry) { log.DebugFormat("Starting registry update from tar.gz file: \"{0}\".", path); // Open the gzip'ed file. using (Stream inputStream = File.OpenRead(path)) { // Create a gzip stream. using (GZipInputStream gzipStream = new GZipInputStream(inputStream)) { // Create a handle for the tar stream. using (TarInputStream tarStream = new TarInputStream(gzipStream)) { // Walk the archive, looking for .ckan files. const string filter = @"\.ckan$"; while (true) { TarEntry entry = tarStream.GetNextEntry(); // Check for EOF. if (entry == null) { break; } string filename = entry.Name; // Skip things we don't want. if (!Regex.IsMatch(filename, filter)) { log.DebugFormat("Skipping archive entry {0}", filename); continue; } log.DebugFormat("Reading CKAN data from {0}", filename); // Read each file into a buffer. int buffer_size; try { buffer_size = Convert.ToInt32(entry.Size); } catch (OverflowException) { log.ErrorFormat("Error processing {0}: Metadata size too large.", entry.Name); continue; } byte[] buffer = new byte[buffer_size]; tarStream.Read(buffer, 0, buffer_size); // Convert the buffer data to a string. string metadata_json = Encoding.ASCII.GetString(buffer); ProcessRegistryMetadataFromJSON(metadata_json, registry, filename); } } } } }
/// <summary> /// Updates the supplied registry from the supplied zip file. /// This will *clear* the registry of available modules first. /// This does not *save* the registry. For that, you probably want Repo.Update /// </summary> internal static void UpdateRegistryFromZip(string path, Registry registry) { log.DebugFormat("Starting registry update from zip file: \"{0}\".", path); using (var zipfile = new ZipFile(path)) { // Walk the archive, looking for .ckan files. const string filter = @"\.ckan$"; foreach (ZipEntry entry in zipfile) { string filename = entry.Name; // Skip things we don't want. if (! Regex.IsMatch(filename, filter)) { log.DebugFormat("Skipping archive entry {0}", filename); continue; } log.DebugFormat("Reading CKAN data from {0}", filename); // Read each file into a string. string metadata_json; using (var stream = new StreamReader(zipfile.GetInputStream(entry))) { metadata_json = stream.ReadToEnd(); stream.Close(); } ProcessRegistryMetadataFromJSON(metadata_json, registry, filename); } zipfile.Close(); } }
/// <summary> /// Creates a new resolver that will find a way to install all the modules specified. /// </summary> public RelationshipResolver(IEnumerable<CkanModule> modules, RelationshipResolverOptions options, Registry registry, KSPVersion kspversion) : this(options,registry,kspversion) { AddModulesToInstall(modules); }
/// <summary> /// Updates the supplied registry from the URL given. /// This does not *save* the registry. For that, you probably want Repo.Update /// </summary> internal static void UpdateRegistry(Uri repo, Registry registry, KSP ksp, IUser user, Boolean clear = true) { log.InfoFormat("Downloading {0}", repo); string repo_file = Net.Download(repo); // Clear our list of known modules. var old_available = registry.available_modules; if (clear) { registry.ClearAvailable(); } // Check the filetype. FileType type = FileIdentifier.IdentifyFile(repo_file); switch (type) { case FileType.TarGz: UpdateRegistryFromTarGz(repo_file, registry); break; case FileType.Zip: UpdateRegistryFromZip(repo_file, registry); break; default: break; } List <CkanModule> metadataChanges = new List <CkanModule>(); foreach (var identifierModulePair in old_available) { var identifier = identifierModulePair.Key; if (registry.IsInstalled(identifier)) { var installedVersion = registry.InstalledVersion(identifier); if (!(registry.available_modules.ContainsKey(identifier))) { log.InfoFormat("UpdateRegistry, module {0}, version {1} not in repository ({2})", identifier, installedVersion, repo); continue; } if (!registry.available_modules[identifier].module_version.ContainsKey(installedVersion)) { continue; } // if the mod is installed and the metadata is different we have to reinstall it var metadata = registry.available_modules[identifier].module_version[installedVersion]; if (!old_available.ContainsKey(identifier) || !old_available[identifier].module_version.ContainsKey(installedVersion)) { continue; } var oldMetadata = old_available[identifier].module_version[installedVersion]; bool same = true; if ((metadata.install == null) != (oldMetadata.install == null) || (metadata.install != null && metadata.install.Length != oldMetadata.install.Length)) { same = false; } else { if (metadata.install != null) { for (int i = 0; i < metadata.install.Length; i++) { if (metadata.install[i].file != oldMetadata.install[i].file) { same = false; break; } if (metadata.install[i].install_to != oldMetadata.install[i].install_to) { same = false; break; } if ((metadata.install[i].filter == null) != (oldMetadata.install[i].filter == null)) { same = false; break; } if (metadata.install[i].filter != null) { if (!metadata.install[i].filter.SequenceEqual(oldMetadata.install[i].filter)) { same = false; break; } } if ((metadata.install[i].filter_regexp == null) != (oldMetadata.install[i].filter_regexp == null)) { same = false; break; } if (metadata.install[i].filter_regexp != null) { if (!metadata.install[i].filter_regexp.SequenceEqual(oldMetadata.install[i].filter_regexp)) { same = false; break; } } } } } if (!same) { metadataChanges.Add(registry.available_modules[identifier].module_version[installedVersion]); } } } if (metadataChanges.Any()) { string mods = ""; for (int i = 0; i < metadataChanges.Count; i++) { mods += metadataChanges[i].identifier + " " + metadataChanges[i].version.ToString() + ((i < metadataChanges.Count - 1) ? ", " : ""); } if (user.RaiseYesNoDialog(String.Format( @"The following mods have had their metadata changed since last update - {0}. It is advisable that you reinstall them in order to preserve consistency with the repository. Do you wish to reinstall now?", mods))) { ModuleInstaller installer = ModuleInstaller.GetInstance(ksp, new NullUser()); installer.Upgrade(metadataChanges, new NetAsyncDownloader(new NullUser())); } } // Remove our downloaded meta-data now we've processed it. // Seems weird to do this as part of a transaction, but Net.Download uses them, so let's be consistent. file_transaction.Delete(repo_file); }
/// <summary> /// Updates the supplied registry from the URL given. /// This does not *save* the registry. For that, you probably want Repo.Update /// </summary> internal static void UpdateRegistry(Uri repo, Registry registry, KSP ksp, IUser user, Boolean clear = true) { // Use this opportunity to also update the build mappings... kind of hacky ServiceLocator.Container.Resolve<IKspBuildMap>().Refresh(); log.InfoFormat("Downloading {0}", repo); string repo_file = String.Empty; try { repo_file = Net.Download(repo); } catch (System.Net.WebException) { user.RaiseMessage("Connection to {0} could not be established.", repo); return; } // Clear our list of known modules. if (clear) { registry.ClearAvailable(); } // Check the filetype. FileType type = FileIdentifier.IdentifyFile(repo_file); switch (type) { case FileType.TarGz: UpdateRegistryFromTarGz (repo_file, registry); break; case FileType.Zip: UpdateRegistryFromZip (repo_file, registry); break; default: break; } List<CkanModule> metadataChanges = new List<CkanModule>(); foreach (var installedModule in registry.InstalledModules) { var identifier = installedModule.identifier; var installedVersion = registry.InstalledVersion(identifier); if (!(registry.available_modules.ContainsKey(identifier))) { log.InfoFormat("UpdateRegistry, module {0}, version {1} not in repository ({2})", identifier, installedVersion, repo); continue; } if (!registry.available_modules[identifier].module_version.ContainsKey(installedVersion)) { continue; } // if the mod is installed and the metadata is different we have to reinstall it var metadata = registry.available_modules[identifier].module_version[installedVersion]; var oldMetadata = registry.InstalledModule(identifier).Module; bool same = true; if ((metadata.install == null) != (oldMetadata.install == null) || (metadata.install != null && metadata.install.Length != oldMetadata.install.Length)) { same = false; } else { if(metadata.install != null) for (int i = 0; i < metadata.install.Length; i++) { if (metadata.install[i].file != oldMetadata.install[i].file) { same = false; break; } if (metadata.install[i].install_to != oldMetadata.install[i].install_to) { same = false; break; } if (metadata.install[i].@as != oldMetadata.install[i].@as) { same = false; break; } if ((metadata.install[i].filter == null) != (oldMetadata.install[i].filter == null)) { same = false; break; } if(metadata.install[i].filter != null) if (!metadata.install[i].filter.SequenceEqual(oldMetadata.install[i].filter)) { same = false; break; } if ((metadata.install[i].filter_regexp == null) != (oldMetadata.install[i].filter_regexp == null)) { same = false; break; } if(metadata.install[i].filter_regexp != null) if (!metadata.install[i].filter_regexp.SequenceEqual(oldMetadata.install[i].filter_regexp)) { same = false; break; } } } if (!RelationshipsAreEquivalent(metadata.conflicts, oldMetadata.conflicts)) same = false; if (!RelationshipsAreEquivalent(metadata.depends, oldMetadata.depends)) same = false; if (!RelationshipsAreEquivalent(metadata.recommends, oldMetadata.recommends)) same = false; if (metadata.provides != oldMetadata.provides) { if (metadata.provides == null || oldMetadata.provides == null) same = false; else if (!metadata.provides.OrderBy(i => i).SequenceEqual(oldMetadata.provides.OrderBy(i => i))) same = false; } if (!same) { metadataChanges.Add(registry.available_modules[identifier].module_version[installedVersion]); } } if (metadataChanges.Any()) { var sb = new StringBuilder(); for (var i = 0; i < metadataChanges.Count; i++) { var module = metadataChanges[i]; sb.AppendLine(string.Format("- {0} {1}", module.identifier, module.version)); } if(user.RaiseYesNoDialog(string.Format(@"The following mods have had their metadata changed since last update: {0} You should reinstall them in order to preserve consistency with the repository. Do you wish to reinstall now?", sb))) { ModuleInstaller installer = ModuleInstaller.GetInstance(ksp, new NullUser()); // New upstream metadata may break the consistency of already installed modules // e.g. if user installs modules A and B and then later up A is made to conflict with B // This is perfectly normal and shouldn't produce an error, therefore we skip enforcing // consistency. However, we will show the user any inconsistencies later on. // Use the identifiers so we use the overload that actually resolves relationships // Do each changed module one at a time so a failure of one doesn't cause all the others to fail foreach (var changedIdentifier in metadataChanges.Select(i => i.identifier)) { try { installer.Upgrade( new[] { changedIdentifier }, new NetAsyncModulesDownloader(new NullUser()), enforceConsistency: false ); } // Thrown when a dependency couldn't be satisfied catch(ModuleNotFoundKraken) { log.WarnFormat("Skipping installation of {0} due to relationship error.", changedIdentifier); user.RaiseMessage("Skipping installation of {0} due to relationship error.", changedIdentifier); } // Thrown when a conflicts relationship is violated catch (InconsistentKraken) { log.WarnFormat("Skipping installation of {0} due to relationship error.", changedIdentifier); user.RaiseMessage("Skipping installation of {0} due to relationship error.", changedIdentifier); } } } } // Remove our downloaded meta-data now we've processed it. // Seems weird to do this as part of a transaction, but Net.Download uses them, so let's be consistent. file_transaction.Delete(repo_file); }
private async Task UpdateChangeSetAndConflicts(Registry registry) { IEnumerable<KeyValuePair<GUIMod, GUIModChangeType>> full_change_set = null; Dictionary<GUIMod, string> new_conflicts = null; bool too_many_provides_thrown = false; var user_change_set = mainModList.ComputeUserChangeSet(); try { var module_installer = ModuleInstaller.GetInstance(CurrentInstance, GUI.user); full_change_set = await mainModList.ComputeChangeSetFromModList(registry, user_change_set, module_installer, CurrentInstance.Version()); } catch (InconsistentKraken) { //Need to be recomputed due to ComputeChangeSetFromModList possibly changing it with too many provides handling. user_change_set = mainModList.ComputeUserChangeSet(); new_conflicts = MainModList.ComputeConflictsFromModList(registry, user_change_set, CurrentInstance.Version()); full_change_set = null; } catch (TooManyModsProvideKraken) { //Can be thrown by ComputeChangeSetFromModList if the user cancels out of it. //We can just rerun it as the ModInfoTabControl has been removed. too_many_provides_thrown = true; } if (too_many_provides_thrown) { await UpdateChangeSetAndConflicts(registry); new_conflicts = Conflicts; full_change_set = ChangeSet; } last_mod_to_have_install_toggled.Clear(); Conflicts = new_conflicts; ChangeSet = full_change_set; }
public void Up() { _instance = new DisposableKSP(); _registry = Registry.Empty(); _manager = new KSPManager(new NullUser(), new FakeWin32Registry(_instance.KSP)); // this module contains a ksp_version of "any" which repros our issue _anyVersionModule = TestData.DogeCoinFlag_101_module(); // install it and set it as pre-installed _instance.KSP.Cache.Store(TestData.DogeCoinFlag_101_module().download, TestData.DogeCoinFlagZip()); _registry.RegisterModule(_anyVersionModule, new string[] { }, _instance.KSP); _registry.AddAvailable(_anyVersionModule); ModuleInstaller.GetInstance(_instance.KSP, _manager.User).InstallList( new List<CkanModule> { { _anyVersionModule } }, new RelationshipResolverOptions(), new NetAsyncModulesDownloader(_manager.User) ); // this module is not for "any" version, to provide another to sort against _registry.AddAvailable(TestData.kOS_014_module()); // test object _modList = new MainModList(null, null, _manager.User); _listGui = new MainModListGUI(); // todo: refactor the column header code to allow mocking of the GUI without creating columns _listGui.Columns.Add(new DataGridViewCheckBoxColumn()); _listGui.Columns.Add(new DataGridViewCheckBoxColumn()); for (int i = 0; i < 10; i++) { _listGui.Columns.Add(i.ToString(), "Column" + i); } }
// 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 = new ModuleInstaller(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 <CkanModule>(); var toUpgrade = new HashSet <CkanModule>(); // 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); break; case GUIModChangeType.Update: toUpgrade.Add(change is ModUpgrade mu ? mu.targetMod : change.Mod); 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); 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, toInstall, toUninstall, 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) { Util.Invoke(this, () => Enabled = true); Util.Invoke(menuStrip1, () => menuStrip1.Enabled = true); 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); downloader.Progress += Wait.SetModuleProgress; downloader.AllComplete += Wait.DownloadsComplete; 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.Select(m => m.identifier), ref possibleConfigOnlyDirs, registry_manager, false, toInstall); processSuccessful = true; } } if (toInstall.Count > 0) { processSuccessful = false; if (!installCanceled) { installer.InstallList(toInstall, opts.Value, registry_manager, ref possibleConfigOnlyDirs, downloader, false); processSuccessful = true; } } if (toUpgrade.Count > 0) { processSuccessful = false; if (!installCanceled) { installer.Upgrade(toUpgrade, downloader, ref possibleConfigOnlyDirs, registry_manager, true, true, 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"); Util.Invoke(this, () => Enabled = true); Util.Invoke(menuStrip1, () => menuStrip1.Enabled = true); e.Result = new KeyValuePair <bool, ModChanges>(false, opts.Key); return; } } } }
/// <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<KeyValuePair<GUIMod, GUIModChangeType>>> ComputeChangeSetFromModList( Registry registry, HashSet<KeyValuePair<GUIMod, GUIModChangeType>> changeSet, ModuleInstaller installer, KSPVersion version) { var modules_to_install = new HashSet<CkanModule>(); var modules_to_remove = new HashSet<Module>(); var options = new RelationshipResolverOptions { without_toomanyprovides_kraken = false, with_recommends = false }; foreach (var change in changeSet) { switch (change.Value) { case GUIModChangeType.None: break; case GUIModChangeType.Install: modules_to_install.Add(change.Key.ToCkanModule()); break; case GUIModChangeType.Remove: modules_to_remove.Add(change.Key); break; case GUIModChangeType.Update: break; default: throw new ArgumentOutOfRangeException(); } } var installed_modules = registry.InstalledModules.Select(imod => imod.Module).ToDictionary(mod => mod.identifier, mod => mod); bool handled_all_to_many_provides = false; while (!handled_all_to_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.ToList(), options, registry, version); handled_all_to_many_provides = true; continue; } catch (TooManyModsProvideKraken k) { kraken = k; } catch (ModuleNotFoundKraken k) { //We shouldn't need this. However the relationship provider will throw TMPs with incompatible mods. user.RaiseError("Module {0} has not been found. This may be because it is not compatible " + "with the currently installed version of KSP", k.module); return null; } //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; } } foreach (var dependency in modules_to_remove. Select(mod => installer.FindReverseDependencies(mod.identifier)). SelectMany(reverse_dependencies => reverse_dependencies)) { //TODO This would be a good place to have a event that alters the row's graphics to show it will be removed Module module_by_version = registry.GetModuleByVersion(installed_modules[dependency].identifier, installed_modules[dependency].version) ?? registry.InstalledModule(dependency).Module; changeSet.Add( new KeyValuePair<GUIMod, GUIModChangeType>( new GUIMod(module_by_version, registry, version), GUIModChangeType.Remove)); } //May throw InconsistentKraken var resolver = new RelationshipResolver(options, registry, version); resolver.RemoveModsFromInstalledList( changeSet.Where(change => change.Value.Equals(GUIModChangeType.Remove)).Select(m => m.Key.ToModule())); resolver.AddModulesToInstall(modules_to_install.ToList()); changeSet.UnionWith( resolver.ModList() .Select( mod => new KeyValuePair<GUIMod, GUIModChangeType>(new GUIMod(mod, registry, version), GUIModChangeType.Install))); return changeSet; }
public void Setup() { registry = CKAN.Registry.Empty(); CKAN.Repo.UpdateRegistry(TestData.TestKAN(), registry); }
// 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. 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 void Load() { // Our registry needs to know our KSP install when upgrading from older // registry formats. This lets us encapsulate that to make it available // after deserialisation. var settings = new JsonSerializerSettings { Context = new System.Runtime.Serialization.StreamingContext( System.Runtime.Serialization.StreamingContextStates.Other, ksp ) }; string json = File.ReadAllText(path); registry = JsonConvert.DeserializeObject<Registry>(json, settings); log.DebugFormat("Loaded CKAN registry at {0}", path); }
private static void ShowUserInconsistencies(Registry registry, IUser user) { // However, if there are any sanity errors let's show them to the user so at least they're aware var sanityErrors = registry.GetSanityErrors(); if (sanityErrors.Any()) { var sanityMessage = new StringBuilder(); sanityMessage.AppendLine("The following inconsistencies were found:"); foreach (var sanityError in sanityErrors) { sanityMessage.Append("- "); sanityMessage.AppendLine(sanityError); } user.RaiseMessage(sanityMessage.ToString()); } }
/// <summary> /// Updates the supplied registry from the URL given. /// This does not *save* the registry. For that, you probably want Repo.Update /// </summary> internal static void UpdateRegistry(Uri repo, Registry registry, KSP ksp, IUser user, Boolean clear = true) { log.InfoFormat("Downloading {0}", repo); string repo_file = Net.Download(repo); // Clear our list of known modules. var old_available = registry.available_modules; if (clear) { registry.ClearAvailable(); } // Check the filetype. FileType type = FileIdentifier.IdentifyFile(repo_file); switch (type) { case FileType.TarGz: UpdateRegistryFromTarGz (repo_file, registry); break; case FileType.Zip: UpdateRegistryFromZip (repo_file, registry); break; default: break; } List<CkanModule> metadataChanges = new List<CkanModule>(); foreach (var identifierModulePair in old_available) { var identifier = identifierModulePair.Key; if (registry.IsInstalled(identifier)) { var installedVersion = registry.InstalledVersion(identifier); if (!(registry.available_modules.ContainsKey(identifier))) { log.InfoFormat("UpdateRegistry, module {0}, version {1} not in repository ({2})", identifier, installedVersion, repo); continue; } if (!registry.available_modules[identifier].module_version.ContainsKey(installedVersion)) { continue; } // if the mod is installed and the metadata is different we have to reinstall it var metadata = registry.available_modules[identifier].module_version[installedVersion]; if (!old_available.ContainsKey(identifier) || !old_available[identifier].module_version.ContainsKey(installedVersion)) { continue; } var oldMetadata = old_available[identifier].module_version[installedVersion]; bool same = true; if ((metadata.install == null) != (oldMetadata.install == null) || (metadata.install != null && metadata.install.Length != oldMetadata.install.Length)) { same = false; } else { if(metadata.install != null) for (int i = 0; i < metadata.install.Length; i++) { if (metadata.install[i].file != oldMetadata.install[i].file) { same = false; break; } if (metadata.install[i].install_to != oldMetadata.install[i].install_to) { same = false; break; } if ((metadata.install[i].filter == null) != (oldMetadata.install[i].filter == null)) { same = false; break; } if(metadata.install[i].filter != null) if (!metadata.install[i].filter.SequenceEqual(oldMetadata.install[i].filter)) { same = false; break; } if ((metadata.install[i].filter_regexp == null) != (oldMetadata.install[i].filter_regexp == null)) { same = false; break; } if(metadata.install[i].filter_regexp != null) if (!metadata.install[i].filter_regexp.SequenceEqual(oldMetadata.install[i].filter_regexp)) { same = false; break; } } } if (!same) { metadataChanges.Add(registry.available_modules[identifier].module_version[installedVersion]); } } } if (metadataChanges.Any()) { string mods = ""; for (int i = 0; i < metadataChanges.Count; i++) { mods += metadataChanges[i].identifier + " " + metadataChanges[i].version.ToString() + ((i < metadataChanges.Count-1) ? ", " : ""); } if(user.RaiseYesNoDialog(String.Format( @"The following mods have had their metadata changed since last update - {0}. It is advisable that you reinstall them in order to preserve consistency with the repository. Do you wish to reinstall now?", mods))) { ModuleInstaller installer = ModuleInstaller.GetInstance(ksp, new NullUser()); installer.Upgrade(metadataChanges, new NetAsyncDownloader(new NullUser())); } } // Remove our downloaded meta-data now we've processed it. // Seems weird to do this as part of a transaction, but Net.Download uses them, so let's be consistent. file_transaction.Delete(repo_file); }
private void Create() { log.InfoFormat("Creating new CKAN registry at {0}", path); registry = Registry.Empty(); Save(); }
/// <summary> /// Updates the supplied registry from the supplied zip file. /// This will *clear* the registry of available modules first. /// This does not *save* the registry. For that, you probably want Repo.Update /// </summary> internal static void UpdateRegistryFromTarGz(string path, Registry registry) { log.DebugFormat("Starting registry update from tar.gz file: \"{0}\".", path); // Open the gzip'ed file. using (Stream inputStream = File.OpenRead(path)) { // Create a gzip stream. using (GZipInputStream gzipStream = new GZipInputStream(inputStream)) { // Create a handle for the tar stream. using (TarInputStream tarStream = new TarInputStream(gzipStream)) { // Walk the archive, looking for .ckan files. const string filter = @"\.ckan$"; while (true) { TarEntry entry = tarStream.GetNextEntry(); // Check for EOF. if (entry == null) { break; } string filename = entry.Name; // Skip things we don't want. if (!Regex.IsMatch(filename, filter)) { log.DebugFormat("Skipping archive entry {0}", filename); continue; } log.DebugFormat("Reading CKAN data from {0}", filename); // Read each file into a buffer. int buffer_size = 0; try { buffer_size = Convert.ToInt32(entry.Size); } catch (OverflowException) { log.ErrorFormat("Error processing {0}: Metadata size too large.", entry.Name); continue; } byte[] buffer = new byte[buffer_size]; tarStream.Read(buffer, 0, buffer_size); // Convert the buffer data to a string. string metadata_json = Encoding.ASCII.GetString(buffer); ProcessRegistryMetadataFromJSON(metadata_json, registry, filename); } } } } }
public static Dictionary<GUIMod, string> ComputeConflictsFromModList(Registry registry, IEnumerable<KeyValuePair<GUIMod, GUIModChangeType>> change_set, KSPVersion ksp_version) { var modules_to_install = new HashSet<string>(); var modules_to_remove = new HashSet<string>(); var options = new RelationshipResolverOptions { without_toomanyprovides_kraken = true, procede_with_inconsistencies = true, without_enforce_consistency = true, with_recommends = false }; foreach (var change in change_set) { switch (change.Value) { case GUIModChangeType.None: break; case GUIModChangeType.Install: modules_to_install.Add(change.Key.Identifier); break; case GUIModChangeType.Remove: modules_to_remove.Add(change.Key.Identifier); break; case GUIModChangeType.Update: break; default: throw new ArgumentOutOfRangeException(); } } var installed = registry.Installed() .Where(pair => pair.Value.CompareTo(new ProvidesVersion("")) != 0) .Select(pair => pair.Key); //We wish to only check mods that would exist after the changes are made. var mods_to_check = installed.Union(modules_to_install).Except(modules_to_remove); var resolver = new RelationshipResolver(mods_to_check.ToList(), options, registry, ksp_version); return resolver.ConflictList.ToDictionary(item => new GUIMod(item.Key, registry, ksp_version), item => item.Value); }
private void Create() { registry = Registry.Empty(); log.DebugFormat("Creating new CKAN registry at {0}", path); Save(); }