Beispiel #1
0
        public void Constructor_ContainsSugestedOfSugested_When_With_all_suggests()
        {
            options.with_all_suggests = true;
            var list = new List<string>();
            var sugested2 = generator.GeneratorRandomModule();
            var sugested = generator.GeneratorRandomModule(sugests: new List<RelationshipDescriptor>
            {
                new RelationshipDescriptor {name = sugested2.identifier}
            });
            var sugester = generator.GeneratorRandomModule(sugests: new List<RelationshipDescriptor>
            {
                new RelationshipDescriptor {name = sugested.identifier}
            });

            list.Add(sugester.identifier);
            AddToRegistry(sugester, sugested, sugested2);

            var relationship_resolver = new RelationshipResolver(list, options, registry, null);
            CollectionAssert.Contains(relationship_resolver.ModList(), sugested2);

            options.with_all_suggests = false;

            relationship_resolver = new RelationshipResolver(list, options, registry, null);
            CollectionAssert.DoesNotContain(relationship_resolver.ModList(), sugested2);
        }
        public void Constructor_WithConflictingModules()
        {
            var list = new List<string>();
            var mod_a = generator.GeneratorRandomModule();
            var mod_b = generator.GeneratorRandomModule(conflicts: new List<RelationshipDescriptor>
            {
                new RelationshipDescriptor {name=mod_a.identifier}
            });

            list.Add(mod_a.identifier);
            list.Add(mod_b.identifier);
            AddToRegistry(mod_a, mod_b);
            
            Assert.Throws<InconsistentKraken>(() => new RelationshipResolver(
                list,
                options,
                registry,
                null));


            options.procede_with_inconsistencies = true;
            var resolver = new RelationshipResolver(list, options, registry, null);

            Assert.That(resolver.ConflictList.Any(s => Equals(s.Key, mod_a)));
            Assert.That(resolver.ConflictList.Any(s => Equals(s.Key, mod_b)));
            Assert.That(resolver.ConflictList, Has.Count.EqualTo(2));
        }
Beispiel #3
0
        private void installFromckanToolStripMenuItem_Click(object sender, EventArgs e)
        {
            OpenFileDialog open_file_dialog = new OpenFileDialog {
                Filter = Resources.CKANFileFilter
            };

            if (open_file_dialog.ShowDialog() == DialogResult.OK)
            {
                var        path   = open_file_dialog.FileName;
                CkanModule module = null;

                try
                {
                    module = CkanModule.FromFile(path);
                }
                catch (Kraken kraken)
                {
                    m_User.RaiseError(kraken.Message + ": " + kraken.InnerException.Message);
                    return;
                }
                catch (Exception ex)
                {
                    m_User.RaiseError(ex.Message);
                    return;
                }

                // We'll need to make some registry changes to do this.
                RegistryManager registry_manager = RegistryManager.Instance(CurrentInstance);

                // Remove this version of the module in the registry, if it exists.
                registry_manager.registry.RemoveAvailable(module);

                // Sneakily add our version in...
                registry_manager.registry.AddAvailable(module);

                var changeset = new List <KeyValuePair <CkanModule, GUIModChangeType> >();
                changeset.Add(new KeyValuePair <CkanModule, GUIModChangeType>(module, GUIModChangeType.Install));

                menuStrip1.Enabled = false;

                RelationshipResolverOptions install_ops = RelationshipResolver.DefaultOpts();
                install_ops.with_recommends = false;

                m_InstallWorker.RunWorkerAsync(
                    new KeyValuePair <List <KeyValuePair <CkanModule, GUIModChangeType> >, RelationshipResolverOptions>(
                        changeset, install_ops));
                m_Changeset = null;

                UpdateChangesDialog(null, m_InstallWorker);
                ShowWaitDialog();
            }
        }
Beispiel #4
0
        /// <summary>
        /// Upgrades the mods listed to the latest versions for the user's KSP.
        /// Will *re-install* with warning even if an upgrade is not available.
        /// Throws ModuleNotFoundKraken if module is not installed, or not available.
        /// </summary>
        public void Upgrade(IEnumerable <string> identifiers, IDownloader netAsyncDownloader)
        {
            var options = new RelationshipResolverOptions();

            // We do not wish to pull in any suggested or recommended mods.
            options.with_recommends = false;
            options.with_suggests   = false;

            var resolver = new RelationshipResolver(identifiers.ToList(), options, registry_manager.registry, ksp.Version());
            List <CkanModule> upgrades = resolver.ModList();

            Upgrade(upgrades, netAsyncDownloader);
        }
Beispiel #5
0
        private void reinstallToolStripMenuItem_Click(object sender, EventArgs e)
        {
            GUIMod module = ModInfoTabControl.SelectedModule;

            if (module == null || !module.IsCKAN)
            {
                return;
            }

            YesNoDialog reinstallDialog  = new YesNoDialog();
            string      confirmationText = $"Do you want to reinstall {module.Name}?";

            if (reinstallDialog.ShowYesNoDialog(confirmationText) == DialogResult.No)
            {
                return;
            }

            IRegistryQuerier registry = RegistryManager.Instance(CurrentInstance).registry;

            // Build the list of changes, first the mod to remove:
            List <ModChange> toReinstall = new List <ModChange>()
            {
                new ModChange(module, GUIModChangeType.Remove, null)
            };
            // Then everything we need to re-install:
            var revdep = registry.FindReverseDependencies(new List <string>()
            {
                module.Identifier
            });
            var goners = revdep.Union(
                registry.FindRemovableAutoInstalled(
                    registry.InstalledModules.Where(im => !revdep.Contains(im.identifier))
                    ).Select(im => im.Module.identifier)
                );

            foreach (string id in goners)
            {
                toReinstall.Add(new ModChange(
                                    mainModList.full_list_of_mod_rows[id]?.Tag as GUIMod,
                                    GUIModChangeType.Install,
                                    null
                                    ));
            }
            // Hand off to centralized [un]installer code
            installWorker.RunWorkerAsync(
                new KeyValuePair <List <ModChange>, RelationshipResolverOptions>(
                    toReinstall,
                    RelationshipResolver.DependsOnlyOpts()
                    )
                );
        }
Beispiel #6
0
        private void Changeset_OnConfirmChanges()
        {
            menuStrip1.Enabled = false;

            //Using the changeset passed in can cause issues with versions.
            // An example is Mechjeb for FAR at 25/06/2015 with a 1.0.2 install.
            // TODO Work out why this is.
            installWorker.RunWorkerAsync(
                new KeyValuePair <List <ModChange>, RelationshipResolverOptions>(
                    mainModList.ComputeUserChangeSet(RegistryManager.Instance(Main.Instance.CurrentInstance).registry).ToList(),
                    RelationshipResolver.DependsOnlyOpts()
                    )
                );
        }
