Beispiel #1
0
 public ModChange(CkanModule mod, GUIModChangeType changeType, SelectionReason reason)
 {
     Mod        = mod;
     ChangeType = changeType;
     // If we don't have a Reason, the user probably wanted to install it
     Reason = reason ?? new SelectionReason.UserRequested();
 }
Beispiel #2
0
        /// <summary>
        /// Adds the specified module to the list of modules we're installing.
        /// This also adds its provides list to what we have available.
        /// </summary>
        private void Add(CkanModule module, SelectionReason reason)
        {
            if (module.IsMetapackage)
            {
                return;
            }
            if (module.IsDLC)
            {
                throw new ModuleIsDLCKraken(module);
            }

            log.DebugFormat("Adding {0} {1}", module.identifier, module.version);

            if (modlist.TryGetValue(module.identifier, out CkanModule possibleDup))
            {
                if (possibleDup.identifier == module.identifier)
                {
                    // We should never add the same module twice!
                    log.ErrorFormat("Assertion failed: Adding {0} twice in relationship resolution", module.identifier);
                    throw new ArgumentException("Already contains module: " + module.identifier);
                }
                else
                {
                    // Duplicates via "provides" are OK though, we'll just replace it
                    modlist.Remove(module.identifier);
                }
            }
            modlist.Add(module.identifier, module);
            if (!reasons.ContainsKey(module))
            {
                reasons.Add(module, reason);
            }
            // Override Installed for upgrades
            else if (reasons[module] is SelectionReason.Installed)
            {
                reasons[module] = reason;
            }

            log.DebugFormat("Added {0}", module.identifier);
            // Stop here if it doesn't have any provide aliases.
            if (module.provides == null)
            {
                return;
            }

            // Handle provides/aliases if it does.

            // It's okay if there's already a key for one of our aliases
            // in the resolution list. In which case, we don't do anything.
            var aliases = module.provides.Where(alias => !modlist.ContainsKey(alias));

            foreach (string alias in aliases)
            {
                log.DebugFormat("Adding {0} providing {1}", module.identifier, alias);
                modlist.Add(alias, module);
            }
        }
Beispiel #3
0
 public ModChange(GUIMod mod, GUIModChangeType changeType, SelectionReason reason)
 {
     Mod = mod;
     ChangeType = changeType;
     Reason = reason;
     
     if (Reason == null)
     {
         // Hey, we don't have a Reason
         // Most likely the user wanted to install it
         Reason = new SelectionReason.UserRequested();
     }
 }
Beispiel #4
0
        public ModChange(GUIMod mod, GUIModChangeType changeType, SelectionReason reason)
        {
            Mod        = mod;
            ChangeType = changeType;
            Reason     = reason;

            if (Reason == null)
            {
                // Hey, we don't have a Reason
                // Most likely the user wanted to install it
                Reason = new SelectionReason.UserRequested();
            }
        }
Beispiel #5
0
        /// <summary>
        /// Adds the specified module to the list of modules we're installing.
        /// This also adds its provides list to what we have available.
        /// </summary>
        private void Add(CkanModule module, SelectionReason reason)
        {
            if (module.IsMetapackage)
            {
                return;
            }

            log.DebugFormat("Adding {0} {1}", module.identifier, module.version);

            if (modlist.ContainsKey(module.identifier))
            {
                // We should never be adding something twice!
                log.ErrorFormat("Assertion failed: Adding {0} twice in relationship resolution", module.identifier);
                throw new ArgumentException("Already contains module:" + module.identifier);
            }
            modlist.Add(module.identifier, module);
            if (!reasons.ContainsKey(module))
            {
                reasons.Add(module, reason);
            }
            // Override Installed for upgrades
            else if (reasons[module] is SelectionReason.Installed)
            {
                reasons[module] = reason;
            }

            log.DebugFormat("Added {0}", module.identifier);
            // Stop here if it doesn't have any provide aliases.
            if (module.provides == null)
            {
                return;
            }

            // Handle provides/aliases if it does.

            // It's okay if there's already a key for one of our aliases
            // in the resolution list. In which case, we don't do anything.
            var aliases = module.provides.Where(alias => !modlist.ContainsKey(alias));

            foreach (string alias in aliases)
            {
                log.DebugFormat("Adding {0} providing {1}", module.identifier, alias);
                modlist.Add(alias, module);
            }
        }
