public void HasUpdate_OtherModDependsOnCurrent_ReturnsFalse() { // Arrange using (var gameInstWrapper = new DisposableKSP()) { CkanModule olderDepMod = CkanModule.FromJson(@"{ ""spec_version"": ""v1.4"", ""identifier"": ""DependencyMod"", ""version"": ""1.0"", ""ksp_version"": ""1.11.1"", ""download"": ""https://mymods/DM/1.0"" }"); CkanModule newerDepMod = CkanModule.FromJson(@"{ ""spec_version"": ""v1.4"", ""identifier"": ""DependencyMod"", ""version"": ""2.0"", ""ksp_version"": ""1.11.1"", ""download"": ""https://mymods/DM/2.0"" }"); CkanModule dependingMod = CkanModule.FromJson(@"{ ""spec_version"": ""v1.4"", ""identifier"": ""DependingMod"", ""version"": ""1.0"", ""ksp_version"": ""1.11.1"", ""download"": ""https://mymods/DM/2.0"", ""depends"": [ { ""name"": ""DependencyMod"", ""version"": ""1.0"" } ] }"); registry.AddAvailable(olderDepMod); registry.AddAvailable(newerDepMod); registry.AddAvailable(dependingMod); GameInstance gameInst = gameInstWrapper.KSP; registry.RegisterModule(olderDepMod, new string[0], gameInst, false); registry.RegisterModule(dependingMod, new string[0], gameInst, false); GameVersionCriteria crit = new GameVersionCriteria(olderDepMod.ksp_version); // Act bool has = registry.HasUpdate(olderDepMod.identifier, crit); // Assert Assert.IsFalse(has, "Upgrade allowed that would break another mod's dependency"); } }
/// <summary> /// Install our mod from the filename supplied. /// If no file is supplied, we will check the cache or throw FileNotFoundKraken. /// Does *not* resolve dependencies; this actually does the heavy listing. /// Does *not* save the registry. /// Do *not* call this directly, use InstallList() instead. /// /// Propagates a BadMetadataKraken if our install metadata is bad. /// Propagates a FileExistsKraken if we were going to overwrite a file. /// Throws a FileNotFoundKraken if we can't find the downloaded module. /// /// </summary> // // TODO: The name of this and InstallModule() need to be made more distinctive. private void Install(CkanModule module, string filename = null) { CheckMetapackageInstallationKraken(module); Version version = registry_manager.registry.InstalledVersion(module.identifier); // TODO: This really should be handled by higher-up code. if (version != null) { User.RaiseMessage(" {0} {1} already installed, skipped", module.identifier, version); return; } // Find our in the cache if we don't already have it. filename = filename ?? Cache.GetCachedZip(module.download, true); // If we *still* don't have a file, then kraken bitterly. if (filename == null) { throw new FileNotFoundKraken( null, String.Format("Trying to install {0}, but it's not downloaded or download is corrupted", module) ); } // We'll need our registry to record which files we've installed. Registry registry = registry_manager.registry; using (var transaction = CkanTransaction.CreateTransactionScope()) { // Install all the things! IEnumerable <string> files = InstallModule(module, filename); // Register our module and its files. registry.RegisterModule(module, files, ksp); // Finish our transaction, but *don't* save the registry; we may be in an // intermediate, inconsistent state. // This is fine from a transaction standpoint, as we may not have an enclosing // transaction, and if we do, they can always roll us back. transaction.Complete(); } // Fire our callback that we've installed a module, if we have one. if (onReportModInstalled != null) { onReportModInstalled(module); } }
/// <summary> /// Install our mod from the filename supplied. /// If no file is supplied, we will check the cache or download it. /// Does *not* resolve dependencies; this actually does the heavy listing. /// Does *not* save the registry. /// Do *not* call this directly, use InstallList() instead. /// /// Propagates a BadMetadataKraken if our install metadata is bad. /// Propagates a FileExistsKraken if we were going to overwrite a file. /// /// </summary> // // TODO: The name of this and InstallModule() need to be made more distinctive. private void Install(CkanModule module, string filename = null) { Version version = registry_manager.registry.InstalledVersion(module.identifier); // TODO: This really should be handled by higher-up code. if (version != null) { User.WriteLine(" {0} {1} already installed, skipped", module.identifier, version); return; } // Fetch our file if we don't already have it. if (filename == null) { filename = CachedOrDownload(module); } // We'll need our registry to record which files we've installed. Registry registry = registry_manager.registry; using (var transaction = new TransactionScope()) { // Install all the things! IEnumerable <string> files = InstallModule(module, filename); // Register our module and its files. registry.RegisterModule(module, files, ksp); // Finish our transaction, but *don't* save the registry; we may be in an // intermediate, inconsistent state. // This is fine from a transaction standpoint, as we may not have an enclosing // transaction, and if we do, they can always roll us back. transaction.Complete(); } // Fire our callback that we've installed a module, if we have one. if (onReportModInstalled != null) { onReportModInstalled(module); } }
/// <summary> /// Install our mod from the filename supplied. /// If no file is supplied, we will fetch() it first. /// </summary> public void Install(CkanModule module, string filename = null) { Console.WriteLine(module.identifier + ":\n"); string version = registry_manager.registry.InstalledVersion(module.identifier); if (version != null) { // TODO: Check if we can upgrade! Console.WriteLine(" {0} {1} already installed, skipped", module.identifier, version); return; } // Check our dependencies. if (module.requires != null) { foreach (dynamic depends in module.requires) { string name = depends.name; string ver = registry_manager.registry.InstalledVersion(name); // TODO: Compare versions. if (ver == null) { // Oh, it's not installed! Let's see if we can find it. // TODO: A big store of all our known CKAN data, so we can go // find our module. // If we can't find it, cry and moan. Console.WriteLine("Requirement {0} not found", depends.name); throw new ModuleNotFoundException(name, depends.version); } } } // Fetch our file if we don't already have it. if (filename == null) { filename = CachedOrDownload(module); } // We'll need our registry to record which files we've installed. Registry registry = registry_manager.registry; // And a list of files to record them to. Dictionary <string, InstalledModuleFile> module_files = new Dictionary <string, InstalledModuleFile> (); // Open our zip file for processing ZipFile zipfile = new ZipFile(File.OpenRead(filename)); // Walk through our install instructions. foreach (dynamic stanza in module.install) { InstallComponent(stanza, zipfile, module_files); } // Register our files. registry.RegisterModule(new InstalledModule(module_files, module, DateTime.Now)); // Handle bundled mods, if we have them. if (module.bundles != null) { foreach (dynamic stanza in module.bundles) { BundledModule bundled = new BundledModule(stanza); string ver = registry_manager.registry.InstalledVersion(bundled.identifier); if (ver != null) { Console.WriteLine( "{0} {1} already installed, skipping bundled version {2}", bundled.identifier, ver, bundled.version ); continue; } // Not installed, so let's get about installing it! Dictionary <string, InstalledModuleFile> installed_files = new Dictionary <string, InstalledModuleFile> (); InstallComponent(stanza, zipfile, installed_files); registry.RegisterModule(new InstalledModule(installed_files, bundled, DateTime.Now)); } } // Done! Save our registry changes! registry_manager.Save(); return; }
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); } }
public void UninstallingConflictingModule_InstallingRecursiveDependencies_ResolvesSuccessfully() { using (var ksp = new DisposableKSP()) { // Arrange: create dummy modules that resemble the relationship entanglement, and make them available var eve = generator.GeneratorRandomModule( identifier: "EnvironmentalVisualEnhancements", depends: new List <RelationshipDescriptor> { new ModuleRelationshipDescriptor { name = "EnvironmentalVisualEnhancements-Config" } } ); var eveDefaultConfig = generator.GeneratorRandomModule( identifier: "EnvironmentalVisualEnhancements-Config-stock", provides: new List <string> { "EnvironmentalVisualEnhancements-Config" }, conflicts: new List <RelationshipDescriptor> { new ModuleRelationshipDescriptor { name = "EnvironmentalVisualEnhancements-Config" } } ); var avp = generator.GeneratorRandomModule( identifier: "AstronomersVisualPack", provides: new List <string> { "EnvironmentalVisualEnhancements-Config" }, depends: new List <RelationshipDescriptor> { new ModuleRelationshipDescriptor { name = "AVP-Textures" }, new ModuleRelationshipDescriptor { name = "EnvironmentalVisualEnhancements" } }, conflicts: new List <RelationshipDescriptor> { new ModuleRelationshipDescriptor { name = "EnvironmentalVisualEnhancements-Config" } } ); var avp2kTextures = generator.GeneratorRandomModule( identifier: "AVP-2kTextures", provides: new List <string> { "AVP-Textures" }, depends: new List <RelationshipDescriptor> { new ModuleRelationshipDescriptor { name = "AstronomersVisualPack" } }, conflicts: new List <RelationshipDescriptor> { new ModuleRelationshipDescriptor { name = "AVP-Textures" } } ); AddToRegistry(eve, eveDefaultConfig, avp, avp2kTextures); // Start with eve and eveDefaultConfig installed registry.RegisterModule(eve, new string[0], ksp.KSP, false); registry.RegisterModule(eveDefaultConfig, new string[0], ksp.KSP, false); Assert.DoesNotThrow(() => registry.CheckSanity()); List <CkanModule> modulesToInstall; List <CkanModule> modulesToRemove; RelationshipResolver resolver; // Act and assert: play through different possible user interactions // Scenario 1 - Try installing AVP, expect an exception for proceed_with_inconsistencies=false modulesToInstall = new List <CkanModule> { avp }; modulesToRemove = new List <CkanModule>(); options.proceed_with_inconsistencies = false; Assert.Throws <InconsistentKraken>(() => { resolver = new RelationshipResolver(modulesToInstall, modulesToRemove, options, registry, null); }); // Scenario 2 - Try installing AVP, expect no exception for proceed_with_inconsistencies=true, but a conflict list resolver = null; options.proceed_with_inconsistencies = true; Assert.DoesNotThrow(() => { resolver = new RelationshipResolver(modulesToInstall, modulesToRemove, options, registry, null); }); CollectionAssert.AreEquivalent(new List <CkanModule> { avp, eveDefaultConfig }, resolver.ConflictList.Keys); // Scenario 3 - Try uninstalling eveDefaultConfig and installing avp, should work and result in no conflicts modulesToInstall = new List <CkanModule> { avp }; modulesToRemove = new List <CkanModule> { eveDefaultConfig }; resolver = null; options.proceed_with_inconsistencies = false; Assert.DoesNotThrow(() => { resolver = new RelationshipResolver(modulesToInstall, modulesToRemove, options, registry, null); }); Assert.IsEmpty(resolver.ConflictList); CollectionAssert.AreEquivalent(new List <CkanModule> { avp, avp2kTextures }, resolver.ModList()); } }