Beispiel #7
0
        /// <summary>
        /// Initiate the GUI installer flow for one specific module
        /// </summary>
        /// <param name="registry">Reference to the registry</param>
        /// <param name="module">Module to install</param>
        public async void InstallModuleDriver(IRegistryQuerier registry, CkanModule module)
        {
            RelationshipResolverOptions install_ops = RelationshipResolver.DefaultOpts();

            install_ops.with_recommends = false;

            try
            {
                // Resolve the provides relationships in the dependencies
                List <ModChange> fullChangeSet = new List <ModChange>(
                    await mainModList.ComputeChangeSetFromModList(
                        registry,
                        new HashSet <ModChange>()
                {
                    new ModChange(
                        new GUIMod(
                            module,
                            registry,
                            CurrentInstance.VersionCriteria()
                            ),
                        GUIModChangeType.Install,
                        null
                        )
                },
                        ModuleInstaller.GetInstance(CurrentInstance, Manager.Cache, GUI.user),
                        CurrentInstance.VersionCriteria()
                        )
                    );
                if (fullChangeSet != null && fullChangeSet.Count > 0)
                {
                    installWorker.RunWorkerAsync(
                        new KeyValuePair <List <ModChange>, RelationshipResolverOptions>(
                            fullChangeSet,
                            install_ops
                            )
                        );
                }
            }
            catch
            {
                // If we failed, do the clean-up normally done by PostInstallMods.
                HideWaitDialog(false);
                menuStrip1.Enabled = true;
            }
            finally
            {
                changeSet = null;
            }
        }
Beispiel #8
0
        public static Dictionary <GUIMod, string> ComputeConflictsFromModList(IRegistryQuerier registry,
                                                                              IEnumerable <ModChange> change_set, FactorioVersion 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.ChangeType)
                {
                case GUIModChangeType.None:
                    break;

                case GUIModChangeType.Install:
                    modules_to_install.Add(change.Mod.Identifier);
                    break;

                case GUIModChangeType.Remove:
                    modules_to_remove.Add(change.Mod.Identifier);
                    break;

                case GUIModChangeType.Update:
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }
            }

            var installed =
                registry.Installed()
                .Where(pair => pair.Value.CompareTo(new ProvidedVersion("", "0.0.0")) != 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).Select(p => new CfanModuleIdAndVersion(p));
            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));
        }
Beispiel #9
0
        private void ConfirmChangesButton_Click(object sender, EventArgs e)
        {
            menuStrip1.Enabled = false;

            RelationshipResolverOptions install_ops = RelationshipResolver.DefaultOpts();

            install_ops.with_recommends = false;

            m_InstallWorker.RunWorkerAsync(
                new KeyValuePair <List <KeyValuePair <CkanModule, GUIModChangeType> >, RelationshipResolverOptions>(
                    m_Changeset, install_ops));
            m_Changeset = null;

            UpdateChangesDialog(null, m_InstallWorker);
            ShowWaitDialog();
        }
Beispiel #10
0
        private void minimizeNotifyIcon_BalloonTipClicked(object sender, EventArgs e)
        {
            // Unminimize
            OpenWindow();

            // Check all the upgrade checkboxes
            ManageMods.MarkAllUpdates();

            // Install
            installWorker.RunWorkerAsync(
                new KeyValuePair <List <ModChange>, RelationshipResolverOptions>(
                    ManageMods.mainModList.ComputeUserChangeSet(RegistryManager.Instance(Main.Instance.CurrentInstance).registry).ToList(),
                    RelationshipResolver.DependsOnlyOpts()
                    )
                );
        }
Beispiel #11
0
        /// <summary>
        /// Tries to get every mod in the Dictionary, which can be installed
        /// It also transforms the Recommender list to a string
        /// </summary>
        /// <param name="mods"></param>
        /// <returns></returns>
        private Dictionary <CkanModule, string> GetShowableMods(Dictionary <string, List <string> > mods)
        {
            Dictionary <CkanModule, string> modules = new Dictionary <CkanModule, string>();

            var opts = new RelationshipResolverOptions
            {
                with_all_suggests              = false,
                with_recommends                = false,
                with_suggests                  = false,
                without_enforce_consistency    = false,
                without_toomanyprovides_kraken = true
            };

            foreach (var pair in mods)
            {
                CkanModule module;

                try
                {
                    var resolver = new RelationshipResolver(new List <string> {
                        pair.Key
                    }, opts,
                                                            RegistryManager.Instance(manager.CurrentInstance).registry, CurrentInstance.VersionCriteria());
                    if (!resolver.ModList().Any())
                    {
                        continue;
                    }

                    module = RegistryManager.Instance(manager.CurrentInstance)
                             .registry.LatestAvailable(pair.Key, CurrentInstance.VersionCriteria());
                }
                catch
                {
                    continue;
                }

                if (module == null)
                {
                    continue;
                }
                modules.Add(module, String.Join(",", pair.Value.ToArray()));
            }
            return(modules);
        }
Beispiel #12
0
 /// <summary>
 /// Tries to get every mod in the Dictionary, which can be installed
 /// It also transforms the Recommender list to a string
 /// </summary>
 /// <param name="mods">Map from recommendations to lists of recommenders</param>
 /// <param name="registry">Registry of current game instance</param>
 /// <param name="versionCriteria">Versions compatible with current instance</param>
 /// <param name="toInstall">Modules planned to be installed</param>
 /// <returns>Map from installable recommendations to string describing recommenders</returns>
 private Dictionary <CkanModule, string> GetShowableMods(
     Dictionary <CkanModule, List <string> > mods,
     IRegistryQuerier registry,
     KspVersionCriteria versionCriteria,
     HashSet <CkanModule> toInstall
     )
 {
     return(mods.Where(kvp => CanInstall(
                           registry, versionCriteria,
                           RelationshipResolver.DependsOnlyOpts(),
                           toInstall.ToList().Concat(new List <CkanModule>()
     {
         kvp.Key
     }).ToList()
                           )).ToDictionary(
                kvp => kvp.Key,
                kvp => string.Join(", ", kvp.Value.ToArray())
                ));
 }
Beispiel #13
0
 /// <summary>
 /// Initiate the GUI installer flow for one specific module
 /// </summary>
 /// <param name="registry">Reference to the registry</param>
 /// <param name="module">Module to install</param>
 public async void InstallModuleDriver(IRegistryQuerier registry, CkanModule module)
 {
     try
     {
         var             userChangeSet = new List <ModChange>();
         InstalledModule installed     = registry.InstalledModule(module.identifier);
         if (installed != null)
         {
             // Already installed, remove it first
             userChangeSet.Add(new ModChange(
                                   new GUIMod(installed.Module, registry, CurrentInstance.VersionCriteria()),
                                   GUIModChangeType.Remove,
                                   null
                                   ));
         }
         // Install the selected mod
         userChangeSet.Add(new ModChange(
                               new GUIMod(module, registry, CurrentInstance.VersionCriteria()),
                               GUIModChangeType.Install,
                               null
                               ));
         if (userChangeSet.Count > 0)
         {
             // Resolve the provides relationships in the dependencies
             installWorker.RunWorkerAsync(
                 new KeyValuePair <List <ModChange>, RelationshipResolverOptions>(
                     userChangeSet,
                     RelationshipResolver.DependsOnlyOpts()
                     )
                 );
         }
     }
     catch
     {
         // If we failed, do the clean-up normally done by PostInstallMods.
         HideWaitDialog(false);
         menuStrip1.Enabled = true;
     }
     finally
     {
         changeSet = null;
     }
 }
