private TreeNode UpdateModDependencyGraphRecursively(TreeNode parentNode, CkanModule module, RelationshipType relationship, int depth, bool virtualProvides = false) { TreeNode node = null; if (module == null) { return(node); } if (depth > 0 && dependencyGraphRootModule == module) { return(node); } if (alreadyVisited.Contains(module)) { return(node); } alreadyVisited.Add(module); if (parentNode == null) { node = new TreeNode(module.name); } else { node = parentNode.Nodes.Add(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; } if (relationships == null) { return(node); } int i = 0; foreach (RelationshipDescriptor dependency in relationships) { Registry registry = RegistryManager.Instance(KSPManager.CurrentInstance).registry; try { CkanModule dependencyModule = null; try { dependencyModule = registry.LatestAvailable (dependency.name.ToString(), KSPManager.CurrentInstance.Version()); UpdateModDependencyGraphRecursively(node, dependencyModule, relationship, depth + 1); } catch (ModuleNotFoundKraken) { List <CkanModule> dependencyModules = registry.LatestAvailableWithProvides (dependency.name.ToString(), KSPManager.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); i++; } } } catch (Exception) { } } return(node); }
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); 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; } if (relationships == null) { return(node); } foreach (RelationshipDescriptor dependency in relationships) { Registry 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); }
/// <summary> /// Resolve a relationship stanza (a list of relationships). /// This will add modules to be installed, if required. /// May recurse back to Resolve for those new modules. /// /// If `soft_resolve` is true, we warn rather than throw exceptions on mods we cannot find. /// If `soft_resolve` is false (default), we throw a ModuleNotFoundKraken if we can't find a dependency. /// /// Throws a TooManyModsProvideKraken if we have too many choices. /// </summary> private void ResolveStanza(IEnumerable <RelationshipDescriptor> stanza, RelationshipResolverOptions options, bool soft_resolve = false) { if (stanza == null) { return; } foreach (string dep_name in stanza.Select(dep => dep.name)) { log.DebugFormat("Considering {0}", dep_name); // If we already have this dependency covered, skip. // If it's already installed, skip. if (modlist.ContainsKey(dep_name) || registry.IsInstalled(dep_name)) { continue; } List <CkanModule> candidates = registry.LatestAvailableWithProvides(dep_name, kspversion); if (candidates.Count == 0) { if (!soft_resolve) { log.ErrorFormat("Dependency on {0} found, but nothing provides it.", dep_name); throw new ModuleNotFoundKraken(dep_name); } log.InfoFormat("{0} is recommended/suggested, but nothing provides it.", dep_name); continue; } if (candidates.Count > 1) { // Oh no, too many to pick from! // TODO: It would be great if instead we picked the one with the // most recommendations. if (options.without_toomanyprovides_kraken) { continue; } throw new TooManyModsProvideKraken(dep_name, candidates); } CkanModule candidate = candidates[0]; // Finally, check our candidate against everything which might object // to it being installed; that's all the mods which are fixed in our // list thus far, as well as everything on the system. var fixed_mods = new HashSet <Module>(modlist.Values); fixed_mods.UnionWith(registry.InstalledModules.Select(x => x.Module)); foreach (Module mod in fixed_mods) { if (mod.ConflictsWith(candidate)) { if (soft_resolve) { log.InfoFormat("{0} would cause conflicts, excluding it from consideration", candidate); // I want labeled loops please, so I don't have to set this to null, // break, and then look at it at the end. o_O candidate = null; break; } var this_is_why_we_cant_have_nice_things = new List <string> { string.Format( "{0} and {1} conflict with each other, yet we require them both!", candidate, mod) }; throw new InconsistentKraken(this_is_why_we_cant_have_nice_things); } } // Our candidate may have been set to null if it was vetoed by our // sanity check above. if (candidate != null) { // Okay, looks like we want this one. Adding. Add(candidate); Resolve(candidate, options); } } }
/// <summary> /// Resolve a relationship stanza (a list of relationships). /// This will add modules to be installed, if required. /// May recurse back to Resolve for those new modules. /// /// If `soft_resolve` is true, we warn rather than throw exceptions on mods we cannot find. /// If `soft_resolve` is false (default), we throw a ModuleNotFoundKraken if we can't find a dependency. /// /// Throws a TooManyModsProvideKraken if we have too many choices and /// options.without_toomanyprovides_kraken is not set. /// /// See RelationshipResolverOptions for further adjustments that can be made. /// /// </summary> private void ResolveStanza(IEnumerable <RelationshipDescriptor> stanza, Relationship reason, RelationshipResolverOptions options, bool soft_resolve = false) { if (stanza == null) { return; } foreach (string dep_name in stanza.Select(dep => dep.name)) { log.DebugFormat("Considering {0}", dep_name); // If we already have this dependency covered, skip. // If it's already installed, skip. if (modlist.ContainsKey(dep_name) || registry.IsInstalled(dep_name)) { continue; } List <CkanModule> candidates = registry.LatestAvailableWithProvides(dep_name, kspversion); if (candidates.Count == 0) { if (!soft_resolve) { log.ErrorFormat("Dependency on {0} found, but nothing provides it.", dep_name); throw new ModuleNotFoundKraken(dep_name); } log.InfoFormat("{0} is recommended/suggested, but nothing provides it.", dep_name); continue; } if (candidates.Count > 1) { // Oh no, too many to pick from! // TODO: It would be great if instead we picked the one with the // most recommendations. if (options.without_toomanyprovides_kraken) { continue; } throw new TooManyModsProvideKraken(dep_name, candidates); } CkanModule candidate = candidates[0]; // Finally, check our candidate against everything which might object // to it being installed; that's all the mods which are fixed in our // list thus far, as well as everything on the system. var fixed_mods = new HashSet <Module>(modlist.Values); fixed_mods.UnionWith(registry.InstalledModules.Select(x => x.Module)); var conflicting_mod = fixed_mods.FirstOrDefault(mod => mod.ConflictsWith(candidate)); if (conflicting_mod == null) { // Okay, looks like we want this one. Adding. Add(candidate, reason); Resolve(candidate, options); } else if (soft_resolve) { log.InfoFormat("{0} would cause conflicts, excluding it from consideration", candidate); } else { if (options.procede_with_inconsistencies) { Add(candidate, reason); conflicts.Add(new KeyValuePair <Module, Module>(conflicting_mod, candidate)); conflicts.Add(new KeyValuePair <Module, Module>(candidate, conflicting_mod)); } else { throw new InconsistentKraken(string.Format("{0} conflicts with {1}, can't install both.", conflicting_mod, candidate)); } } } }