Beispiel #6
0
        /// <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, SelectionReason reason,
            RelationshipResolverOptions options, bool soft_resolve = false)
        {
            if (stanza == null)
            {
                return;
            }

            foreach (var descriptor in stanza)
            {
                string dep_name = descriptor.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))
                {
                    if (descriptor.version_within_bounds(modlist[dep_name].version))
                        continue;
                    //TODO Ideally we could check here if it can be replaced by the version we want.
                    throw new InconsistentKraken(
                        string.Format(
                            "{0} requires a version {1}. However a incompatible version, {2}, is in the resolver",
                            dep_name, descriptor.RequiredVersion, modlist[dep_name].version));

                }

                if (registry.IsInstalled(dep_name))
                {
                    if(descriptor.version_within_bounds(registry.InstalledVersion(dep_name)))
                    continue;
                    //TODO Ideally we could check here if it can be replaced by the version we want.
                    throw new InconsistentKraken(
                        string.Format(
                            "{0} requires a version {1}. However a incompatible version, {2}, is already installed",
                            dep_name, descriptor.RequiredVersion, registry.InstalledVersion(dep_name)));
                }

                List<CkanModule> candidates = registry.LatestAvailableWithProvides(dep_name, kspversion, descriptor)
                    .Where(mod=>MightBeInstallable(mod)).ToList();

                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(installed_modules);

                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));
                    }
                }
            }
        }
Beispiel #7
0
        /// <summary>
        /// Adds the specified module to the list of modules we're installing.
        /// This also adds its provides list to what we have available.
        /// </summary>
        private void Add(CkanModule module, SelectionReason reason)
        {
            if (module.IsMetapackage)
                return;

            log.DebugFormat("Adding {0} {1}", module.identifier, module.version);

            if (modlist.ContainsKey(module.identifier))
            {
                // We should never be adding something twice!
                log.ErrorFormat("Assertion failed: Adding {0} twice in relationship resolution", module.identifier);
                throw new ArgumentException("Already contains module:" + module.identifier);
            }
            modlist.Add(module.identifier, module);
            if(!reasons.ContainsKey(module)) reasons.Add(module, reason);

            log.DebugFormat("Added {0}", module.identifier);
            // Stop here if it doesn't have any provide aliases.
            if (module.provides == null)
            {
                return;
            }

            // Handle provides/aliases if it does.

            // It's okay if there's already a key for one of our aliases
            // in the resolution list. In which case, we don't do anything.
            var aliases = module.provides.Where(alias => !modlist.ContainsKey(alias));
            foreach (string alias in aliases)
            {
                log.DebugFormat("Adding {0} providing {1}", module.identifier, alias);
                modlist.Add(alias, module);
            }
        }