Beispiel #14
0
        private void ConfirmChangesButton_Click(object sender, EventArgs e)
        {
            if (changeSet == null)
            {
                return;
            }

            menuStrip1.Enabled = false;
            RetryCurrentActionButton.Visible = false;

            //Using the changeset passed in can cause issues with versions.
            // An example is Mechjeb for FAR at 25/06/2015 with a 1.0.2 install.
            // TODO Work out why this is.
            installWorker.RunWorkerAsync(
                new KeyValuePair <List <ModChange>, RelationshipResolverOptions>(
                    mainModList.ComputeUserChangeSet().ToList(),
                    RelationshipResolver.DependsOnlyOpts()
                    )
                );
        }
Beispiel #15
0
        /// <summary>
        /// Is the mod installed and does it have a newer version compatible with version
        /// We can't update AD mods
        /// </summary>
        public static bool HasUpdate(this IRegistryQuerier querier, string identifier, GameVersionCriteria version)
        {
            CkanModule newest_version;

            try
            {
                newest_version = querier.LatestAvailable(identifier, version);
            }
            catch (Exception)
            {
                return(false);
            }
            if (newest_version == null ||
                !querier.IsInstalled(identifier, false) ||
                !newest_version.version.IsGreaterThan(querier.InstalledVersion(identifier)))
            {
                return(false);
            }
            // All quick checks pass. Now check the relationships.
            try
            {
                var instMod = querier.InstalledModule(identifier);
                RelationshipResolver resolver = new RelationshipResolver(
                    new CkanModule[] { newest_version },
                    // Remove the old module when installing the new one
                    instMod == null ? null : new CkanModule[] { instMod.Module },
                    new RelationshipResolverOptions()
                {
                    with_recommends = false,
                    without_toomanyprovides_kraken = true,
                },
                    querier,
                    version
                    );
            }
            catch (Exception)
            {
                return(false);
            }
            return(true);
        }
Beispiel #16
0
        private void AuditRecommendations(IRegistryQuerier registry, KspVersionCriteria versionCriteria)
        {
            var recommended = new Dictionary <CkanModule, List <string> >();
            var suggested   = new Dictionary <CkanModule, List <string> >();
            var toInstall   = new HashSet <CkanModule>();

            // Find recommendations and suggestions
            foreach (var mod in registry.InstalledModules.Select(im => im.Module))
            {
                AddMod(mod.recommends, recommended, mod.identifier, registry, toInstall);
                AddMod(mod.suggests, suggested, mod.identifier, registry, toInstall);
            }

            if (!recommended.Any() && !suggested.Any())
            {
                GUI.user.RaiseError("No recommendations or suggestions found.");
                return;
            }

            // Prompt user to choose
            installCanceled = false;
            ShowSelection(recommended, toInstall);
            ShowSelection(suggested, toInstall, true);
            tabController.HideTab("ChooseRecommendedModsTabPage");

            // Install
            if (!installCanceled && toInstall.Any())
            {
                installWorker.RunWorkerAsync(
                    new KeyValuePair <List <ModChange>, RelationshipResolverOptions>(
                        toInstall.Select(mod => new ModChange(
                                             new GUIMod(mod, registry, versionCriteria),
                                             GUIModChangeType.Install,
                                             null
                                             )).ToList(),
                        RelationshipResolver.DefaultOpts()
                        )
                    );
            }
        }
Beispiel #17
0
        /// <summary>
        /// Is the mod installed and does it have a newer version compatible with version
        /// We can't update AD mods
        /// </summary>
        public static bool HasUpdate(this IRegistryQuerier querier, string identifier, KspVersionCriteria version)
        {
            CkanModule newest_version;

            try
            {
                newest_version = querier.LatestAvailable(identifier, version);
            }
            catch (Exception)
            {
                return(false);
            }
            if (newest_version == null ||
                !querier.IsInstalled(identifier, false) ||
                querier.InstalledDlls.Contains(identifier) ||
                !newest_version.version.IsGreaterThan(querier.InstalledVersion(identifier)))
            {
                return(false);
            }
            // All quick checks pass. Now check the relationships.
            try
            {
                RelationshipResolver resolver = new RelationshipResolver(
                    new CkanModule[] { newest_version },
                    null,
                    new RelationshipResolverOptions()
                {
                    with_recommends = false,
                    without_toomanyprovides_kraken = true,
                },
                    querier,
                    version
                    );
            }
            catch (Exception)
            {
                return(false);
            }
            return(true);
        }
Beispiel #18
0
        private void AuditRecommendations(IRegistryQuerier registry, GameVersionCriteria versionCriteria)
        {
            var installer = ModuleInstaller.GetInstance(CurrentInstance, Manager.Cache, currentUser);

            if (installer.FindRecommendations(
                    registry.InstalledModules.Select(im => im.Module).ToHashSet(),
                    new HashSet <CkanModule>(),
                    registry as 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, new HashSet <CkanModule>(), new HashSet <CkanModule>(),
                    versionCriteria, Manager.Cache,
                    recommendations, suggestions, supporters);
                var result = ChooseRecommendedMods.Wait();
                tabController.HideTab("ChooseRecommendedModsTabPage");
                if (result != null && result.Any())
                {
                    installWorker.RunWorkerAsync(
                        new KeyValuePair <List <ModChange>, RelationshipResolverOptions>(
                            result.Select(mod => new ModChange(
                                              mod,
                                              GUIModChangeType.Install,
                                              null
                                              )).ToList(),
                            RelationshipResolver.DependsOnlyOpts()
                            )
                        );
                }
            }
            else
            {
                currentUser.RaiseError(Properties.Resources.MainRecommendationsNoneFound);
            }
        }
Beispiel #19
0
        public void Constructor_ProvidesSatisfyDependencies()
        {
            var list = new List<string>();
            var mod_a = generator.GeneratorRandomModule();
            var mod_b = generator.GeneratorRandomModule(provides: new List<string>
            {
                mod_a.identifier
            });
            var depender = generator.GeneratorRandomModule(depends: new List<RelationshipDescriptor>
            {
                new RelationshipDescriptor {name = mod_a.identifier}
            });
            list.Add(depender.identifier);
            AddToRegistry(mod_b, depender);
            var relationship_resolver = new RelationshipResolver(list, options, registry, null);

            CollectionAssert.AreEquivalent(relationship_resolver.ModList(), new List<CkanModule>
            {
                mod_b,
                depender
            });
        }
Beispiel #20
0
        /// <summary>
        /// Returns mods that we require to install the selected module.
        /// This returns null if we can't compute these without user input,
        /// or if the mods conflict.
        /// </summary>
        private List <CkanModule> GetInstallDependencies(CkanModule module, RelationshipResolverOptions options)
        {
            var tmp = new List <string>();

            tmp.Add(module.identifier);

            RelationshipResolver resolver = null;

            try
            {
                resolver = new RelationshipResolver(tmp, options, RegistryManager.Instance(KSPManager.CurrentInstance).registry);
            }
            catch (Kraken kraken)
            {
                // TODO: Both of these krakens contain extra information; either a list of
                // mods the user can choose from, or a list of inconsistencies that are blocking
                // this selection. We *should* display those to the user. See GH #345.
                if (kraken is TooManyModsProvideKraken || kraken is InconsistentKraken)
                {
                    // Expected krakens.
                    return(null);
                }
                else if (kraken is ModuleNotFoundKraken)
                {
                    var not_found = (ModuleNotFoundKraken)kraken;
                    log.ErrorFormat(
                        "Can't find {0}, but {1} depends on it",
                        not_found.module, module
                        );
                    return(null);
                }

                log.ErrorFormat("Unexpected Kraken in GetInstallDeps: {0}", kraken.GetType());
                return(null);
            }

            return(resolver.ModList());
        }
