public static int Update(RegistryManager registry_manager, KSP ksp, IUser user, Boolean clear = true, Uri repo = null) { // Use our default repo, unless we've been told otherwise. if (repo == null) { repo = default_ckan_repo; } UpdateRegistry(repo, registry_manager.registry, ksp, user, clear); // Save our changes! registry_manager.Save(); // Return how many we got! return registry_manager.registry.Available(ksp.Version()).Count; }
/// <summary> /// Download and update the local CKAN meta-info. /// Optionally takes a URL to the zipfile repo to download. /// Returns the number of unique modules updated. /// </summary> public static int UpdateAllRepositories(RegistryManager registry_manager, KSP ksp, IUser user) { // If we handle multiple repositories, we will call ClearRegistry() ourselves... registry_manager.registry.ClearAvailable(); // TODO this should already give us a pre-sorted list SortedDictionary<string, Repository> sortedRepositories = registry_manager.registry.Repositories; foreach (KeyValuePair<string, Repository> repository in sortedRepositories) { log.InfoFormat("About to update {0}", repository.Value.name); UpdateRegistry(repository.Value.uri, registry_manager.registry, ksp, user, false); } // Save our changes. registry_manager.Save(); // Return how many we got! return registry_manager.registry.Available(ksp.Version()).Count; }
private static int Update(RegistryManager registry_manager, KSP ksp, IUser user, Boolean clear = true, Uri repo = null) { // Use our default repo, unless we've been told otherwise. if (repo == null) { repo = default_ckan_repo; } UpdateRegistry(repo, registry_manager.registry, ksp, user, clear); // Save our changes! registry_manager.Save(enforce_consistency: false); ShowUserInconsistencies(registry_manager.registry, user); // Return how many we got! return(registry_manager.registry.Available(ksp.Version()).Count); }
/// <summary> /// Download and update the local CKAN meta-info. /// Optionally takes a URL to the zipfile repo to download. /// Returns the number of unique modules updated. /// </summary> public static int UpdateAllRepositories(RegistryManager registry_manager, KSP ksp, IUser user) { // If we handle multiple repositories, we will call ClearRegistry() ourselves... registry_manager.registry.ClearAvailable(); // TODO this should already give us a pre-sorted list SortedDictionary <string, Repository> sortedRepositories = registry_manager.registry.Repositories; foreach (KeyValuePair <string, Repository> repository in sortedRepositories) { log.InfoFormat("About to update {0}", repository.Value.name); UpdateRegistry(repository.Value.uri, registry_manager.registry, ksp, user, false); } // Save our changes. registry_manager.Save(); // Return how many we got! return(registry_manager.registry.Available(ksp.Version()).Count); }
public static int Update(RegistryManager registry_manager, KSP ksp, IUser user, Boolean clear = true, Uri repo = null) { // Use our default repo, unless we've been told otherwise. if (repo == null) { repo = default_ckan_repo; } UpdateRegistry(repo, registry_manager.registry, ksp, user, clear); // Save our changes! registry_manager.Save(); // maybe we can move some preexisting modules to installed (i.e. they now may have corresponding version available) ksp.ScanGameData(); // Return how many we got! return(registry_manager.registry.Available(ksp.Version()).Count); }
public static void ScanGameData() { RegistryManager registry_manager = RegistryManager.Instance(); Registry registry = registry_manager.registry; // Forget that we've seen any DLLs, as we're going to refresh them all. registry.ClearDlls(); // TODO: It would be great to optimise this to skip .git directories and the like. // Yes, I keep my GameData in git. string[] dllFiles = Directory.GetFiles(GameData(), "*.dll", SearchOption.AllDirectories); foreach (string file in dllFiles) { // register_dll does the heavy lifting of turning it into a modname registry.RegisterDll(file); } registry_manager.Save(); }
// Same as above, just with a Uri instead of string for the repo public static int Update(RegistryManager registry_manager, KSP ksp, IUser user, Uri repo = null) { // Use our default repo, unless we've been told otherwise. if (repo == null) { repo = CKAN.Repository.default_ckan_repo_uri; } List <CkanModule> newAvail = UpdateRegistry(repo, ksp, user); if (newAvail != null && newAvail.Count > 0) { registry_manager.registry.SetAllAvailable(newAvail); // Save our changes! registry_manager.Save(enforce_consistency: false); } ShowUserInconsistencies(registry_manager.registry, user); // Return how many we got! return(registry_manager.registry.Available(ksp.VersionCriteria()).Count); }
/// <summary> /// Download and update the local CKAN meta-info. /// Optionally takes a URL to the zipfile repo to download. /// Returns the number of unique modules updated. /// </summary> public static int UpdateAllRepositories(RegistryManager registry_manager, KSP ksp, IUser user) { // If we handle multiple repositories, we will call ClearRegistry() ourselves... registry_manager.registry.ClearAvailable(); // TODO this should already give us a pre-sorted list SortedDictionary <string, Repository> sortedRepositories = registry_manager.registry.Repositories; foreach (KeyValuePair <string, Repository> repository in sortedRepositories) { log.InfoFormat("About to update {0}", repository.Value.name); UpdateRegistry(repository.Value.uri, registry_manager.registry, ksp, user, false); } // Save our changes // we're not sure where it's called from (and whether InconsistentKraken will be handled), and it shouldn't change consistency, so let's not check for it. registry_manager.Save(false); // maybe we can move some preexisting modules to installed (i.e. they now may have corresponding version available) ksp.ScanGameData(); // Return how many we got! return(registry_manager.registry.Available(ksp.Version()).Count); }
/// <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); }
/// <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); }
/// <summary> /// Install our mod from the filename supplied. /// If no file is supplied, we will fetch() it first. /// </summary> public void Install(CkanModule module, string filename = null) { Console.WriteLine(module.identifier + ":\n"); string version = registry_manager.registry.InstalledVersion(module.identifier); if (version != null) { // TODO: Check if we can upgrade! Console.WriteLine(" {0} {1} already installed, skipped", module.identifier, version); return; } // Check our dependencies. if (module.requires != null) { foreach (dynamic depends in module.requires) { string name = depends.name; string ver = registry_manager.registry.InstalledVersion(name); // TODO: Compare versions. if (ver == null) { // Oh, it's not installed! Let's see if we can find it. // TODO: A big store of all our known CKAN data, so we can go // find our module. // If we can't find it, cry and moan. Console.WriteLine("Requirement {0} not found", depends.name); throw new ModuleNotFoundException(name, depends.version); } } } // Fetch our file if we don't already have it. if (filename == null) { filename = CachedOrDownload(module); } // We'll need our registry to record which files we've installed. Registry registry = registry_manager.registry; // And a list of files to record them to. Dictionary <string, InstalledModuleFile> module_files = new Dictionary <string, InstalledModuleFile> (); // Open our zip file for processing ZipFile zipfile = new ZipFile(File.OpenRead(filename)); // Walk through our install instructions. foreach (dynamic stanza in module.install) { InstallComponent(stanza, zipfile, module_files); } // Register our files. registry.RegisterModule(new InstalledModule(module_files, module, DateTime.Now)); // Handle bundled mods, if we have them. if (module.bundles != null) { foreach (dynamic stanza in module.bundles) { BundledModule bundled = new BundledModule(stanza); string ver = registry_manager.registry.InstalledVersion(bundled.identifier); if (ver != null) { Console.WriteLine( "{0} {1} already installed, skipping bundled version {2}", bundled.identifier, ver, bundled.version ); continue; } // Not installed, so let's get about installing it! Dictionary <string, InstalledModuleFile> installed_files = new Dictionary <string, InstalledModuleFile> (); InstallComponent(stanza, zipfile, installed_files); registry.RegisterModule(new InstalledModule(installed_files, bundled, DateTime.Now)); } } // Done! Save our registry changes! registry_manager.Save(); return; }
/// <summary> /// Download and update the local CKAN meta-info. /// Optionally takes a URL to the zipfile repo to download. /// </summary> public static RepoUpdateResult UpdateAllRepositories(RegistryManager registry_manager, GameInstance ksp, NetModuleCache cache, IUser user) { SortedDictionary <string, Repository> sortedRepositories = registry_manager.registry.Repositories; user.RaiseProgress("Checking for updates", 0); if (sortedRepositories.Values.All(repo => !string.IsNullOrEmpty(repo.last_server_etag) && repo.last_server_etag == Net.CurrentETag(repo.uri))) { user.RaiseProgress("Already up to date", 100); user.RaiseMessage("No changes since last update"); return(RepoUpdateResult.NoChanges); } List <CkanModule> allAvail = new List <CkanModule>(); int index = 0; foreach (KeyValuePair <string, Repository> repository in sortedRepositories) { user.RaiseProgress($"Updating {repository.Value.name}", 10 + 80 * index / sortedRepositories.Count); SortedDictionary <string, int> downloadCounts; string newETag; List <CkanModule> avail = UpdateRegistry(repository.Value.uri, ksp, user, out downloadCounts, out newETag); registry_manager.registry.SetDownloadCounts(downloadCounts); if (avail == null) { // Report failure if any repo fails, rather than losing half the list. // UpdateRegistry will have alerted the user to specific errors already. return(RepoUpdateResult.Failed); } else { // Merge all the lists allAvail.AddRange(avail); repository.Value.last_server_etag = newETag; user.RaiseMessage("Updated {0} ({1} modules)", repository.Value.name, avail.Count); } ++index; } // Save allAvail to the registry if we found anything if (allAvail.Count > 0) { user.RaiseProgress("Saving modules to registry", 90); using (var transaction = CkanTransaction.CreateTransactionScope()) { // Save our changes. registry_manager.registry.SetAllAvailable(allAvail); registry_manager.Save(enforce_consistency: false); transaction.Complete(); } ShowUserInconsistencies(registry_manager.registry, user); List <CkanModule> metadataChanges = GetChangedInstalledModules(registry_manager.registry); if (metadataChanges.Count > 0) { HandleModuleChanges(metadataChanges, user, ksp, cache, registry_manager); } // Registry.CompatibleModules is slow, just return success, // caller can check it if it's really needed user.RaiseProgress("Registry saved", 100); user.RaiseMessage("Repositories updated"); return(RepoUpdateResult.Updated); } else { // Return failure user.RaiseMessage("No modules found!"); return(RepoUpdateResult.Failed); } }
/// <summary> /// Clears the registry of DLL data, and refreshes it by scanning GameData. /// This operates as a transaction. /// This *saves* the registry upon completion. /// </summary> // TODO: This would likely be better in the Registry class itself. public void ScanGameData() { using (TransactionScope tx = CkanTransaction.CreateTransactionScope()) { Registry.ClearPreexistingModules(); var detectedModules = FactorioModDetector.findAllModsInDirectory(Path.Combine(gamedatadir, "mods")); foreach (var detectedModule in detectedModules) { string detectedModulePath = detectedModule.Key; ModInfoJson detectedModInfo = detectedModule.Value; if (Registry.InstalledModules.Any(p => p.identifier == detectedModInfo.name)) { continue; } AvailableModule availableModule; if (Registry.available_modules.TryGetValue(detectedModInfo.name, out availableModule)) { CfanModule availableCfan = availableModule.ByVersion(detectedModInfo.version); if (availableCfan != null) { string expectedFilename = availableCfan.standardFileName + ".zip"; if (Path.GetFileName(detectedModulePath) == expectedFilename) { // yay, we can use this mod as installed (we will be able to update/remove it through cfan) Registry.RegisterModule(availableCfan, new [] { detectedModulePath }, this); continue; } } } // we only register that this module exists, but we won't be able to do anything with it Registry.RegisterPreexistingModule(this, detectedModulePath, detectedModInfo); } try { Registry.CheckSanity(); } catch (InconsistentKraken e) { User.RaiseError("Autodetected mods has unmet dependencies, they won't be managed by CFAN until you fix inconsitencies.\n{0}", e.InconsistenciesPretty); var unmet = SanityChecker.FindUnmetDependencies(Registry.InstalledModules.Select(p => p.Module), Registry.InstalledPreexistingModules); do { unmet .Select(unmetDependencyKeyValue => unmetDependencyKeyValue.Value) .SelectMany(p => p.Select(modWithUnmetDependencies => detectedModules.FirstOrDefault(detectedModule => detectedModule.Value.name == modWithUnmetDependencies.identifier))) .Where(p => !p.Equals(default(KeyValuePair <string, ModInfoJson>))) .ToList() .ForEach(modWithUnmetDependencies => { Registry.DeregisterModule(this, modWithUnmetDependencies.Value.name, true); Registry.RegisterPreexistingModule(this, modWithUnmetDependencies.Key, modWithUnmetDependencies.Value); }); unmet = SanityChecker.FindUnmetDependencies(Registry.InstalledModules.Select(p => p.Module), Registry.InstalledPreexistingModules); } while (unmet.Any()); } tx.Complete(); } RegistryManager.Save(); }
private static int Update(RegistryManager registry_manager, KSP ksp, IUser user, Boolean clear = true, Uri repo = null) { // Use our default repo, unless we've been told otherwise. if (repo == null) { repo = default_ckan_repo; } UpdateRegistry(repo, registry_manager.registry, ksp, user, clear); // Save our changes! registry_manager.Save(enforce_consistency: false); ShowUserInconsistencies(registry_manager.registry, user); // Return how many we got! return registry_manager.registry.Available(ksp.VersionCriteria()).Count; }