Beispiel #8
0
        /// <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, SelectionReason reason,
                                   RelationshipResolverOptions options, bool soft_resolve = false, IEnumerable <RelationshipDescriptor> old_stanza = null)
        {
            if (stanza == null)
            {
                return;
            }
            stanza = stanza.Memoize();

            foreach (RelationshipDescriptor descriptor in stanza)
            {
                log.DebugFormat("Considering {0}", descriptor.ToString());

                // If we already have this dependency covered, skip.
                if (descriptor.MatchesAny(modlist.Values, null, null))
                {
                    continue;
                }
                else if (descriptor.ContainsAny(modlist.Keys))
                {
                    CkanModule module = modlist.Values
                                        .FirstOrDefault(m => descriptor.ContainsAny(new string[] { m.identifier }));
                    if (options.proceed_with_inconsistencies)
                    {
                        conflicts.Add(new KeyValuePair <CkanModule, CkanModule>(module, reason.Parent));
                        conflicts.Add(new KeyValuePair <CkanModule, CkanModule>(reason.Parent, module));
                        continue;
                    }
                    else
                    {
                        throw new InconsistentKraken(
                                  $"{descriptor} required, but an incompatible version is in the resolver"
                                  );
                    }
                }

                // If it's already installed, skip.
                if (descriptor.MatchesAny(
                        installed_modules,
                        registry.InstalledDlls.ToHashSet(),
                        registry.InstalledDlc))
                {
                    continue;
                }
                else if (descriptor.ContainsAny(installed_modules.Select(im => im.identifier)))
                {
                    CkanModule module = installed_modules
                                        .FirstOrDefault(m => descriptor.ContainsAny(new string[] { m.identifier }));
                    if (options.proceed_with_inconsistencies)
                    {
                        conflicts.Add(new KeyValuePair <CkanModule, CkanModule>(module, reason.Parent));
                        conflicts.Add(new KeyValuePair <CkanModule, CkanModule>(reason.Parent, module));
                        continue;
                    }
                    else
                    {
                        throw new InconsistentKraken(
                                  $"{descriptor} required, but an incompatible version is installed"
                                  );
                    }
                }

                // Pass mod list in case an older version of a module is conflict-free while later versions have conflicts
                var descriptor1 = descriptor;
                List <CkanModule> candidates = descriptor
                                               .LatestAvailableWithProvides(registry, GameVersion, modlist.Values)
                                               .Where(mod => !modlist.ContainsKey(mod.identifier) &&
                                                      descriptor1.WithinBounds(mod) &&
                                                      MightBeInstallable(mod))
                                               .ToList();
                if (candidates.Count == 0)
                {
                    // Nothing found, try again without mod list
                    // (conflicts will still be caught below)
                    candidates = descriptor
                                 .LatestAvailableWithProvides(registry, GameVersion)
                                 .Where(mod => !modlist.ContainsKey(mod.identifier) &&
                                        descriptor1.WithinBounds(mod) &&
                                        MightBeInstallable(mod))
                                 .ToList();
                }

                if (candidates.Count == 0)
                {
                    if (!soft_resolve)
                    {
                        log.InfoFormat("Dependency on {0} found but it is not listed in the index, or not available for your version of KSP.", descriptor.ToString());
                        throw new DependencyNotSatisfiedKraken(reason.Parent, descriptor.ToString());
                    }
                    log.InfoFormat("{0} is recommended/suggested but it is not listed in the index, or not available for your version of KSP.", descriptor.ToString());
                    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;
                    }

                    // If we've got a parent stanza that has a relationship on a mod that provides what
                    // we need, then select that.
                    if (old_stanza != null)
                    {
                        List <CkanModule> provide = candidates
                                                    .Where(cand => old_stanza.Any(rel => rel.WithinBounds(cand)))
                                                    .ToList();
                        if (!provide.Any() || provide.Count() > 1)
                        {
                            //We still have either nothing, or too many to pick from
                            //Just throw the TMP now
                            throw new TooManyModsProvideKraken(descriptor.ToString(), candidates);
                        }
                        candidates[0] = provide.First();
                    }
                    else
                    {
                        throw new TooManyModsProvideKraken(descriptor.ToString(), 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 <CkanModule>(modlist.Values);
                fixed_mods.UnionWith(installed_modules);

                CkanModule 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, stanza);
                }
                else if (soft_resolve)
                {
                    log.InfoFormat("{0} would cause conflicts, excluding it from consideration", candidate);
                }
                else
                {
                    if (options.proceed_with_inconsistencies)
                    {
                        Add(candidate, reason);
                        conflicts.Add(new KeyValuePair <CkanModule, CkanModule>(conflicting_mod, candidate));
                        conflicts.Add(new KeyValuePair <CkanModule, CkanModule>(candidate, conflicting_mod));
                    }
                    else
                    {
                        throw new InconsistentKraken(
                                  $"{conflicting_mod} conflicts with {candidate}");
                    }
                }
            }
        }