Beispiel #21
0
        /// <summary>
        /// Tries to get every mod in the Dictionary, which can be installed
        /// It also transforms the Recommender list to a string
        /// </summary>
        /// <param name="mods"></param>
        /// <returns></returns>
        private Dictionary <CkanModule, string> GetShowableMods(Dictionary <CkanModule, List <string> > mods)
        {
            Dictionary <CkanModule, string> modules = new Dictionary <CkanModule, string>();

            var opts = new RelationshipResolverOptions
            {
                with_all_suggests              = false,
                with_recommends                = false,
                with_suggests                  = false,
                without_enforce_consistency    = false,
                without_toomanyprovides_kraken = true
            };

            foreach (var pair in mods)
            {
                try
                {
                    RelationshipResolver resolver = new RelationshipResolver(
                        new List <CkanModule> {
                        pair.Key
                    },
                        null,
                        opts,
                        RegistryManager.Instance(manager.CurrentInstance).registry,
                        CurrentInstance.VersionCriteria()
                        );

                    if (resolver.ModList().Any())
                    {
                        // Resolver was able to find a way to install, so show it to the user
                        modules.Add(pair.Key, String.Join(",", pair.Value.ToArray()));
                    }
                }
                catch { }
            }
            return(modules);
        }
Beispiel #22
0
        private void Changeset_OnConfirmChanges()
        {
            menuStrip1.Enabled = false;

            // Using the changeset passed in can cause issues with versions.
            // An example is Mechjeb for FAR at 25/06/2015 with a 1.0.2 install.
            // TODO Work out why this is.
            try
            {
                installWorker.RunWorkerAsync(
                    new KeyValuePair <List <ModChange>, RelationshipResolverOptions>(
                        ManageMods.mainModList
                        .ComputeUserChangeSet(RegistryManager.Instance(Main.Instance.CurrentInstance).registry)
                        .ToList(),
                        RelationshipResolver.DependsOnlyOpts()
                        )
                    );
            }
            catch (InvalidOperationException)
            {
                // Thrown if it's already busy, can happen if the user fouble-clicks the button. Ignore it.
                // More thread-safe than checking installWorker.IsBusy beforehand.
            }
        }
Beispiel #23
0
        /// <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);
        }
Beispiel #24
0
        public void InstallList(List <string> modules, RelationshipResolverOptions options, IDownloader downloader = null)
        {
            var resolver = new RelationshipResolver(modules, options, registry_manager.registry, ksp.VersionCriteria());

            InstallList(resolver.ModList().ToList(), options, downloader);
        }
Beispiel #25
0
        /// <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);
        }
Beispiel #26
0
        private async void installFromckanToolStripMenuItem_Click(object sender, EventArgs e)
        {
            OpenFileDialog open_file_dialog = new OpenFileDialog {
                Filter = Resources.CKANFileFilter
            };

            if (open_file_dialog.ShowDialog() == DialogResult.OK)
            {
                var        path = open_file_dialog.FileName;
                CkanModule module;

                try
                {
                    module = CkanModule.FromFile(path);
                }
                catch (Kraken kraken)
                {
                    currentUser.RaiseError(kraken.InnerException == null
                        ? kraken.Message
                        : $"{kraken.Message}: {kraken.InnerException.Message}");

                    return;
                }
                catch (Exception ex)
                {
                    currentUser.RaiseError(ex.Message);
                    return;
                }

                // We'll need to make some registry changes to do this.
                RegistryManager registry_manager = RegistryManager.Instance(CurrentInstance);

                // Remove this version of the module in the registry, if it exists.
                registry_manager.registry.RemoveAvailable(module);

                // Sneakily add our version in...
                registry_manager.registry.AddAvailable(module);

                menuStrip1.Enabled = false;

                RelationshipResolverOptions install_ops = RelationshipResolver.DefaultOpts();
                install_ops.with_recommends = false;

                try
                {
                    // Resolve the provides relationships in the dependencies
                    List <ModChange> fullChangeSet = new List <ModChange>(
                        await mainModList.ComputeChangeSetFromModList(
                            registry_manager.registry,
                            new HashSet <ModChange>()
                    {
                        new ModChange(
                            new GUIMod(
                                module,
                                registry_manager.registry,
                                CurrentInstance.VersionCriteria()
                                ),
                            GUIModChangeType.Install,
                            null
                            )
                    },
                            ModuleInstaller.GetInstance(CurrentInstance, GUI.user),
                            CurrentInstance.VersionCriteria()
                            )
                        );
                    if (fullChangeSet != null && fullChangeSet.Count > 0)
                    {
                        installWorker.RunWorkerAsync(
                            new KeyValuePair <List <ModChange>, RelationshipResolverOptions>(
                                fullChangeSet,
                                install_ops
                                )
                            );
                        ShowWaitDialog();
                    }
                }
                catch
                {
                    // If we failed, do the clean-up normally done by PostInstallMods.
                    HideWaitDialog(false);
                    menuStrip1.Enabled = true;
                }
                finally
                {
                    changeSet = null;
                }
            }
        }
Beispiel #27
0
        /// <summary>
        /// Determine whether there is any way to install the given set of mods.
        /// Handles virtual dependencies, including recursively.
        /// </summary>
        /// <param name="registry">Registry of instance into which we want to install</param>
        /// <param name="versionCriteria">Compatible versions of instance</param>
        /// <param name="opts">Installer options</param>
        /// <param name="toInstall">Mods we want to install</param>
        /// <returns>
        /// True if it's possible to install these mods, false otherwise
        /// </returns>
        private bool CanInstall(
            IRegistryQuerier registry,
            KspVersionCriteria versionCriteria,
            RelationshipResolverOptions opts,
            List <CkanModule> toInstall
            )
        {
            string request = toInstall.Select(m => m.identifier).Aggregate((a, b) => $"{a}, {b}");

            try
            {
                RelationshipResolver resolver = new RelationshipResolver(
                    toInstall,
                    null,
                    opts, registry, versionCriteria
                    );

                if (resolver.ModList().Count() >= toInstall.Count(m => !m.IsMetapackage))
                {
                    // We can install with no further dependencies
                    string recipe = resolver.ModList()
                                    .Select(m => m.identifier)
                                    .Aggregate((a, b) => $"{a}, {b}");
                    log.Debug($"Installable: {request}: {recipe}");
                    return(true);
                }
                else
                {
                    string problems = resolver.ConflictList.Values
                                      .Aggregate((a, b) => $"{a}, {b}");
                    log.Debug($"Can't install {request}: {problems}");
                    return(false);
                }
            }
            catch (TooManyModsProvideKraken k)
            {
                // One of the dependencies is virtual
                foreach (CkanModule mod in k.modules)
                {
                    // Try each option recursively to see if any are successful
                    if (CanInstall(registry, versionCriteria, opts, toInstall.Concat(new List <CkanModule>()
                    {
                        mod
                    }).ToList()))
                    {
                        // Child call will emit debug output, so we don't need to here
                        return(true);
                    }
                }
                log.Debug($"Can't install {request}: Can't install provider of {k.requested}");
            }
            catch (InconsistentKraken k)
            {
                log.Debug($"Can't install {request}: {k.ShortDescription}");
            }
            catch (Exception ex)
            {
                log.Debug($"Can't install {request}: {ex.Message}");
            }
            return(false);
        }
