public GUIMod(CkanModule mod, Registry registry, KSPVersion ksp_version) { //Currently anything which could alter these causes a full reload of the modlist // If this is ever changed these could be moved into the properties Mod = mod; IsInstalled = registry.IsInstalled(mod.identifier); IsInstallChecked = IsInstalled; HasUpdate = registry.HasUpdate(mod.identifier); IsIncompatible = !mod.IsCompatibleKSP(ksp_version); IsAutodetected = registry.IsAutodetected(mod.identifier); Authors = mod.author == null ? "N/A" : String.Join(",", mod.author); var installedVersion = registry.InstalledVersion(mod.identifier); var latestVersion = mod.version; var kspVersion = mod.ksp_version; InstalledVersion = installedVersion != null?installedVersion.ToString() : "-"; LatestVersion = latestVersion != null?latestVersion.ToString() : "-"; KSPversion = kspVersion != null?kspVersion.ToString() : "-"; Abstract = mod.@abstract; Homepage = mod.resources != null && mod.resources.homepage != null ? (object)mod.resources.homepage : "N/A"; Identifier = mod.identifier; }
private int CountModsByFilter(GUIModFilter filter) { Registry registry = RegistryManager.Instance(KSPManager.CurrentInstance).registry; List <CkanModule> modules = registry.Available(); int count = modules.Count(); // filter by left menu selection switch (filter) { case GUIModFilter.All: break; case GUIModFilter.Installed: count -= modules.Count(m => !registry.IsInstalled(m.identifier)); break; case GUIModFilter.InstalledUpdateAvailable: count -= modules.Count ( m => !(registry.IsInstalled(m.identifier) && m.version.IsGreaterThan( registry.InstalledVersion(m.identifier))) ); break; case GUIModFilter.NewInRepository: break; case GUIModFilter.NotInstalled: count -= modules.RemoveAll(m => registry.IsInstalled(m.identifier)); break; case GUIModFilter.Incompatible: count = registry.Incompatible().Count; break; } return(count); }
/// <summary> /// Updates the supplied registry from the URL given. /// This does not *save* the registry. For that, you probably want Repo.Update /// </summary> internal static void UpdateRegistry(Uri repo, Registry registry, KSP ksp, IUser user, Boolean clear = true) { log.InfoFormat("Downloading {0}", repo); string repo_file = String.Empty; try { repo_file = Net.Download(repo); } catch (System.Net.WebException) { user.RaiseMessage("Connection to {0} could not be established.", repo); return; } // Clear our list of known modules. var old_available = registry.available_modules; if (clear) { registry.ClearAvailable(); } // Check the filetype. FileType type = FileIdentifier.IdentifyFile(repo_file); switch (type) { case FileType.TarGz: UpdateRegistryFromTarGz(repo_file, registry); break; case FileType.Zip: UpdateRegistryFromZip(repo_file, registry); break; default: break; } List <CkanModule> metadataChanges = new List <CkanModule>(); foreach (var identifierModulePair in old_available) { var identifier = identifierModulePair.Key; if (registry.IsInstalled(identifier)) { var installedVersion = registry.InstalledVersion(identifier); if (!(registry.available_modules.ContainsKey(identifier))) { log.InfoFormat("UpdateRegistry, module {0}, version {1} not in repository ({2})", identifier, installedVersion, repo); continue; } if (!registry.available_modules[identifier].module_version.ContainsKey(installedVersion)) { continue; } // if the mod is installed and the metadata is different we have to reinstall it var metadata = registry.available_modules[identifier].module_version[installedVersion]; if (!old_available.ContainsKey(identifier) || !old_available[identifier].module_version.ContainsKey(installedVersion)) { continue; } var oldMetadata = old_available[identifier].module_version[installedVersion]; bool same = true; if ((metadata.install == null) != (oldMetadata.install == null) || (metadata.install != null && metadata.install.Length != oldMetadata.install.Length)) { same = false; } else { if (metadata.install != null) { for (int i = 0; i < metadata.install.Length; i++) { if (metadata.install[i].file != oldMetadata.install[i].file) { same = false; break; } if (metadata.install[i].install_to != oldMetadata.install[i].install_to) { same = false; break; } if ((metadata.install[i].filter == null) != (oldMetadata.install[i].filter == null)) { same = false; break; } if (metadata.install[i].filter != null) { if (!metadata.install[i].filter.SequenceEqual(oldMetadata.install[i].filter)) { same = false; break; } } if ((metadata.install[i].filter_regexp == null) != (oldMetadata.install[i].filter_regexp == null)) { same = false; break; } if (metadata.install[i].filter_regexp != null) { if (!metadata.install[i].filter_regexp.SequenceEqual(oldMetadata.install[i].filter_regexp)) { same = false; break; } } } } } if (!same) { metadataChanges.Add(registry.available_modules[identifier].module_version[installedVersion]); } } } if (metadataChanges.Any()) { string mods = ""; for (int i = 0; i < metadataChanges.Count; i++) { mods += metadataChanges[i].identifier + " " + metadataChanges[i].version.ToString() + ((i < metadataChanges.Count - 1) ? ", " : ""); } if (user.RaiseYesNoDialog(String.Format( @"The following mods have had their metadata changed since last update - {0}. It is advisable that you reinstall them in order to preserve consistency with the repository. Do you wish to reinstall now?", mods))) { ModuleInstaller installer = ModuleInstaller.GetInstance(ksp, new NullUser()); installer.Upgrade(metadataChanges, new NetAsyncDownloader(new NullUser())); } } // Remove our downloaded meta-data now we've processed it. // Seems weird to do this as part of a transaction, but Net.Download uses them, so let's be consistent. file_transaction.Delete(repo_file); }
/// <summary> /// Updates the supplied registry from the URL given. /// This does not *save* the registry. For that, you probably want Repo.Update /// </summary> internal static void UpdateRegistry(Uri repo, Registry registry, KSP ksp, IUser user, Boolean clear = true) { log.InfoFormat("Downloading {0}", repo); string repo_file = Net.Download(repo); // Clear our list of known modules. var old_available = registry.available_modules; if (clear) { registry.ClearAvailable(); } // Check the filetype. FileType type = FileIdentifier.IdentifyFile(repo_file); switch (type) { case FileType.TarGz: UpdateRegistryFromTarGz (repo_file, registry); break; case FileType.Zip: UpdateRegistryFromZip (repo_file, registry); break; default: break; } List<CkanModule> metadataChanges = new List<CkanModule>(); foreach (var identifierModulePair in old_available) { var identifier = identifierModulePair.Key; if (registry.IsInstalled(identifier)) { var installedVersion = registry.InstalledVersion(identifier); if (!(registry.available_modules.ContainsKey(identifier))) { log.InfoFormat("UpdateRegistry, module {0}, version {1} not in repository ({2})", identifier, installedVersion, repo); continue; } if (!registry.available_modules[identifier].module_version.ContainsKey(installedVersion)) { continue; } // if the mod is installed and the metadata is different we have to reinstall it var metadata = registry.available_modules[identifier].module_version[installedVersion]; if (!old_available.ContainsKey(identifier) || !old_available[identifier].module_version.ContainsKey(installedVersion)) { continue; } var oldMetadata = old_available[identifier].module_version[installedVersion]; bool same = true; if ((metadata.install == null) != (oldMetadata.install == null) || (metadata.install != null && metadata.install.Length != oldMetadata.install.Length)) { same = false; } else { if(metadata.install != null) for (int i = 0; i < metadata.install.Length; i++) { if (metadata.install[i].file != oldMetadata.install[i].file) { same = false; break; } if (metadata.install[i].install_to != oldMetadata.install[i].install_to) { same = false; break; } if ((metadata.install[i].filter == null) != (oldMetadata.install[i].filter == null)) { same = false; break; } if(metadata.install[i].filter != null) if (!metadata.install[i].filter.SequenceEqual(oldMetadata.install[i].filter)) { same = false; break; } if ((metadata.install[i].filter_regexp == null) != (oldMetadata.install[i].filter_regexp == null)) { same = false; break; } if(metadata.install[i].filter_regexp != null) if (!metadata.install[i].filter_regexp.SequenceEqual(oldMetadata.install[i].filter_regexp)) { same = false; break; } } } if (!same) { metadataChanges.Add(registry.available_modules[identifier].module_version[installedVersion]); } } } if (metadataChanges.Any()) { string mods = ""; for (int i = 0; i < metadataChanges.Count; i++) { mods += metadataChanges[i].identifier + " " + metadataChanges[i].version.ToString() + ((i < metadataChanges.Count-1) ? ", " : ""); } if(user.RaiseYesNoDialog(String.Format( @"The following mods have had their metadata changed since last update - {0}. It is advisable that you reinstall them in order to preserve consistency with the repository. Do you wish to reinstall now?", mods))) { ModuleInstaller installer = ModuleInstaller.GetInstance(ksp, new NullUser()); installer.Upgrade(metadataChanges, new NetAsyncDownloader(new NullUser())); } } // Remove our downloaded meta-data now we've processed it. // Seems weird to do this as part of a transaction, but Net.Download uses them, so let's be consistent. file_transaction.Delete(repo_file); }
private void _UpdateModsList(bool markUpdates) { Registry registry = RegistryManager.Instance(KSPManager.CurrentInstance).registry; ModList.Rows.Clear(); List <CkanModule> modules = GetModsByFilter(m_ModFilter); // filter by left menu selection switch (m_ModFilter) { case GUIModFilter.All: break; case GUIModFilter.Installed: modules.RemoveAll(m => !registry.IsInstalled(m.identifier)); break; case GUIModFilter.InstalledUpdateAvailable: modules.RemoveAll ( m => !(registry.IsInstalled(m.identifier) && m.version.IsGreaterThan( registry.InstalledVersion(m.identifier))) ); break; case GUIModFilter.NewInRepository: break; case GUIModFilter.NotInstalled: modules.RemoveAll(m => registry.IsInstalled(m.identifier)); break; case GUIModFilter.Incompatible: break; } // filter by name modules.RemoveAll(m => !m.name.ToLowerInvariant().Contains(m_ModNameFilter.ToLowerInvariant())); foreach (CkanModule mod in modules) { var item = new DataGridViewRow(); item.Tag = mod; bool isInstalled = registry.IsInstalled(mod.identifier); // installed if (m_ModFilter != GUIModFilter.Incompatible) { var installedCell = new DataGridViewCheckBoxCell(); installedCell.Value = isInstalled; item.Cells.Add(installedCell); } else { var installedCell = new DataGridViewTextBoxCell(); installedCell.Value = "-"; item.Cells.Add(installedCell); } // want update if (!isInstalled) { var updateCell = new DataGridViewTextBoxCell(); item.Cells.Add(updateCell); updateCell.ReadOnly = true; updateCell.Value = "-"; } else { bool isUpToDate = !registry.InstalledVersion(mod.identifier).IsLessThan(mod.version); if (!isUpToDate) { var updateCell = new DataGridViewCheckBoxCell(); item.Cells.Add(updateCell); updateCell.ReadOnly = false; } else { var updateCell = new DataGridViewTextBoxCell(); item.Cells.Add(updateCell); updateCell.ReadOnly = true; updateCell.Value = "-"; } } // name var nameCell = new DataGridViewTextBoxCell(); nameCell.Value = mod.name; item.Cells.Add(nameCell); // author var authorCell = new DataGridViewTextBoxCell(); if (mod.author != null) { string authors = ""; for (int i = 0; i < mod.author.Count(); i++) { authors += mod.author[i]; if (i != mod.author.Count() - 1) { authors += ", "; } } authorCell.Value = authors; } else { authorCell.Value = "N/A"; } item.Cells.Add(authorCell); // installed version Version installedVersion = registry.InstalledVersion(mod.identifier); var installedVersionCell = new DataGridViewTextBoxCell(); if (installedVersion != null) { installedVersionCell.Value = installedVersion.ToString(); } else { installedVersionCell.Value = "-"; } item.Cells.Add(installedVersionCell); // latest version Version latestVersion = mod.version; var latestVersionCell = new DataGridViewTextBoxCell(); if (latestVersion != null) { latestVersionCell.Value = latestVersion.ToString(); } else { latestVersionCell.Value = "-"; } item.Cells.Add(latestVersionCell); // KSP version KSPVersion kspVersion = mod.ksp_version; var kspVersionCell = new DataGridViewTextBoxCell(); if (kspVersion != null) { kspVersionCell.Value = kspVersion.ToString(); } else { kspVersionCell.Value = "-"; } item.Cells.Add(kspVersionCell); // description var descriptionCell = new DataGridViewTextBoxCell(); descriptionCell.Value = mod.@abstract; item.Cells.Add(descriptionCell); // homepage var homepageCell = new DataGridViewLinkCell(); if (mod.resources != null && mod.resources.homepage != null) { homepageCell.Value = mod.resources.homepage; } else { homepageCell.Value = "N/A"; } item.Cells.Add(homepageCell); ModList.Rows.Add(item); // sort by name ModList.Sort(ModList.Columns[2], ListSortDirection.Ascending); ModList.Refresh(); } }
// 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()); }
/// <summary> /// Resolve a relationship stanza (a list of relationships). /// This will add modules to be installed, if required. /// May recurse back to Resolve for those new modules. /// /// If `soft_resolve` is true, we warn rather than throw exceptions on mods we cannot find. /// If `soft_resolve` is false (default), we throw a ModuleNotFoundKraken if we can't find a dependency. /// /// Throws a TooManyModsProvideKraken if we have too many choices. /// </summary> private void ResolveStanza(IEnumerable <RelationshipDescriptor> stanza, RelationshipResolverOptions options, bool soft_resolve = false) { if (stanza == null) { return; } foreach (string dep_name in stanza.Select(dep => dep.name)) { log.DebugFormat("Considering {0}", dep_name); // If we already have this dependency covered, skip. // If it's already installed, skip. if (modlist.ContainsKey(dep_name) || registry.IsInstalled(dep_name)) { continue; } List <CkanModule> candidates = registry.LatestAvailableWithProvides(dep_name, kspversion); if (candidates.Count == 0) { if (!soft_resolve) { log.ErrorFormat("Dependency on {0} found, but nothing provides it.", dep_name); throw new ModuleNotFoundKraken(dep_name); } log.InfoFormat("{0} is recommended/suggested, but nothing provides it.", dep_name); continue; } if (candidates.Count > 1) { // Oh no, too many to pick from! // TODO: It would be great if instead we picked the one with the // most recommendations. if (options.without_toomanyprovides_kraken) { continue; } throw new TooManyModsProvideKraken(dep_name, candidates); } CkanModule candidate = candidates[0]; // Finally, check our candidate against everything which might object // to it being installed; that's all the mods which are fixed in our // list thus far, as well as everything on the system. var fixed_mods = new HashSet <Module>(modlist.Values); fixed_mods.UnionWith(registry.InstalledModules.Select(x => x.Module)); foreach (Module mod in fixed_mods) { if (mod.ConflictsWith(candidate)) { if (soft_resolve) { log.InfoFormat("{0} would cause conflicts, excluding it from consideration", candidate); // I want labeled loops please, so I don't have to set this to null, // break, and then look at it at the end. o_O candidate = null; break; } var this_is_why_we_cant_have_nice_things = new List <string> { string.Format( "{0} and {1} conflict with each other, yet we require them both!", candidate, mod) }; throw new InconsistentKraken(this_is_why_we_cant_have_nice_things); } } // Our candidate may have been set to null if it was vetoed by our // sanity check above. if (candidate != null) { // Okay, looks like we want this one. Adding. Add(candidate); Resolve(candidate, options); } } }
/// <summary> /// Resolve a relationship stanza (a list of relationships). /// This will add modules to be installed, if required. /// May recurse back to Resolve for those new modules. /// /// If `soft_resolve` is true, we warn rather than throw exceptions on mods we cannot find. /// If `soft_resolve` is false (default), we throw a ModuleNotFoundKraken if we can't find a dependency. /// /// Throws a TooManyModsProvideKraken if we have too many choices and /// options.without_toomanyprovides_kraken is not set. /// /// See RelationshipResolverOptions for further adjustments that can be made. /// /// </summary> private void ResolveStanza(IEnumerable <RelationshipDescriptor> stanza, Relationship reason, RelationshipResolverOptions options, bool soft_resolve = false) { if (stanza == null) { return; } foreach (string dep_name in stanza.Select(dep => dep.name)) { log.DebugFormat("Considering {0}", dep_name); // If we already have this dependency covered, skip. // If it's already installed, skip. if (modlist.ContainsKey(dep_name) || registry.IsInstalled(dep_name)) { continue; } List <CkanModule> candidates = registry.LatestAvailableWithProvides(dep_name, kspversion); if (candidates.Count == 0) { if (!soft_resolve) { log.ErrorFormat("Dependency on {0} found, but nothing provides it.", dep_name); throw new ModuleNotFoundKraken(dep_name); } log.InfoFormat("{0} is recommended/suggested, but nothing provides it.", dep_name); continue; } if (candidates.Count > 1) { // Oh no, too many to pick from! // TODO: It would be great if instead we picked the one with the // most recommendations. if (options.without_toomanyprovides_kraken) { continue; } throw new TooManyModsProvideKraken(dep_name, candidates); } CkanModule candidate = candidates[0]; // Finally, check our candidate against everything which might object // to it being installed; that's all the mods which are fixed in our // list thus far, as well as everything on the system. var fixed_mods = new HashSet <Module>(modlist.Values); fixed_mods.UnionWith(registry.InstalledModules.Select(x => x.Module)); var conflicting_mod = fixed_mods.FirstOrDefault(mod => mod.ConflictsWith(candidate)); if (conflicting_mod == null) { // Okay, looks like we want this one. Adding. Add(candidate, reason); Resolve(candidate, options); } else if (soft_resolve) { log.InfoFormat("{0} would cause conflicts, excluding it from consideration", candidate); } else { if (options.procede_with_inconsistencies) { Add(candidate, reason); conflicts.Add(new KeyValuePair <Module, Module>(conflicting_mod, candidate)); conflicts.Add(new KeyValuePair <Module, Module>(candidate, conflicting_mod)); } else { throw new InconsistentKraken(string.Format("{0} conflicts with {1}, can't install both.", conflicting_mod, candidate)); } } } }
/// <summary> /// Updates the supplied registry from the URL given. /// This does not *save* the registry. For that, you probably want Repo.Update /// </summary> internal static void UpdateRegistry(Uri repo, Registry registry, KSP ksp, IUser user, Boolean clear = true) { log.InfoFormat("Downloading {0}", repo); string repo_file = String.Empty; try { repo_file = Net.Download(repo); } catch (System.Net.WebException e) { user.RaiseError($"Couldn't download {repo}.", e); return; } // Clear our list of known modules. var old_available = registry.available_modules; if (clear) { registry.ClearAvailable(); } // Check the filetype. FileType type = FileIdentifier.IdentifyFile(repo_file); switch (type) { case FileType.TarGz: UpdateRegistryFromTarGz(repo_file, registry); break; case FileType.Zip: UpdateRegistryFromZip(repo_file, registry); break; default: break; } List <CfanModule> metadataChanges = new List <CfanModule>(); foreach (var identifierModulePair in old_available) { var identifier = identifierModulePair.Key; if (registry.IsInstalled(identifier)) { AbstractVersion abstractVersion = registry.InstalledVersion(identifier); var installedVersion = new ModVersion(abstractVersion.ToString()); if (!(registry.available_modules.ContainsKey(identifier))) { log.InfoFormat("UpdateRegistry, module {0}, version {1} not in repository ({2})", identifier, installedVersion, repo); continue; } if (!registry.available_modules[identifier].module_version.ContainsKey(installedVersion)) { continue; } // if the mod is installed and the metadata is different we have to reinstall it CfanModule metadata = new CfanModule(registry.available_modules[identifier].module_version[installedVersion]); if (!old_available.ContainsKey(identifier) || !old_available[identifier].module_version.ContainsKey(installedVersion)) { continue; } CfanModule oldMetadata = new CfanModule(old_available[identifier].module_version[installedVersion]); bool same = metadata.kind == oldMetadata.kind; if (!same) { metadataChanges.Add(new CfanModule(registry.available_modules[identifier].module_version[installedVersion])); } } } if (metadataChanges.Any()) { string mods = ""; for (int i = 0; i < metadataChanges.Count; i++) { mods += metadataChanges[i].identifier + " " + metadataChanges[i].modVersion.ToString() + ((i < metadataChanges.Count - 1) ? ", " : ""); } if (user.RaiseYesNoDialog(String.Format( @"The following mods have had their metadata changed since last update - {0}. It is advisable that you reinstall them in order to preserve consistency with the repository. Do you wish to reinstall now?", mods))) { ModuleInstaller installer = ModuleInstaller.GetInstance(ksp, new NullUser()); installer.Upgrade(metadataChanges, new NetAsyncModulesDownloader(new NullUser(), ksp.tryGetFactorioAuthData())); } } // Remove our downloaded meta-data now we've processed it. // Seems weird to do this as part of a transaction, but Net.Download uses them, so let's be consistent. file_transaction.Delete(repo_file); }