Beispiel #9
0
        /// <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, SelectionReason reason,
                                   RelationshipResolverOptions options, bool soft_resolve = false, IEnumerable <RelationshipDescriptor> old_stanza = null)
        {
            if (stanza == null)
            {
                return;
            }

            foreach (var descriptor in stanza)
            {
                string dep_name = descriptor.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))
                {
                    var module = modlist[dep_name];
                    if (descriptor.version_within_bounds(module.version))
                    {
                        continue;
                    }
                    //TODO Ideally we could check here if it can be replaced by the version we want.
                    if (options.procede_with_inconsistencies)
                    {
                        conflicts.Add(new KeyValuePair <CkanModule, CkanModule>(module, reason.Parent));
                        conflicts.Add(new KeyValuePair <CkanModule, CkanModule>(reason.Parent, module));
                        continue;
                    }
                    throw new InconsistentKraken(
                              string.Format(
                                  "{0} requires a version {1}. However a incompatible version, {2}, is in the resolver",
                                  dep_name, descriptor.RequiredVersion, module.version));
                }

                if (registry.IsInstalled(dep_name))
                {
                    if (descriptor.version_within_bounds(registry.InstalledVersion(dep_name)))
                    {
                        continue;
                    }
                    var module = registry.InstalledModule(dep_name).Module;

                    //TODO Ideally we could check here if it can be replaced by the version we want.
                    if (options.procede_with_inconsistencies)
                    {
                        conflicts.Add(new KeyValuePair <CkanModule, CkanModule>(module, reason.Parent));
                        conflicts.Add(new KeyValuePair <CkanModule, CkanModule>(reason.Parent, module));
                        continue;
                    }
                    throw new InconsistentKraken(
                              string.Format(
                                  "{0} requires a version {1}. However a incompatible version, {2}, is already installed",
                                  dep_name, descriptor.RequiredVersion, registry.InstalledVersion(dep_name)));
                }

                var descriptor1 = descriptor;
                List <CkanModule> candidates = registry.LatestAvailableWithProvides(dep_name, kspversion, descriptor)
                                               .Where(mod => descriptor1.version_within_bounds(mod.version) && MightBeInstallable(mod)).ToList();

                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;
                    }

                    // If we've got a parent stanza that has a relationship on a mod that provides what
                    // we need, then select that.
                    if (old_stanza != null)
                    {
                        List <CkanModule> provide = candidates.Where(can => old_stanza.Where(relation => can.identifier == relation.name).Any()).ToList();
                        if (!provide.Any() || provide.Count() > 1)
                        {
                            //We still have either nothing, or too my to pick from
                            //Just throw the TMP now
                            throw new TooManyModsProvideKraken(dep_name, candidates);
                        }
                        candidates[0] = provide.First();
                    }
                    else
                    {
                        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 <CkanModule>(modlist.Values);
                fixed_mods.UnionWith(installed_modules);

                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, stanza);
                }
                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 <CkanModule, CkanModule>(conflicting_mod, candidate));
                        conflicts.Add(new KeyValuePair <CkanModule, CkanModule>(candidate, conflicting_mod));
                    }
                    else
                    {
                        throw new InconsistentKraken(string.Format("{0} conflicts with {1}, can't install both.", conflicting_mod,
                                                                   candidate));
                    }
                }
            }
        }
Beispiel #10
0
 public ModUpgrade(CkanModule mod, GUIModChangeType changeType, SelectionReason reason, CkanModule targetMod)
     : base(mod, changeType, reason)
 {
     this.targetMod = targetMod;
 }