Beispiel #28
0
        /// <summary>
        /// Tries to get every mod in the Dictionary, which can be installed
        /// It also transforms the Recommender list to a string
        /// </summary>
        /// <param name="mods"></param>
        /// <returns></returns>
        private Dictionary<CkanModule, string> GetShowableMods(Dictionary<string, List<string>> mods)
        {
            Dictionary<CkanModule, string> modules = new Dictionary<CkanModule, string>();

            var opts = new RelationshipResolverOptions
            {
                with_all_suggests = false,
                with_recommends = false,
                with_suggests = false,
                without_enforce_consistency = false,
                without_toomanyprovides_kraken = true
            };

            foreach (var pair in mods)
            {
                CkanModule module;

                try
                {
                    var resolver = new RelationshipResolver(new List<string> { pair.Key }, opts,
                        RegistryManager.Instance(manager.CurrentInstance).registry, CurrentInstance.Version());
                    if (!resolver.ModList().Any())
                    {
                        continue;
                    }

                    module = RegistryManager.Instance(manager.CurrentInstance)
                        .registry.LatestAvailable(pair.Key, CurrentInstance.Version());
                }
                catch
                {
                    continue;
                }

                if (module == null)
                {
                    continue;
                }
                modules.Add(module, String.Join(",", pair.Value.ToArray()));
            }
            return modules;
        }
Beispiel #29
0
        public static Dictionary <GUIMod, string> ComputeConflictsFromModList(IRegistryQuerier registry,
                                                                              IEnumerable <ModChange> change_set, GameVersionCriteria ksp_version)
        {
            var modules_to_install = new HashSet <string>();
            var modules_to_remove  = new HashSet <string>();
            var options            = new RelationshipResolverOptions
            {
                without_toomanyprovides_kraken = true,
                proceed_with_inconsistencies   = true,
                without_enforce_consistency    = true,
                with_recommends = false
            };

            foreach (var change in change_set)
            {
                switch (change.ChangeType)
                {
                case GUIModChangeType.None:
                    break;

                case GUIModChangeType.Install:
                    modules_to_install.Add(change.Mod.identifier);
                    break;

                case GUIModChangeType.Remove:
                    modules_to_remove.Add(change.Mod.identifier);
                    break;

                case GUIModChangeType.Update:
                    break;

                case GUIModChangeType.Replace:
                    ModuleReplacement repl = registry.GetReplacement(change.Mod, ksp_version);
                    if (repl != null)
                    {
                        modules_to_remove.Add(repl.ToReplace.identifier);
                        modules_to_install.Add(repl.ReplaceWith.identifier);
                    }
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }
            }

            // Only check mods that would exist after the changes are made.
            IEnumerable <CkanModule> installed = registry.InstalledModules.Where(
                im => !modules_to_remove.Contains(im.Module.identifier)
                ).Select(im => im.Module);

            // Convert ONLY modules_to_install with CkanModule.FromIDandVersion,
            // because it may not find already-installed modules.
            IEnumerable <CkanModule> mods_to_check = installed.Union(
                modules_to_install.Except(modules_to_remove).Select(
                    name => CkanModule.FromIDandVersion(registry, name, ksp_version)
                    )
                );
            var resolver = new RelationshipResolver(
                mods_to_check,
                change_set.Where(ch => ch.ChangeType == GUIModChangeType.Remove)
                .Select(ch => ch.Mod),
                options, registry, ksp_version
                );

            return(resolver.ConflictList.ToDictionary(item => new GUIMod(item.Key, registry, ksp_version),
                                                      item => item.Value));
        }
Beispiel #30
0
        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);
        }
Beispiel #31
0
        public void ModList_WithInstalledModulesSugested_DoesNotContainThem()
        {
            options.with_all_suggests = true;
            var list = new List<string>();
            var sugested = generator.GeneratorRandomModule();
            var sugester = generator.GeneratorRandomModule(sugests: new List<RelationshipDescriptor>
            {
                new RelationshipDescriptor {name = sugested.identifier}
            });

            list.Add(sugester.identifier);
            AddToRegistry(sugester, sugested);
            registry.Installed().Add(sugested.identifier, sugested.version);

            var relationship_resolver = new RelationshipResolver(list, options, registry, null);
            CollectionAssert.Contains(relationship_resolver.ModList(), sugested);
        }
Beispiel #32
0
        /// <summary>
        /// Upgrades the mods listed to the latest versions for the user's KSP.
        /// Will *re-install* with warning even if an upgrade is not available.
        /// Throws ModuleNotFoundKraken if module is not installed, or not available.
        /// </summary>
        public void Upgrade(IEnumerable<string> identifiers, NetAsyncModulesDownloader netAsyncDownloader, bool enforceConsistency = true)
        {
            var options = new RelationshipResolverOptions();

            // We do not wish to pull in any suggested or recommended mods.
            options.with_recommends = false;
            options.with_suggests = false;

            var resolver = new RelationshipResolver(identifiers.ToList(), options, registry_manager.registry, ksp.VersionCriteria());
            Upgrade(resolver.ModList(), netAsyncDownloader, enforceConsistency);
        }
Beispiel #33
0
        public void Constructor_WithDependantVersion_ChooseCorrectly(string ver, string dep, string other)
        {
            var list = new List<string>();
            var dependant = generator.GeneratorRandomModule(version: new Version(ver));
            var other_dependant = generator.GeneratorRandomModule(identifier: dependant.identifier, version: new Version(other));

            var depender = generator.GeneratorRandomModule(depends: new List<RelationshipDescriptor>
            {
                new RelationshipDescriptor {name = dependant.identifier, version = new Version(dep)}
            });

            list.Add(depender.identifier);
            AddToRegistry(depender, dependant, other_dependant);

            var relationship_resolver = new RelationshipResolver(list, options, registry, null);
            CollectionAssert.AreEquivalent(relationship_resolver.ModList(), new List<CkanModule>
            {
                dependant,
                depender
            });
        }
Beispiel #34
0
        public void InstallList(
            List<string> modules,
            RelationshipResolverOptions options,
            IDownloader downloader = null
        )
        {
            var resolver = new RelationshipResolver(modules, options, registry_manager.registry, ksp.Version());
            List<CkanModule> modsToInstall = resolver.ModList();

            InstallList(modsToInstall, options, downloader);
        }
