/// <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) { // Use this opportunity to also update the build mappings... kind of hacky ServiceLocator.Container.Resolve <IKspBuildMap>().Refresh(); 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].@as != oldMetadata.install[i].@as) { 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 = 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. 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 installedModule in registry.InstalledModules) { var identifier = installedModule.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]; var oldMetadata = registry.InstalledModule(identifier).Module; 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].@as != oldMetadata.install[i].@as) { 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 (!RelationshipsAreEquivalent(metadata.conflicts, oldMetadata.conflicts)) { same = false; } if (!RelationshipsAreEquivalent(metadata.depends, oldMetadata.depends)) { same = false; } if (!RelationshipsAreEquivalent(metadata.recommends, oldMetadata.recommends)) { same = false; } if (metadata.provides != oldMetadata.provides) { if (metadata.provides == null || oldMetadata.provides == null) { same = false; } else if (!metadata.provides.OrderBy(i => i).SequenceEqual(oldMetadata.provides.OrderBy(i => i))) { same = false; } } if (!same) { metadataChanges.Add(registry.available_modules[identifier].module_version[installedVersion]); } } if (metadataChanges.Any()) { var sb = new StringBuilder(); for (var i = 0; i < metadataChanges.Count; i++) { var module = metadataChanges[i]; sb.AppendLine(string.Format("- {0} {1}", module.identifier, module.version)); } if (user.RaiseYesNoDialog(string.Format(@"The following mods have had their metadata changed since last update: {0} You should reinstall them in order to preserve consistency with the repository. Do you wish to reinstall now?", sb))) { ModuleInstaller installer = ModuleInstaller.GetInstance(ksp, new NullUser()); // New upstream metadata may break the consistency of already installed modules // e.g. if user installs modules A and B and then later up A is made to conflict with B // This is perfectly normal and shouldn't produce an error, therefore we skip enforcing // consistency. However, we will show the user any inconsistencies later on. // Use the identifiers so we use the overload that actually resolves relationships // Do each changed module one at a time so a failure of one doesn't cause all the others to fail foreach (var changedIdentifier in metadataChanges.Select(i => i.identifier)) { try { installer.Upgrade( new[] { changedIdentifier }, new NetAsyncModulesDownloader(new NullUser()), enforceConsistency: false ); } // Thrown when a dependency couldn't be satisfied catch (ModuleNotFoundKraken) { log.WarnFormat("Skipping installation of {0} due to relationship error.", changedIdentifier); user.RaiseMessage("Skipping installation of {0} due to relationship error.", changedIdentifier); } // Thrown when a conflicts relationship is violated catch (InconsistentKraken) { log.WarnFormat("Skipping installation of {0} due to relationship error.", changedIdentifier); user.RaiseMessage("Skipping installation of {0} due to relationship error.", changedIdentifier); } } } } // 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 = 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); }