public static ModuleReplacement GetReplacement(this IRegistryQuerier querier, CkanModule installedVersion, KspVersionCriteria version) { // Mod is not installed, so we don't care about replacements if (installedVersion == null) { return(null); } // No replaced_by relationship if (installedVersion.replaced_by == null) { return(null); } // Get the identifier from the replaced_by relationship, if it exists ModuleRelationshipDescriptor replacedBy = installedVersion.replaced_by; // Now we need to see if there is a compatible version of the replacement try { ModuleReplacement replacement = new ModuleReplacement(); replacement.ToReplace = installedVersion; if (installedVersion.replaced_by.version != null) { replacement.ReplaceWith = querier.GetModuleByVersion(installedVersion.replaced_by.name, installedVersion.replaced_by.version); if (replacement.ReplaceWith != null) { if (replacement.ReplaceWith.IsCompatibleKSP(version)) { return(replacement); } } } else { replacement.ReplaceWith = querier.LatestAvailable(installedVersion.replaced_by.name, version); if (replacement.ReplaceWith != null) { if (installedVersion.replaced_by.min_version != null) { if (!replacement.ReplaceWith.version.IsLessThan(replacedBy.min_version)) { return(replacement); } } else { return(replacement); } } } return(null); } catch (ModuleNotFoundKraken) { return(null); } }
private static List <CfanModule> getModulesFromRegistry( IEnumerable <CfanModuleIdAndVersion> module_names, IRegistryQuerier registry, FactorioVersion kspversion) { return(module_names.Select( p => { var mod = p.version != null ? registry.GetModuleByVersion(p.identifier, p.version) : registry.LatestAvailable(p.identifier, kspversion); if (mod == null) { throw new ModuleNotFoundKraken(p.identifier, p.version?.ToString(), "Module not found."); } return mod; }).ToList()); }
/// <summary> /// Helper to call <see cref="IRegistryQuerier.GetModuleByVersion(string, ModuleVersion)"/> /// </summary> public static CkanModule GetModuleByVersion(this IRegistryQuerier querier, string ident, string version) { return(querier.GetModuleByVersion(ident, new ModuleVersion(version))); }
/// <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 game instance</param> /// <param name="version">The version of the current game instance</param> public IEnumerable <ModChange> ComputeChangeSetFromModList( IRegistryQuerier registry, HashSet <ModChange> changeSet, ModuleInstaller installer, GameVersionCriteria 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: modules_to_install.Add(change.Mod); break; case GUIModChangeType.Remove: modules_to_remove.Add(change.Mod); break; case GUIModChangeType.Replace: ModuleReplacement repl = registry.GetReplacement(change.Mod, 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 dependent in registry.FindReverseDependencies( modules_to_remove .Select(mod => mod.identifier) .Except(modules_to_install.Select(m => m.identifier)), modules_to_install )) { //TODO This would be a good place to have an event that alters the row's graphics to show it will be removed CkanModule depMod; if (installed_modules.TryGetValue(dependent, out depMod)) { CkanModule module_by_version = registry.GetModuleByVersion(depMod.identifier, depMod.version) ?? registry.InstalledModule(dependent).Module; changeSet.Add(new ModChange(module_by_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) || modules_to_install.Any(m => m.identifier == im.identifier)) )) { changeSet.Add(new ModChange(im.Module, GUIModChangeType.Remove, new SelectionReason.NoLongerUsed())); modules_to_remove.Add(im.Module); } // Get as many dependencies as we can, but leave decisions and prompts for installation time RelationshipResolverOptions opts = RelationshipResolver.DependsOnlyOpts(); opts.without_toomanyprovides_kraken = true; opts.without_enforce_consistency = true; var resolver = new RelationshipResolver( modules_to_install, modules_to_remove, opts, registry, version); changeSet.UnionWith( resolver.ModList() .Select(m => new ModChange(m, GUIModChangeType.Install, resolver.ReasonFor(m)))); return(changeSet); }
/// <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, FactorioVersion version) { var modules_to_install = new HashSet <CfanModule>(); var modules_to_remove = new HashSet <CfanModule>(); var options = new RelationshipResolverOptions { without_toomanyprovides_kraken = false, with_recommends = false }; 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; 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 registry.FindReverseDependencies(modules_to_remove.Select(mod => mod.identifier))) { //TODO This would be a good place to have a event that alters the row's graphics to show it will be removed CfanModule module_by_version = registry.GetModuleByVersion(installed_modules[dependency].identifier, installed_modules[dependency].modVersion) ?? registry.InstalledModule(dependency).Module; changeSet.Add(new ModChange(new GUIMod(module_by_version, registry, version), GUIModChangeType.Remove, null)); } //May throw InconsistentKraken var resolver = new RelationshipResolver(options, registry, version); resolver.RemoveModsFromInstalledList( changeSet.Where(change => change.ChangeType.Equals(GUIModChangeType.Remove)).Select(m => m.Mod.ToModule())); resolver.AddModulesToInstall(modules_to_install.ToList()); changeSet.UnionWith( resolver.ModList() .Select(m => new ModChange(new GUIMod(m, registry, version), GUIModChangeType.Install, resolver.ReasonFor(m)))); return(changeSet); }
/// <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); }
/// <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, 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.ChangeType) { case GUIModChangeType.None: break; 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.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 registry.FindReverseDependencies(modules_to_remove.Select(mod=>mod.identifier))) { //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 ModChange(new GUIMod(module_by_version, registry, version), GUIModChangeType.Remove, null)); } //May throw InconsistentKraken var resolver = new RelationshipResolver(options, registry, version); resolver.RemoveModsFromInstalledList( changeSet.Where(change => change.ChangeType.Equals(GUIModChangeType.Remove)).Select(m => m.Mod.ToModule())); resolver.AddModulesToInstall(modules_to_install.ToList()); changeSet.UnionWith( resolver.ModList() .Select(m => new ModChange(new GUIMod(m, registry, version), GUIModChangeType.Install, resolver.ReasonFor(m)))); return changeSet; }