Beispiel #35
0
        /// <summary>
        ///     Installs all modules given a list of identifiers as a transaction. Resolves dependencies.
        ///     This *will* save the registry at the end of operation.
        ///
        /// Propagates a BadMetadataKraken if our install metadata is bad.
        /// Propagates a FileExistsKraken if we were going to overwrite a file.
        /// Propagates a CancelledActionKraken if the user cancelled the install.
        /// </summary>
        //
        // TODO: Break this up into smaller pieces! It's huge!
        public void InstallList(
            ICollection<CkanModule> modules,
            RelationshipResolverOptions options,
            IDownloader downloader = null
        )
        {
            var resolver = new RelationshipResolver(modules, options, registry_manager.registry, ksp.Version());
            List<CkanModule> modsToInstall = resolver.ModList();
            List<CkanModule> downloads = new List<CkanModule> ();

            // TODO: All this user-stuff should be happening in another method!
            // We should just be installing mods as a transaction.

            User.RaiseMessage("About to install...\n");

            foreach (CkanModule module in modsToInstall)
            {
                if (!ksp.Cache.IsCachedZip(module.download))
                {
                    User.RaiseMessage(" * {0} {1}", module.name, module.version);
                    downloads.Add(module);
                }
                else
                {
                    User.RaiseMessage(" * {0} {1}(cached)", module.name, module.version);
                }
            }

            bool ok = User.RaiseYesNoDialog("\nContinue?");

            if (!ok)
            {
                throw new CancelledActionKraken("User declined install list");
            }

            User.RaiseMessage(String.Empty); // Just to look tidy.

            if (downloads.Count > 0)
            {
                if (downloader == null)
                {
                    downloader = new NetAsyncDownloader(User);
                }

                downloader.DownloadModules(ksp.Cache, downloads);
            }

            // We're about to install all our mods; so begin our transaction.
            using (TransactionScope transaction = CkanTransaction.CreateTransactionScope())
            {
                for (int i = 0; i < modsToInstall.Count; i++)
                {
                    int percent_complete = (i * 100) / modsToInstall.Count;

                    User.RaiseProgress(String.Format("Installing mod \"{0}\"", modsToInstall[i]),
                                         percent_complete);

                    Install(modsToInstall[i]);
                }

                User.RaiseProgress("Updating registry", 70);

                registry_manager.Save(!options.without_enforce_consistency);

                User.RaiseProgress("Commiting filesystem changes", 80);

                transaction.Complete();

            }

            // We can scan GameData as a separate transaction. Installing the mods
            // leaves everything consistent, and this is just gravy. (And ScanGameData
            // acts as a Tx, anyway, so we don't need to provide our own.)

            User.RaiseProgress("Rescanning GameData", 90);

            if (!options.without_enforce_consistency)
            {
                ksp.ScanGameData();
            }

            User.RaiseProgress("Done!\n", 100);
        }
Beispiel #36
0
        /// <summary>
        /// Upgrades the mods listed to the latest versions for the user's KSP.
        /// Will *re-install* with warning even if an upgrade is not available.
        /// Throws ModuleNotFoundKraken if module is not installed, or not available.
        /// </summary>
        public void Upgrade(IEnumerable<string> identifiers, IDownloader netAsyncDownloader)
        {
            var options = new RelationshipResolverOptions();

            // We do not wish to pull in any suggested or recommended mods.
            options.with_recommends = false;
            options.with_suggests = false;

            var resolver = new RelationshipResolver(identifiers.ToList(), options, registry_manager.registry, ksp.Version());
            List<CkanModule> upgrades = resolver.ModList();

            Upgrade(upgrades, netAsyncDownloader);
        }
Beispiel #37
0
        /// <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;
        }
Beispiel #38
0
        public void ModList_WithInstalledModules_DoesNotContainThem()
        {
            var list = new List<string>();
            var mod_a = generator.GeneratorRandomModule();
            list.Add(mod_a.identifier);
            AddToRegistry(mod_a);
            registry.Installed().Add(mod_a.identifier, mod_a.version);

            var relationship_resolver = new RelationshipResolver(list, options, registry, null);
            CollectionAssert.IsEmpty(relationship_resolver.ModList());
        }
Beispiel #39
0
        /// <summary>
        ///     Installs all modules given a list of identifiers as a transaction. Resolves dependencies.
        ///     This *will* save the registry at the end of operation.
        ///
        /// Propagates a BadMetadataKraken if our install metadata is bad.
        /// Propagates a FileExistsKraken if we were going to overwrite a file.
        /// Propagates a CancelledActionKraken if the user cancelled the install.
        /// </summary>
        //
        // TODO: Break this up into smaller pieces! It's huge!
        public void InstallList(
            ICollection <CkanModule> modules,
            RelationshipResolverOptions options,
            IDownloader downloader = null
            )
        {
            var resolver = new RelationshipResolver(modules, options, registry_manager.registry, ksp.Version());
            List <CkanModule> modsToInstall = resolver.ModList();
            List <CkanModule> downloads     = new List <CkanModule> ();

            // TODO: All this user-stuff should be happening in another method!
            // We should just be installing mods as a transaction.

            User.RaiseMessage("About to install...\n");

            foreach (CkanModule module in modsToInstall)
            {
                if (!ksp.Cache.IsCachedZip(module.download))
                {
                    User.RaiseMessage(" * {0}", module);
                    downloads.Add(module);
                }
                else
                {
                    User.RaiseMessage(" * {0} (cached)", module);
                }
            }

            bool ok = User.RaiseYesNoDialog("\nContinue?");

            if (!ok)
            {
                throw new CancelledActionKraken("User declined install list");
            }

            User.RaiseMessage(String.Empty); // Just to look tidy.

            if (downloads.Count > 0)
            {
                if (downloader == null)
                {
                    downloader = new NetAsyncDownloader(User);
                }

                downloader.DownloadModules(ksp.Cache, downloads);
            }

            // We're about to install all our mods; so begin our transaction.
            using (TransactionScope transaction = CkanTransaction.CreateTransactionScope())
            {
                for (int i = 0; i < modsToInstall.Count; i++)
                {
                    int percent_complete = (i * 100) / modsToInstall.Count;

                    User.RaiseProgress(String.Format("Installing mod \"{0}\"", modsToInstall[i]),
                                       percent_complete);

                    Install(modsToInstall[i]);
                }

                User.RaiseProgress("Updating registry", 70);

                registry_manager.Save(!options.without_enforce_consistency);

                User.RaiseProgress("Commiting filesystem changes", 80);

                transaction.Complete();
            }

            // We can scan GameData as a separate transaction. Installing the mods
            // leaves everything consistent, and this is just gravy. (And ScanGameData
            // acts as a Tx, anyway, so we don't need to provide our own.)

            User.RaiseProgress("Rescanning GameData", 90);

            if (!options.without_enforce_consistency)
            {
                ksp.ScanGameData();
            }

            User.RaiseProgress("Done!\n", 100);
        }
Beispiel #40
0
        public void ModList_WithSugestedModulesThatWouldConflict_DoesNotContainThem()
        {
            options.with_all_suggests = true;
            var list = new List<string>();
            var sugested = generator.GeneratorRandomModule();
            var mod = generator.GeneratorRandomModule(conflicts: new List<RelationshipDescriptor>
            {
                new RelationshipDescriptor {name = sugested.identifier}
            });
            var sugester = generator.GeneratorRandomModule(sugests: new List<RelationshipDescriptor>
            {
                new RelationshipDescriptor {name = sugested.identifier}
            });

            list.Add(sugester.identifier);
            list.Add(mod.identifier);
            AddToRegistry(sugester, sugested, mod);

            var relationship_resolver = new RelationshipResolver(list, options, registry, null);
            CollectionAssert.DoesNotContain(relationship_resolver.ModList(), sugested);
        }
Beispiel #41
0
        /// <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);
        }
Beispiel #42
0
        public void ReasonFor_WithModsNotInList_ThrowsArgumentException()
        {
            var list = new List<string>();
            var mod = generator.GeneratorRandomModule();
            list.Add(mod.identifier);
            registry.AddAvailable(mod);
            AddToRegistry(mod);
            var relationship_resolver = new RelationshipResolver(list, options, registry, null);

            var mod_not_in_resolver_list = generator.GeneratorRandomModule();
            CollectionAssert.DoesNotContain(relationship_resolver.ModList(),mod_not_in_resolver_list);
            Assert.Throws<ArgumentException>(() => relationship_resolver.ReasonFor(mod_not_in_resolver_list));
        }
Beispiel #43
0
        private void UpdateRecommendedDialog(Dictionary<string, List<string>> mods, bool suggested = false)
        {
            if (!suggested)
            {
                RecommendedDialogLabel.Text =
                    "The following modules have been recommended by one or more of the chosen modules:";
                RecommendedModsListView.Columns[1].Text = "Recommended by:";
                RecommendedModsToggleCheckbox.Text = "(De-)select all recommended mods.";
                RecommendedModsToggleCheckbox.Checked=true;
                m_TabController.RenameTab("ChooseRecommendedModsTabPage", "Choose recommended mods");
            }
            else
            {
                RecommendedDialogLabel.Text =
                    "The following modules have been suggested by one or more of the chosen modules:";
                RecommendedModsListView.Columns[1].Text = "Suggested by:";
                RecommendedModsToggleCheckbox.Text = "(De-)select all suggested mods.";
                RecommendedModsToggleCheckbox.Checked=false;
                m_TabController.RenameTab("ChooseRecommendedModsTabPage", "Choose suggested mods");
            }

            RecommendedModsListView.Items.Clear();

            foreach (var pair in mods)
            {
                Module module;

                try
                {
                    var opts = new RelationshipResolverOptions
                    {
                        with_all_suggests = false,
                        with_recommends = false,
                        with_suggests = false,
                        without_enforce_consistency = false,
                        without_toomanyprovides_kraken = true
                    };

                    var resolver = new RelationshipResolver(new List<string> {pair.Key}, opts,
                        RegistryManager.Instance(manager.CurrentInstance).registry, CurrentInstance.Version());
                    if (!resolver.ModList().Any())
                    {
                        continue;
                    }

                    module = RegistryManager.Instance(manager.CurrentInstance)
                        .registry.LatestAvailable(pair.Key, CurrentInstance.Version());
                }
                catch
                {
                    continue;
                }

                if (module == null)
                {
                    continue;
                }

                ListViewItem item = new ListViewItem {Tag = module, Checked = !suggested, Text = pair.Key};

                ListViewItem.ListViewSubItem recommendedBy = new ListViewItem.ListViewSubItem();
                string recommendedByString = "";

                bool first = true;
                foreach (string mod in pair.Value)
                {
                    if (!first)
                    {
                        recommendedByString += ", ";
                    }
                    else
                    {
                        first = false;
                    }

                    recommendedByString += mod;
                }

                recommendedBy.Text = recommendedByString;

                item.SubItems.Add(recommendedBy);

                ListViewItem.ListViewSubItem description = new ListViewItem.ListViewSubItem {Text = module.@abstract};

                item.SubItems.Add(description);

                RecommendedModsListView.Items.Add(item);
            }
        }
Beispiel #44
0
        public void ReasonFor_WithTreeOfMods_GivesCorrectParents()
        {
            var list = new List<string>();
            var sugested = generator.GeneratorRandomModule();
            var recommendedA = generator.GeneratorRandomModule();
            var recommendedB = generator.GeneratorRandomModule();
            var mod = generator.GeneratorRandomModule(sugests: new List<RelationshipDescriptor> { new RelationshipDescriptor { name = sugested.identifier}});
            list.Add(mod.identifier);
            sugested.recommends = new List<RelationshipDescriptor>
            { new RelationshipDescriptor {name=recommendedA.identifier},
              new RelationshipDescriptor { name = recommendedB.identifier}};

            AddToRegistry(mod, sugested,recommendedA,recommendedB);

            options.with_all_suggests = true;
            options.with_recommends = true;
            var relationship_resolver = new RelationshipResolver(list, options, registry, null);
            var reason = relationship_resolver.ReasonFor(recommendedA);
            Assert.That(reason, Is.AssignableTo<SelectionReason.Recommended>());
            Assert.That(reason.Parent, Is.EqualTo(sugested));

            reason = relationship_resolver.ReasonFor(recommendedB);
            Assert.That(reason, Is.AssignableTo<SelectionReason.Recommended>());
            Assert.That(reason.Parent, Is.EqualTo(sugested));
        }
Beispiel #45
0
        /// <summary>
        ///     Installs all modules given a list of identifiers as a transaction. Resolves dependencies.
        ///     This *will* save the registry at the end of operation.
        ///
        /// Propagates a BadMetadataKraken if our install metadata is bad.
        /// Propagates a FileExistsKraken if we were going to overwrite a file.
        /// Propagates a CancelledActionKraken if the user cancelled the install.
        /// </summary>
        //
        // TODO: Break this up into smaller pieces! It's huge!
        public void InstallList(
            List <string> modules,
            RelationshipResolverOptions options,
            NetAsyncDownloader downloader = null
            )
        {
            onReportProgress = onReportProgress ?? ((message, progress) => { });

            var resolver = new RelationshipResolver(modules, options, registry_manager.registry);
            List <CkanModule> modsToInstall = resolver.ModList();
            List <CkanModule> downloads     = new List <CkanModule> ();

            // TODO: All this user-stuff should be happening in another method!
            // We should just be installing mods as a transaction.

            User.WriteLine("About to install...\n");

            foreach (CkanModule module in modsToInstall)
            {
                if (!ksp.Cache.IsCachedZip(module.download))
                {
                    User.WriteLine(" * {0}", module);
                    downloads.Add(module);
                }
                else
                {
                    User.WriteLine(" * {0} (cached)", module);
                }
            }

            bool ok = User.YesNo("\nContinue?", FrontEndType.CommandLine);

            if (!ok)
            {
                throw new CancelledActionKraken("User declined install list");
            }

            User.WriteLine(""); // Just to look tidy.

            if (downloads.Count > 0)
            {
                if (downloader == null)
                {
                    downloader = new NetAsyncDownloader();
                }

                downloader.DownloadModules(ksp.Cache, downloads, onReportProgress);
            }

            // We're about to install all our mods; so begin our transaction.
            var txoptions = new TransactionOptions();

            txoptions.Timeout = TransactionManager.MaximumTimeout;

            using (TransactionScope transaction = new TransactionScope(TransactionScopeOption.Required, txoptions))
            {
                for (int i = 0; i < modsToInstall.Count; i++)
                {
                    int percentComplete = (i * 100) / modsToInstall.Count;

                    onReportProgress(String.Format("Installing mod \"{0}\"", modsToInstall[i]),
                                     percentComplete);

                    Install(modsToInstall[i]);
                }

                onReportProgress("Updating registry", 70);

                registry_manager.Save();

                onReportProgress("Commiting filesystem changes", 80);

                transaction.Complete();
            }

            // We can scan GameData as a separate transaction. Installing the mods
            // leaves everything consistent, and this is just gravy. (And ScanGameData
            // acts as a Tx, anyway, so we don't need to provide our own.)

            onReportProgress("Rescanning GameData", 90);

            ksp.ScanGameData();

            onReportProgress("Done!", 100);
        }
Beispiel #46
0
        public void ReasonFor_WithUserAddedMods_GivesReasonUserAdded()
        {
            var list = new List<string>();
            var mod = generator.GeneratorRandomModule();
            list.Add(mod.identifier);
            registry.AddAvailable(mod);
            AddToRegistry(mod);

            var relationship_resolver = new RelationshipResolver(list, options, registry, null);
            var reason = relationship_resolver.ReasonFor(mod);
            Assert.That(reason, Is.AssignableTo<SelectionReason.UserRequested>());
        }
Beispiel #47
0
        private IEnumerable <ListViewItem> getRecSugRows(
            IEnumerable <CkanModule> sourceModules,
            IRegistryQuerier registry,
            HashSet <CkanModule> toInstall
            )
        {
            Dictionary <CkanModule, List <string> > dependersIndex = getDependersIndex(sourceModules, registry, toInstall);

            foreach (CkanModule mod in sourceModules.Where(m => m.recommends != null))
            {
                foreach (RelationshipDescriptor rel in mod.recommends)
                {
                    List <CkanModule> providers = rel.LatestAvailableWithProvides(
                        registry,
                        CurrentInstance.VersionCriteria()
                        );
                    foreach (CkanModule provider in providers)
                    {
                        List <string> dependers;
                        if (!registry.IsInstalled(provider.identifier) &&
                            !toInstall.Any(m => m.identifier == provider.identifier) &&
                            dependersIndex.TryGetValue(provider, out dependers) &&
                            CanInstall(registry, CurrentInstance.VersionCriteria(),
                                       RelationshipResolver.DependsOnlyOpts(),
                                       toInstall.ToList().Concat(new List <CkanModule>()
                        {
                            provider
                        }).ToList()))
                        {
                            dependersIndex.Remove(provider);
                            yield return(getRecSugItem(
                                             provider,
                                             string.Join(", ", dependers),
                                             RecommendationsGroup,
                                             providers.Count <= 1 || provider.identifier == (rel as ModuleRelationshipDescriptor)?.name
                                             ));
                        }
                    }
                }
            }
            foreach (CkanModule mod in sourceModules.Where(m => m.suggests != null))
            {
                foreach (RelationshipDescriptor rel in mod.suggests)
                {
                    List <CkanModule> providers = rel.LatestAvailableWithProvides(
                        registry,
                        CurrentInstance.VersionCriteria()
                        );
                    foreach (CkanModule provider in providers)
                    {
                        List <string> dependers;
                        if (!registry.IsInstalled(provider.identifier) &&
                            !toInstall.Any(m => m.identifier == provider.identifier) &&
                            dependersIndex.TryGetValue(provider, out dependers) &&
                            CanInstall(registry, CurrentInstance.VersionCriteria(),
                                       RelationshipResolver.DependsOnlyOpts(),
                                       toInstall.ToList().Concat(new List <CkanModule>()
                        {
                            provider
                        }).ToList()))
                        {
                            dependersIndex.Remove(provider);
                            yield return(getRecSugItem(
                                             provider,
                                             string.Join(", ", dependers),
                                             SuggestionsGroup,
                                             false
                                             ));
                        }
                    }
                }
            }
        }
Beispiel #48
0
        // this functions computes a changeset from the user's choices in the GUI
        private List <KeyValuePair <CkanModule, GUIModChangeType> > ComputeChangeSetFromModList()
        // this probably needs to be refactored
        {
            var changeset = new HashSet <KeyValuePair <CkanModule, GUIModChangeType> >();

            // these are the lists
            var modulesToInstall = new HashSet <string>();
            var modulesToRemove  = new HashSet <string>();

            Registry registry = RegistryManager.Instance(KSPManager.CurrentInstance).registry;

            foreach (DataGridViewRow row in ModList.Rows)
            {
                var mod = (CkanModule)row.Tag;
                if (mod == null)
                {
                    continue;
                }

                bool isInstalled        = registry.IsInstalled(mod.identifier);
                var  isInstalledCell    = row.Cells[0] as DataGridViewCheckBoxCell;
                var  isInstalledChecked = (bool)isInstalledCell.Value;

                if (!isInstalled && isInstalledChecked)
                {
                    modulesToInstall.Add(mod.identifier);
                }
                else if (isInstalled && !isInstalledChecked)
                {
                    modulesToRemove.Add(mod.identifier);
                }
            }

            RelationshipResolverOptions options = RelationshipResolver.DefaultOpts();

            options.with_recommends = false;
            options.without_toomanyprovides_kraken = true;
            options.without_enforce_consistency    = true;

            RelationshipResolver resolver = null;

            try
            {
                resolver = new RelationshipResolver(modulesToInstall.ToList(), options, registry);
            }
            catch (Exception e)
            {
                return(null);
            }

            foreach (CkanModule mod in resolver.ModList())
            {
                changeset.Add(new KeyValuePair <CkanModule, GUIModChangeType>(mod, GUIModChangeType.Install));
            }

            ModuleInstaller installer = ModuleInstaller.Instance;

            foreach (string moduleName in modulesToRemove)
            {
                var reverseDependencies = installer.FindReverseDependencies(moduleName);
                foreach (string reverseDependency in reverseDependencies)
                {
                    CkanModule mod = registry.LatestAvailable(reverseDependency);
                    changeset.Add(new KeyValuePair <CkanModule, GUIModChangeType>(mod, GUIModChangeType.Remove));
                }
            }

            foreach (DataGridViewRow row in ModList.Rows)
            {
                var mod = (CkanModule)row.Tag;
                if (mod == null)
                {
                    continue;
                }

                bool             isInstalled         = registry.IsInstalled(mod.identifier);
                var              isInstalledCell     = row.Cells[0] as DataGridViewCheckBoxCell;
                var              isInstalledChecked  = (bool)isInstalledCell.Value;
                DataGridViewCell shouldBeUpdatedCell = row.Cells[1];
                bool             shouldBeUpdated     = false;
                if (shouldBeUpdatedCell is DataGridViewCheckBoxCell && shouldBeUpdatedCell.Value != null)
                {
                    shouldBeUpdated = (bool)shouldBeUpdatedCell.Value;
                }

                if (isInstalled && !isInstalledChecked)
                {
                    changeset.Add(new KeyValuePair <CkanModule, GUIModChangeType>(mod, GUIModChangeType.Remove));
                }
                else if (isInstalled && isInstalledChecked &&
                         mod.version.IsGreaterThan(registry.InstalledVersion(mod.identifier)) && shouldBeUpdated)
                {
                    changeset.Add(new KeyValuePair <CkanModule, GUIModChangeType>(mod, GUIModChangeType.Update));
                }
            }

            return(changeset.ToList());
        }