public int RunCommand(CKAN.GameInstance ksp, object raw_options) { AvailableOptions opts = (AvailableOptions)raw_options; IRegistryQuerier registry = RegistryManager.Instance(ksp).registry; var compatible = registry .CompatibleModules(ksp.VersionCriteria()) .Where(m => !m.IsDLC); user.RaiseMessage("Modules compatible with KSP {0}", ksp.Version()); user.RaiseMessage(""); if (opts.detail) { foreach (CkanModule module in compatible) { user.RaiseMessage("* {0} ({1}) - {2} - {3}", module.identifier, module.version, module.name, module.@abstract); } } else { foreach (CkanModule module in compatible) { user.RaiseMessage("* {0} ({1}) - {2}", module.identifier, module.version, module.name); } } return(Exit.OK); }
/// <summary> /// Searches for the term in the list of compatible or incompatible modules for the ksp instance. /// Looks in name, identifier and description fields, and if given, restricts to authors matching the author term. /// </summary> /// <returns>List of matching modules.</returns> /// <param name="ksp">The KSP instance to perform the search for.</param> /// <param name="term">The search term. Case insensitive.</param> /// <param name="author">Name of author to find</param> /// <param name="searchIncompatible">True to look for incompatible modules, false (default) to look for compatible</param> public List <CkanModule> PerformSearch(CKAN.GameInstance ksp, string term, string author = null, bool searchIncompatible = false) { // Remove spaces and special characters from the search term. term = String.IsNullOrWhiteSpace(term) ? string.Empty : CkanModule.nonAlphaNums.Replace(term, ""); author = String.IsNullOrWhiteSpace(author) ? string.Empty : CkanModule.nonAlphaNums.Replace(author, ""); var registry = RegistryManager.Instance(ksp).registry; if (!searchIncompatible) { return(registry .CompatibleModules(ksp.VersionCriteria()) // Look for a match in each string. .Where(module => (module.SearchableName.IndexOf(term, StringComparison.OrdinalIgnoreCase) > -1 || module.SearchableIdentifier.IndexOf(term, StringComparison.OrdinalIgnoreCase) > -1 || module.SearchableAbstract.IndexOf(term, StringComparison.OrdinalIgnoreCase) > -1 || module.SearchableDescription.IndexOf(term, StringComparison.OrdinalIgnoreCase) > -1) && module.SearchableAuthors.Any((auth) => auth.IndexOf(author, StringComparison.OrdinalIgnoreCase) > -1)) .ToList()); } else { return(registry .IncompatibleModules(ksp.VersionCriteria()) // Look for a match in each string. .Where(module => (module.SearchableName.IndexOf(term, StringComparison.OrdinalIgnoreCase) > -1 || module.SearchableIdentifier.IndexOf(term, StringComparison.OrdinalIgnoreCase) > -1 || module.SearchableAbstract.IndexOf(term, StringComparison.OrdinalIgnoreCase) > -1 || module.SearchableDescription.IndexOf(term, StringComparison.OrdinalIgnoreCase) > -1) && module.SearchableAuthors.Any((auth) => auth.IndexOf(author, StringComparison.OrdinalIgnoreCase) > -1)) .ToList()); } }
/// <summary> /// Try to repair our registry. /// </summary> private int Registry(CKAN.GameInstance ksp) { RegistryManager manager = RegistryManager.Instance(ksp); manager.registry.Repair(); manager.Save(); User.RaiseMessage("Registry repairs attempted. Hope it helped."); return(Exit.OK); }
/// <summary> /// Upgrade some modules by their identifier and (optional) version /// </summary> /// <param name="manager">Game instance manager to use</param> /// <param name="user">IUser object for output</param> /// <param name="ksp">Game instance to use</param> /// <param name="identsAndVersions">List of identifier[=version] to upgrade</param> public static void UpgradeModules(GameInstanceManager manager, IUser user, CKAN.GameInstance ksp, List <string> identsAndVersions) { UpgradeModules(manager, user, ksp, (ModuleInstaller installer, NetAsyncModulesDownloader downloader, RegistryManager regMgr, ref HashSet <string> possibleConfigOnlyDirs) => installer.Upgrade(identsAndVersions, downloader, ref possibleConfigOnlyDirs, regMgr, true), m => identsAndVersions.Add(m.identifier) ); }
/// <summary> /// Upgrade some modules by their CkanModules /// </summary> /// <param name="manager">Game instance manager to use</param> /// <param name="user">IUser object for output</param> /// <param name="ksp">Game instance to use</param> /// <param name="modules">List of modules to upgrade</param> public static void UpgradeModules(GameInstanceManager manager, IUser user, CKAN.GameInstance ksp, bool ConfirmPrompt, List <CkanModule> modules) { UpgradeModules(manager, user, ksp, (ModuleInstaller installer, NetAsyncModulesDownloader downloader, RegistryManager regMgr, ref HashSet <string> possibleConfigOnlyDirs) => installer.Upgrade(modules, downloader, ref possibleConfigOnlyDirs, regMgr, true, true, ConfirmPrompt), m => modules.Add(m) ); }
public static CKAN.GameInstance GetGameInstance(GameInstanceManager manager) { CKAN.GameInstance inst = manager.CurrentInstance ?? manager.GetPreferredInstance(); if (inst == null) { throw new NoGameInstanceKraken(); } return(inst); }
public FakeConfiguration(CKAN.GameInstance instance, string autostart) : this( new List <Tuple <string, string, string> > { new Tuple <string, string, string>("test", instance.GameDir(), "KSP") }, autostart ) { }
/// <summary> /// Updates the repository. /// </summary> /// <param name="ksp">The KSP instance to work on.</param> /// <param name="repository">Repository to update. If null all repositories are used.</param> private void UpdateRepository(CKAN.GameInstance ksp, string repository = null) { RegistryManager registry_manager = RegistryManager.Instance(ksp); var updated = repository == null ? CKAN.Repo.UpdateAllRepositories(registry_manager, ksp, manager.Cache, user) != CKAN.RepoUpdateResult.Failed : CKAN.Repo.Update(registry_manager, ksp, user, repository); user.RaiseMessage("Updated information on {0} compatible modules", registry_manager.registry.CompatibleModules(ksp.VersionCriteria()).Count()); }
/// <summary> /// Update the registry /// </summary> /// <param name="ksp">Game instance to update</param> /// <param name="raw_options">Command line options object</param> /// <returns> /// Exit code for shell environment /// </returns> public int RunCommand(CKAN.GameInstance ksp, object raw_options) { UpdateOptions options = (UpdateOptions)raw_options; List <CkanModule> compatible_prior = null; if (options.list_changes) { // Get a list of compatible modules prior to the update. var registry = RegistryManager.Instance(ksp).registry; compatible_prior = registry.CompatibleModules(ksp.VersionCriteria()).ToList(); } // If no repository is selected, select all. if (options.repo == null) { options.update_all = true; } try { if (options.update_all) { UpdateRepository(ksp); } else { UpdateRepository(ksp, options.repo); } } catch (ReinstallModuleKraken rmk) { Upgrade.UpgradeModules(manager, user, ksp, false, rmk.Modules); } catch (MissingCertificateKraken kraken) { // Handling the kraken means we have prettier output. user.RaiseMessage(kraken.ToString()); return(Exit.ERROR); } if (options.list_changes) { var registry = RegistryManager.Instance(ksp).registry; PrintChanges(compatible_prior, registry.CompatibleModules(ksp.VersionCriteria()).ToList()); } return(Exit.OK); }
internal static CkanModule LoadCkanFromFile(CKAN.GameInstance current_instance, string ckan_file) { CkanModule module = CkanModule.FromFile(ckan_file); // We'll need to make some registry changes to do this. RegistryManager registry_manager = RegistryManager.Instance(current_instance); // 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); return(module); }
/// <summary> /// Convert case insensitive mod names from the user to case sensitive identifiers /// </summary> /// <param name="ksp">Game instance forgetting the mods</param> /// <param name="modules">List of strings to convert, format 'identifier' or 'identifier=version'</param> public static void AdjustModulesCase(CKAN.GameInstance ksp, List <string> modules) { IRegistryQuerier registry = RegistryManager.Instance(ksp).registry; // Get the list of all compatible and incompatible mods List <CkanModule> mods = registry.CompatibleModules(ksp.VersionCriteria()).ToList(); mods.AddRange(registry.IncompatibleModules(ksp.VersionCriteria())); for (int i = 0; i < modules.Count; ++i) { Match match = CkanModule.idAndVersionMatcher.Match(modules[i]); if (match.Success) { // Handle name=version format string ident = match.Groups["mod"].Value; string version = match.Groups["version"].Value; modules[i] = $"{CaseInsensitiveExactMatch(mods, ident)}={version}"; } else { modules[i] = CaseInsensitiveExactMatch(mods, modules[i]); } } }
/// <summary> /// Execute an import command /// </summary> /// <param name="ksp">Game instance into which to import</param> /// <param name="options">Command line parameters from the user</param> /// <returns> /// Process exit code /// </returns> public int RunCommand(CKAN.GameInstance ksp, object options) { try { ImportOptions opts = options as ImportOptions; HashSet <FileInfo> toImport = GetFiles(opts); if (toImport.Count < 1) { user.RaiseMessage("Usage: ckan import path [path2, ...]"); return(Exit.ERROR); } else { log.InfoFormat("Importing {0} files", toImport.Count); List <string> toInstall = new List <string>(); RegistryManager regMgr = RegistryManager.Instance(ksp); ModuleInstaller inst = new ModuleInstaller(ksp, manager.Cache, user); inst.ImportFiles(toImport, user, mod => toInstall.Add(mod.identifier), regMgr.registry, !opts.Headless); HashSet <string> possibleConfigOnlyDirs = null; if (toInstall.Count > 0) { inst.InstallList( toInstall, new RelationshipResolverOptions(), regMgr, ref possibleConfigOnlyDirs ); } return(Exit.OK); } } catch (Exception ex) { user.RaiseError("Import error: {0}", ex.Message); return(Exit.ERROR); } }
private void ShowVersionTable(CKAN.GameInstance inst, List <CkanModule> modules) { var versions = modules.Select(m => m.version.ToString()).ToList(); var gameVersions = modules.Select(m => { GameVersion minKsp = null, maxKsp = null; Registry.GetMinMaxVersions(new List <CkanModule>() { m }, out _, out _, out minKsp, out maxKsp); return(GameVersionRange.VersionSpan(inst.game, minKsp, maxKsp)); }).ToList(); string[] headers = new string[] { "Version", "Game Versions" }; int versionLength = Math.Max(headers[0].Length, versions.Max(v => v.Length)); int gameVersionLength = Math.Max(headers[1].Length, gameVersions.Max(v => v.Length)); user.RaiseMessage(""); user.RaiseMessage( "{0} {1}", headers[0].PadRight(versionLength), headers[1].PadRight(gameVersionLength) ); user.RaiseMessage( "{0} {1}", new string('-', versionLength), new string('-', gameVersionLength) ); for (int row = 0; row < versions.Count; ++row) { user.RaiseMessage( "{0} {1}", versions[row].PadRight(versionLength), gameVersions[row].PadRight(gameVersionLength) ); } }
/// <summary> /// The core of the module upgrading logic, with callbacks to /// support different input formats managed by the calling code. /// Handles transactions, creating commonly required objects, /// looping logic, prompting for TooManyModsProvideKraken resolution. /// </summary> /// <param name="manager">Game instance manager to use</param> /// <param name="user">IUser object for output</param> /// <param name="ksp">Game instance to use</param> /// <param name="attemptUpgradeCallback">Function to call to try to perform the actual upgrade, may throw TooManyModsProvideKraken</param> /// <param name="addUserChoiceCallback">Function to call when the user has requested a new module added to the change set in response to TooManyModsProvideKraken</param> private static void UpgradeModules( GameInstanceManager manager, IUser user, CKAN.GameInstance ksp, AttemptUpgradeAction attemptUpgradeCallback, System.Action <CkanModule> addUserChoiceCallback) { using (TransactionScope transact = CkanTransaction.CreateTransactionScope()) { var installer = new ModuleInstaller(ksp, manager.Cache, user); var downloader = new NetAsyncModulesDownloader(user, manager.Cache); var regMgr = RegistryManager.Instance(ksp); HashSet <string> possibleConfigOnlyDirs = null; bool done = false; while (!done) { try { attemptUpgradeCallback?.Invoke(installer, downloader, regMgr, ref possibleConfigOnlyDirs); transact.Complete(); done = true; } catch (TooManyModsProvideKraken k) { int choice = user.RaiseSelectionDialog( k.Message, k.modules.Select(m => $"{m.identifier} ({m.name})").ToArray()); if (choice < 0) { return; } else { addUserChoiceCallback?.Invoke(k.modules[choice]); } } } } }
/// <summary> /// Scans the game instance. Detects installed mods to mark as auto-detected and checks the consistency /// </summary> /// <param name="inst">The instance to scan</param> /// <param name="user"></param> /// <param name="next_command">Changes the output message if set.</param> /// <returns>Exit.OK if instance is consistent, Exit.ERROR otherwise </returns> private static int Scan(CKAN.GameInstance inst, IUser user, string next_command = null) { try { inst.Scan(); return(Exit.OK); } catch (InconsistentKraken kraken) { if (next_command == null) { user.RaiseError(kraken.InconsistenciesPretty); user.RaiseError("The repo has not been saved."); } else { user.RaiseMessage("Preliminary scanning shows that the install is in a inconsistent state."); user.RaiseMessage("Use ckan.exe scan for more details"); user.RaiseMessage("Proceeding with {0} in case it fixes it.\r\n", next_command); } return(Exit.ERROR); } }
public int RunCommand(CKAN.GameInstance ksp, object raw_options) { ShowOptions options = (ShowOptions)raw_options; if (options.Modname == null) { // empty argument user.RaiseMessage("show <module> - module name argument missing, perhaps you forgot it?"); return(Exit.BADOPT); } // Check installed modules for an exact match. var registry = RegistryManager.Instance(ksp).registry; var installedModuleToShow = registry.InstalledModule(options.Modname); if (installedModuleToShow != null) { // Show the installed module. return(ShowMod(installedModuleToShow)); } // Module was not installed, look for an exact match in the available modules, // either by "name" (the user-friendly display name) or by identifier CkanModule moduleToShow = registry .CompatibleModules(ksp.VersionCriteria()) .SingleOrDefault( mod => mod.name == options.Modname || mod.identifier == options.Modname ); if (moduleToShow == null) { // No exact match found. Try to look for a close match for this KSP version. user.RaiseMessage("{0} not found or installed.", options.Modname); user.RaiseMessage("Looking for close matches in mods compatible with KSP {0}.", ksp.Version()); Search search = new Search(user); var matches = search.PerformSearch(ksp, options.Modname); // Display the results of the search. if (!matches.Any()) { // No matches found. user.RaiseMessage("No close matches found."); return(Exit.BADOPT); } else if (matches.Count() == 1) { // If there is only 1 match, display it. user.RaiseMessage("Found 1 close match: {0}", matches[0].name); user.RaiseMessage(""); moduleToShow = matches[0]; } else { // Display the found close matches. string[] strings_matches = new string[matches.Count]; for (int i = 0; i < matches.Count; i++) { strings_matches[i] = matches[i].name; } int selection = user.RaiseSelectionDialog("Close matches", strings_matches); if (selection < 0) { return(Exit.BADOPT); } // Mark the selection as the one to show. moduleToShow = matches[selection]; } } return(ShowMod(moduleToShow)); }
public int RunCommand(CKAN.GameInstance ksp, object raw_options) { SearchOptions options = (SearchOptions)raw_options; // Check the input. if (String.IsNullOrWhiteSpace(options.search_term) && String.IsNullOrWhiteSpace(options.author_term)) { user.RaiseError("No search term?"); return(Exit.BADOPT); } List <CkanModule> matching_compatible = PerformSearch(ksp, options.search_term, options.author_term, false); List <CkanModule> matching_incompatible = new List <CkanModule>(); if (options.all) { matching_incompatible = PerformSearch(ksp, options.search_term, options.author_term, true); } // Show how many matches we have. if (options.all && !String.IsNullOrWhiteSpace(options.author_term)) { user.RaiseMessage("Found {0} compatible and {1} incompatible mods matching \"{2}\" by \"{3}\".", matching_compatible.Count().ToString(), matching_incompatible.Count().ToString(), options.search_term, options.author_term); } else if (options.all && String.IsNullOrWhiteSpace(options.author_term)) { user.RaiseMessage("Found {0} compatible and {1} incompatible mods matching \"{2}\".", matching_compatible.Count().ToString(), matching_incompatible.Count().ToString(), options.search_term); } else if (!options.all && !String.IsNullOrWhiteSpace(options.author_term)) { user.RaiseMessage("Found {0} compatible mods matching \"{1}\" by \"{2}\".", matching_compatible.Count().ToString(), options.search_term, options.author_term); } else if (!options.all && String.IsNullOrWhiteSpace(options.author_term)) { user.RaiseMessage("Found {0} compatible mods matching \"{1}\".", matching_compatible.Count().ToString(), options.search_term); } // Present the results. if (!matching_compatible.Any() && (!options.all || !matching_incompatible.Any())) { return(Exit.OK); } if (options.detail) { user.RaiseMessage("Matching compatible mods:"); foreach (CkanModule mod in matching_compatible) { user.RaiseMessage("* {0} ({1}) - {2} by {3} - {4}", mod.identifier, mod.version, mod.name, mod.author == null ? "N/A" : String.Join(", ", mod.author), mod.@abstract); } if (matching_incompatible.Any()) { user.RaiseMessage("Matching incompatible mods:"); foreach (CkanModule mod in matching_incompatible) { Registry.GetMinMaxVersions(new List <CkanModule> { mod }, out _, out _, out var minKsp, out var maxKsp); string GameVersion = Versioning.GameVersionRange.VersionSpan(ksp.game, minKsp, maxKsp).ToString(); user.RaiseMessage("* {0} ({1} - {2}) - {3} by {4} - {5}", mod.identifier, mod.version, GameVersion, mod.name, mod.author == null ? "N/A" : String.Join(", ", mod.author), mod.@abstract); } } } else { List <CkanModule> matching = matching_compatible.Concat(matching_incompatible).ToList(); matching.Sort((x, y) => string.Compare(x.identifier, y.identifier, StringComparison.Ordinal)); foreach (CkanModule mod in matching) { user.RaiseMessage(mod.identifier); } } return(Exit.OK); }
/// <summary> /// Uninstalls a module, if it exists. /// </summary> /// <param name="ksp">Game instance from which to remove</param> /// <param name="raw_options">Command line options object</param> /// <returns> /// Exit code for shell environment /// </returns> public int RunCommand(CKAN.GameInstance ksp, object raw_options) { RemoveOptions options = (RemoveOptions)raw_options; RegistryManager regMgr = RegistryManager.Instance(ksp); // Use one (or more!) regex to select the modules to remove if (options.regex) { log.Debug("Attempting Regex"); // Parse every "module" as a grumpy regex var justins = options.modules.Select(s => new Regex(s)); // Modules that have been selected by one regex List <string> selectedModules = new List <string>(); // Get the list of installed modules // Try every regex on every installed module: // if it matches, select for removal foreach (string mod in regMgr.registry.InstalledModules.Select(mod => mod.identifier)) { if (justins.Any(re => re.IsMatch(mod))) { selectedModules.Add(mod); } } // Replace the regular expressions with the selected modules // and continue removal as usual options.modules = selectedModules; } if (options.rmall) { log.Debug("Removing all mods"); // Add the list of installed modules to the list that should be uninstalled options.modules.AddRange( regMgr.registry.InstalledModules .Where(mod => !mod.Module.IsDLC) .Select(mod => mod.identifier) ); } if (options.modules != null && options.modules.Count > 0) { try { HashSet <string> possibleConfigOnlyDirs = null; var installer = ModuleInstaller.GetInstance(ksp, manager.Cache, user); Search.AdjustModulesCase(ksp, options.modules); installer.UninstallList(options.modules, ref possibleConfigOnlyDirs, regMgr); user.RaiseMessage(""); } catch (ModNotInstalledKraken kraken) { user.RaiseMessage("I can't do that, {0} isn't installed.", kraken.mod); user.RaiseMessage("Try `ckan list` for a list of installed mods."); return(Exit.BADOPT); } catch (ModuleIsDLCKraken kraken) { user.RaiseMessage($"CKAN can't remove expansion '{kraken.module.name}' for you."); var res = kraken?.module?.resources; var storePagesMsg = new Uri[] { res?.store, res?.steamstore } .Where(u => u != null) .Aggregate("", (a, b) => $"{a}\r\n- {b}"); if (!string.IsNullOrEmpty(storePagesMsg)) { user.RaiseMessage($"To remove this expansion, follow the instructions for the store page from which you purchased it:\r\n{storePagesMsg}"); } return(Exit.BADOPT); } catch (CancelledActionKraken k) { user.RaiseMessage("Remove aborted: {0}", k.Message); return(Exit.ERROR); } } else { user.RaiseMessage("No mod selected, nothing to do"); return(Exit.BADOPT); } return(Exit.OK); }
public int RunCommand(CKAN.GameInstance ksp, object raw_options) { ListOptions options = (ListOptions)raw_options; IRegistryQuerier registry = RegistryManager.Instance(ksp).registry; ExportFileType?exportFileType = null; if (!string.IsNullOrWhiteSpace(options.export)) { exportFileType = GetExportFileType(options.export); if (exportFileType == null) { user.RaiseError("Unknown export format: {0}", options.export); } } if (!(options.porcelain) && exportFileType == null) { user.RaiseMessage("\r\nKSP found at {0}\r\n", ksp.GameDir()); user.RaiseMessage("KSP Version: {0}\r\n", ksp.Version()); user.RaiseMessage("Installed Modules:\r\n"); } if (exportFileType == null) { var installed = new SortedDictionary <string, ModuleVersion>(registry.Installed()); foreach (KeyValuePair <string, ModuleVersion> mod in installed) { ModuleVersion current_version = mod.Value; string modInfo = string.Format("{0} {1}", mod.Key, mod.Value); string bullet = "*"; if (current_version is ProvidesModuleVersion) { // Skip virtuals for now. continue; } else if (current_version is UnmanagedModuleVersion) { // Autodetected dll bullet = "A"; } else { try { // Check if upgrades are available, and show appropriately. log.DebugFormat("Check if upgrades are available for {0}", mod.Key); CkanModule latest = registry.LatestAvailable(mod.Key, ksp.VersionCriteria()); CkanModule current = registry.GetInstalledVersion(mod.Key); InstalledModule inst = registry.InstalledModule(mod.Key); if (latest == null) { // Not compatible! log.InfoFormat("Latest {0} is not compatible", mod.Key); bullet = "X"; if (current == null) { log.DebugFormat(" {0} installed version not found in registry", mod.Key); } // Check if mod is replaceable if (current.replaced_by != null) { ModuleReplacement replacement = registry.GetReplacement(mod.Key, ksp.VersionCriteria()); if (replacement != null) { // Replaceable! bullet = ">"; modInfo = string.Format("{0} > {1} {2}", modInfo, replacement.ReplaceWith.name, replacement.ReplaceWith.version); } } } else if (latest.version.IsEqualTo(current_version)) { // Up to date log.InfoFormat("Latest {0} is {1}", mod.Key, latest.version); bullet = (inst?.AutoInstalled ?? false) ? "+" : "-"; // Check if mod is replaceable if (current.replaced_by != null) { ModuleReplacement replacement = registry.GetReplacement(latest.identifier, ksp.VersionCriteria()); if (replacement != null) { // Replaceable! bullet = ">"; modInfo = string.Format("{0} > {1} {2}", modInfo, replacement.ReplaceWith.name, replacement.ReplaceWith.version); } } } else if (latest.version.IsGreaterThan(mod.Value)) { // Upgradable bullet = "^"; } } catch (ModuleNotFoundKraken) { log.InfoFormat("{0} is installed, but no longer in the registry", mod.Key); bullet = "?"; } } user.RaiseMessage("{0} {1}", bullet, modInfo); } } else { var stream = Console.OpenStandardOutput(); new Exporter(exportFileType.Value).Export(registry, stream); stream.Flush(); } if (!(options.porcelain) && exportFileType == null) { user.RaiseMessage("\r\nLegend: -: Up to date. +:Auto-installed. X: Incompatible. ^: Upgradable. >: Replaceable\r\n A: Autodetected. ?: Unknown. *: Broken. "); // Broken mods are in a state that CKAN doesn't understand, and therefore can't handle automatically } return(Exit.OK); }
/// <summary> /// Upgrade an installed module /// </summary> /// <param name="ksp">Game instance from which to remove</param> /// <param name="raw_options">Command line options object</param> /// <returns> /// Exit code for shell environment /// </returns> public int RunCommand(CKAN.GameInstance ksp, object raw_options) { UpgradeOptions options = (UpgradeOptions)raw_options; if (options.ckan_file != null) { options.modules.Add(MainClass.LoadCkanFromFile(ksp, options.ckan_file).identifier); } if (options.modules.Count == 0 && !options.upgrade_all) { // What? No files specified? User.RaiseMessage("Usage: ckan upgrade Mod [Mod2, ...]"); User.RaiseMessage(" or ckan upgrade --all"); if (AutoUpdate.CanUpdate) { User.RaiseMessage(" or ckan upgrade ckan"); } return(Exit.BADOPT); } if (!options.upgrade_all && options.modules[0] == "ckan" && AutoUpdate.CanUpdate) { User.RaiseMessage("Querying the latest CKAN version"); AutoUpdate.Instance.FetchLatestReleaseInfo(); var latestVersion = AutoUpdate.Instance.latestUpdate.Version; var currentVersion = new ModuleVersion(Meta.GetVersion(VersionFormat.Short)); if (latestVersion.IsGreaterThan(currentVersion)) { User.RaiseMessage("New CKAN version available - " + latestVersion); var releaseNotes = AutoUpdate.Instance.latestUpdate.ReleaseNotes; User.RaiseMessage(releaseNotes); User.RaiseMessage("\r\n"); if (User.RaiseYesNoDialog("Proceed with install?")) { User.RaiseMessage("Upgrading CKAN, please wait.."); AutoUpdate.Instance.StartUpdateProcess(false); } } else { User.RaiseMessage("You already have the latest version."); } return(Exit.OK); } try { var regMgr = RegistryManager.Instance(ksp); var registry = regMgr.registry; if (options.upgrade_all) { var to_upgrade = new List <CkanModule>(); foreach (KeyValuePair <string, ModuleVersion> mod in registry.Installed(false)) { try { // Check if upgrades are available var latest = registry.LatestAvailable(mod.Key, ksp.VersionCriteria()); // This may be an unindexed mod. If so, // skip rather than crash. See KSP-CKAN/CKAN#841. if (latest == null || latest.IsDLC) { continue; } if (latest.version.IsGreaterThan(mod.Value)) { // Upgradable log.InfoFormat("New version {0} found for {1}", latest.version, latest.identifier); to_upgrade.Add(latest); } } catch (ModuleNotFoundKraken) { log.InfoFormat("{0} is installed, but no longer in the registry", mod.Key); } } UpgradeModules(manager, User, ksp, true, to_upgrade); } else { Search.AdjustModulesCase(ksp, options.modules); UpgradeModules(manager, User, ksp, options.modules); } User.RaiseMessage(""); } catch (CancelledActionKraken k) { User.RaiseMessage("Upgrade aborted: {0}", k.Message); return(Exit.ERROR); } catch (ModuleNotFoundKraken kraken) { User.RaiseMessage("Module {0} not found", kraken.module); return(Exit.ERROR); } catch (InconsistentKraken kraken) { User.RaiseMessage(kraken.ToString()); return(Exit.ERROR); } catch (ModuleIsDLCKraken kraken) { User.RaiseMessage($"CKAN can't upgrade expansion '{kraken.module.name}' for you."); var res = kraken?.module?.resources; var storePagesMsg = new Uri[] { res?.store, res?.steamstore } .Where(u => u != null) .Aggregate("", (a, b) => $"{a}\r\n- {b}"); if (!string.IsNullOrEmpty(storePagesMsg)) { User.RaiseMessage($"To upgrade this expansion, download any updates from the store page from which you purchased it:\r\n{storePagesMsg}"); } return(Exit.ERROR); } return(Exit.OK); }
public int RunCommand(CKAN.GameInstance ksp, object raw_options) { ShowOptions options = (ShowOptions)raw_options; if (options.modules == null || options.modules.Count < 1) { // empty argument user.RaiseMessage("show <module> - module name argument missing, perhaps you forgot it?"); return(Exit.BADOPT); } int combined_exit_code = Exit.OK; // Check installed modules for an exact match. var registry = RegistryManager.Instance(ksp).registry; foreach (string modName in options.modules) { var installedModuleToShow = registry.InstalledModule(modName); if (installedModuleToShow != null) { // Show the installed module. combined_exit_code = CombineExitCodes( combined_exit_code, ShowMod(installedModuleToShow) ); if (options.with_versions) { ShowVersionTable(ksp, registry.AvailableByIdentifier(installedModuleToShow.identifier).ToList()); } user.RaiseMessage(""); continue; } // Module was not installed, look for an exact match in the available modules, // either by "name" (the user-friendly display name) or by identifier CkanModule moduleToShow = registry .CompatibleModules(ksp.VersionCriteria()) .SingleOrDefault( mod => mod.name == modName || mod.identifier == modName ); if (moduleToShow == null) { // No exact match found. Try to look for a close match for this KSP version. user.RaiseMessage( "{0} not installed or compatible with {1} {2}.", modName, ksp.game.ShortName, string.Join(", ", ksp.VersionCriteria().Versions.Select(v => v.ToString())) ); user.RaiseMessage("Looking for close matches in compatible mods..."); Search search = new Search(user); var matches = search.PerformSearch(ksp, modName); // Display the results of the search. if (!matches.Any()) { // No matches found. user.RaiseMessage("No close matches found."); combined_exit_code = CombineExitCodes(combined_exit_code, Exit.BADOPT); user.RaiseMessage(""); continue; } else if (matches.Count() == 1) { // If there is only 1 match, display it. user.RaiseMessage("Found 1 close match: {0}", matches[0].name); user.RaiseMessage(""); moduleToShow = matches[0]; } else { // Display the found close matches. int selection = user.RaiseSelectionDialog( "Close matches:", matches.Select(m => m.name).ToArray() ); user.RaiseMessage(""); if (selection < 0) { combined_exit_code = CombineExitCodes(combined_exit_code, Exit.BADOPT); continue; } // Mark the selection as the one to show. moduleToShow = matches[selection]; } } combined_exit_code = CombineExitCodes( combined_exit_code, ShowMod(moduleToShow) ); if (options.with_versions) { ShowVersionTable(ksp, registry.AvailableByIdentifier(moduleToShow.identifier).ToList()); } user.RaiseMessage(""); } return(combined_exit_code); }
public int RunCommand(CKAN.GameInstance ksp, object raw_options) { ReplaceOptions options = (ReplaceOptions)raw_options; if (options.ckan_file != null) { options.modules.Add(MainClass.LoadCkanFromFile(ksp, options.ckan_file).identifier); } if (options.modules.Count == 0 && !options.replace_all) { // What? No mods specified? User.RaiseMessage("Usage: ckan replace Mod [Mod2, ...]"); User.RaiseMessage(" or ckan replace --all"); return(Exit.BADOPT); } // Prepare options. Can these all be done in the new() somehow? var replace_ops = new RelationshipResolverOptions { with_all_suggests = options.with_all_suggests, with_suggests = options.with_suggests, with_recommends = !options.no_recommends, allow_incompatible = options.allow_incompatible }; var regMgr = RegistryManager.Instance(ksp); var registry = regMgr.registry; var to_replace = new List <ModuleReplacement>(); if (options.replace_all) { log.Debug("Running Replace all"); var installed = new Dictionary <string, ModuleVersion>(registry.Installed()); foreach (KeyValuePair <string, ModuleVersion> mod in installed) { ModuleVersion current_version = mod.Value; if ((current_version is ProvidesModuleVersion) || (current_version is UnmanagedModuleVersion)) { continue; } else { try { log.DebugFormat("Testing {0} {1} for possible replacement", mod.Key, mod.Value); // Check if replacement is available ModuleReplacement replacement = registry.GetReplacement(mod.Key, ksp.VersionCriteria()); if (replacement != null) { // Replaceable log.InfoFormat("Replacement {0} {1} found for {2} {3}", replacement.ReplaceWith.identifier, replacement.ReplaceWith.version, replacement.ToReplace.identifier, replacement.ToReplace.version); to_replace.Add(replacement); } } catch (ModuleNotFoundKraken) { log.InfoFormat("{0} is installed, but it or its replacement is not in the registry", mod.Key); } } } } else { foreach (string mod in options.modules) { try { log.DebugFormat("Checking that {0} is installed", mod); CkanModule modToReplace = registry.GetInstalledVersion(mod); if (modToReplace != null) { log.DebugFormat("Testing {0} {1} for possible replacement", modToReplace.identifier, modToReplace.version); try { // Check if replacement is available ModuleReplacement replacement = registry.GetReplacement(modToReplace.identifier, ksp.VersionCriteria()); if (replacement != null) { // Replaceable log.InfoFormat("Replacement {0} {1} found for {2} {3}", replacement.ReplaceWith.identifier, replacement.ReplaceWith.version, replacement.ToReplace.identifier, replacement.ToReplace.version); to_replace.Add(replacement); } if (modToReplace.replaced_by != null) { log.InfoFormat("Attempt to replace {0} failed, replacement {1} is not compatible", mod, modToReplace.replaced_by.name); } else { log.InfoFormat("Mod {0} has no replacement defined for the current version {1}", modToReplace.identifier, modToReplace.version); } } catch (ModuleNotFoundKraken) { log.InfoFormat("{0} is installed, but its replacement {1} is not in the registry", mod, modToReplace.replaced_by.name); } } } catch (ModuleNotFoundKraken kraken) { User.RaiseMessage("Module {0} not found", kraken.module); } } } if (to_replace.Count() != 0) { User.RaiseMessage("\r\nReplacing modules...\r\n"); foreach (ModuleReplacement r in to_replace) { User.RaiseMessage("Replacement {0} {1} found for {2} {3}", r.ReplaceWith.identifier, r.ReplaceWith.version, r.ToReplace.identifier, r.ToReplace.version); } bool ok = User.RaiseYesNoDialog("Continue?"); if (!ok) { User.RaiseMessage("Replacements canceled at user request."); return(Exit.ERROR); } // TODO: These instances all need to go. try { HashSet <string> possibleConfigOnlyDirs = null; new ModuleInstaller(ksp, manager.Cache, User).Replace(to_replace, replace_ops, new NetAsyncModulesDownloader(User, manager.Cache), ref possibleConfigOnlyDirs, regMgr); User.RaiseMessage(""); } catch (DependencyNotSatisfiedKraken ex) { User.RaiseMessage("Dependencies not satisfied for replacement, {0} requires {1} {2} but it is not listed in the index, or not available for your version of KSP.", ex.parent, ex.module, ex.version); } } else { User.RaiseMessage("No replacements found."); return(Exit.OK); } return(Exit.OK); }
/// <summary> /// Installs a module, if available /// </summary> /// <param name="ksp">Game instance into which to install</param> /// <param name="raw_options">Command line options object</param> /// <returns> /// Exit code for shell environment /// </returns> public int RunCommand(CKAN.GameInstance ksp, object raw_options) { InstallOptions options = (InstallOptions)raw_options; if (options.ckan_files != null) { // Oooh! We're installing from a CKAN file. foreach (string ckan_file in options.ckan_files) { Uri ckan_uri; // Check if the argument if a wellformatted Uri. if (!Uri.IsWellFormedUriString(ckan_file, UriKind.Absolute)) { // Assume it is a local file, check if the file exists. if (File.Exists(ckan_file)) { // Get the full path of the file. ckan_uri = new Uri(Path.GetFullPath(ckan_file)); } else { // We have no further ideas as what we can do with this Uri, tell the user. user.RaiseError("Can not find file \"{0}\".", ckan_file); user.RaiseError("Exiting."); return(Exit.ERROR); } } else { ckan_uri = new Uri(ckan_file); } string filename = String.Empty; // If it is a local file, we already know the filename. If it is remote, create a temporary file and download the remote resource. if (ckan_uri.IsFile) { filename = ckan_uri.LocalPath; log.InfoFormat("Installing from local CKAN file \"{0}\"", filename); } else { log.InfoFormat("Installing from remote CKAN file \"{0}\"", ckan_uri); filename = Net.Download(ckan_uri, null, user); log.DebugFormat("Temporary file for \"{0}\" is at \"{1}\".", ckan_uri, filename); } // Parse the JSON file. try { CkanModule m = MainClass.LoadCkanFromFile(ksp, filename); options.modules.Add($"{m.identifier}={m.version}"); } catch (Kraken kraken) { user.RaiseError(kraken.InnerException == null ? kraken.Message : $"{kraken.Message}: {kraken.InnerException.Message}"); } } // At times RunCommand() calls itself recursively - in this case we do // not want to be doing this again, so "consume" the option options.ckan_files = null; } else { Search.AdjustModulesCase(ksp, options.modules); } if (options.modules.Count == 0) { // What? No files specified? user.RaiseMessage( "Usage: ckan install [--with-suggests] [--with-all-suggests] [--no-recommends] [--headless] Mod [Mod2, ...]"); return(Exit.BADOPT); } // Prepare options. Can these all be done in the new() somehow? var install_ops = new RelationshipResolverOptions { with_all_suggests = options.with_all_suggests, with_suggests = options.with_suggests, with_recommends = !options.no_recommends, allow_incompatible = options.allow_incompatible }; if (user.Headless) { install_ops.without_toomanyprovides_kraken = true; install_ops.without_enforce_consistency = true; } RegistryManager regMgr = RegistryManager.Instance(ksp); List <string> modules = options.modules; for (bool done = false; !done;) { // Install everything requested. :) try { HashSet <string> possibleConfigOnlyDirs = null; var installer = ModuleInstaller.GetInstance(ksp, manager.Cache, user); installer.InstallList(modules, install_ops, regMgr, ref possibleConfigOnlyDirs); user.RaiseMessage(""); done = true; } catch (DependencyNotSatisfiedKraken ex) { user.RaiseError(ex.Message); user.RaiseMessage("If you're lucky, you can do a `ckan update` and try again."); user.RaiseMessage("Try `ckan install --no-recommends` to skip installation of recommended modules."); user.RaiseMessage("Or `ckan install --allow-incompatible` to ignore module compatibility."); return(Exit.ERROR); } catch (ModuleNotFoundKraken ex) { if (ex.version == null) { user.RaiseError("Module {0} required but it is not listed in the index, or not available for your version of KSP.", ex.module); } else { user.RaiseError("Module {0} {1} required but it is not listed in the index, or not available for your version of KSP.", ex.module, ex.version); } user.RaiseMessage("If you're lucky, you can do a `ckan update` and try again."); user.RaiseMessage("Try `ckan install --no-recommends` to skip installation of recommended modules."); user.RaiseMessage("Or `ckan install --allow-incompatible` to ignore module compatibility."); return(Exit.ERROR); } catch (BadMetadataKraken ex) { user.RaiseError("Bad metadata detected for module {0}: {1}", ex.module, ex.Message); return(Exit.ERROR); } catch (TooManyModsProvideKraken ex) { // Request the user selects one of the mods. string[] mods = new string[ex.modules.Count]; for (int i = 0; i < ex.modules.Count; i++) { mods[i] = String.Format("{0} ({1})", ex.modules[i].identifier, ex.modules[i].name); } string message = String.Format("Too many mods provide {0}. Please pick from the following:\r\n", ex.requested); int result; try { result = user.RaiseSelectionDialog(message, mods); } catch (Kraken e) { user.RaiseMessage(e.Message); return(Exit.ERROR); } if (result < 0) { user.RaiseMessage(String.Empty); // Looks tidier. return(Exit.ERROR); } // Add the module to the list. modules.Add($"{ex.modules[result].identifier}={ex.modules[result].version}"); // DON'T return so we can loop around and try again } catch (FileExistsKraken ex) { if (ex.owningModule != null) { user.RaiseError( "Oh no! We tried to overwrite a file owned by another mod!\r\n" + "Please try a `ckan update` and try again.\r\n\r\n" + "If this problem re-occurs, then it maybe a packaging bug.\r\n" + "Please report it at:\r\n\r\n" + "https://github.com/KSP-CKAN/NetKAN/issues/new\r\n\r\n" + "Please including the following information in your report:\r\n\r\n" + "File : {0}\r\n" + "Installing Mod : {1}\r\n" + "Owning Mod : {2}\r\n" + "CKAN Version : {3}\r\n", ex.filename, ex.installingModule, ex.owningModule, Meta.GetVersion(VersionFormat.Full) ); } else { user.RaiseError( "Oh no!\r\n\r\n" + "It looks like you're trying to install a mod which is already installed,\r\n" + "or which conflicts with another mod which is already installed.\r\n\r\n" + "As a safety feature, CKAN will *never* overwrite or alter a file\r\n" + "that it did not install itself.\r\n\r\n" + "If you wish to install {0} via CKAN,\r\n" + "then please manually uninstall the mod which owns:\r\n\r\n" + "{1}\r\n\r\n" + "and try again.\r\n", ex.installingModule, ex.filename ); } user.RaiseMessage("Your GameData has been returned to its original state."); return(Exit.ERROR); } catch (InconsistentKraken ex) { // The prettiest Kraken formats itself for us. user.RaiseError(ex.InconsistenciesPretty); user.RaiseMessage("Install canceled. Your files have been returned to their initial state."); return(Exit.ERROR); } catch (CancelledActionKraken k) { user.RaiseError("Installation aborted: {0}", k.Message); return(Exit.ERROR); } catch (MissingCertificateKraken kraken) { // Another very pretty kraken. user.RaiseError(kraken.ToString()); return(Exit.ERROR); } catch (DownloadThrottledKraken kraken) { user.RaiseError(kraken.ToString()); user.RaiseMessage("Try the authtoken command. See {0} for details.", kraken.infoUrl); return(Exit.ERROR); } catch (DownloadErrorsKraken) { user.RaiseError("One or more files failed to download, stopped."); return(Exit.ERROR); } catch (ModuleDownloadErrorsKraken kraken) { user.RaiseError(kraken.ToString()); return(Exit.ERROR); } catch (DirectoryNotFoundKraken kraken) { user.RaiseError(kraken.Message); return(Exit.ERROR); } catch (ModuleIsDLCKraken kraken) { user.RaiseError("CKAN can't install expansion '{0}' for you.", kraken.module.name); var res = kraken?.module?.resources; var storePagesMsg = new Uri[] { res?.store, res?.steamstore } .Where(u => u != null) .Aggregate("", (a, b) => $"{a}\r\n- {b}"); if (!string.IsNullOrEmpty(storePagesMsg)) { user.RaiseMessage($"To install this expansion, purchase it from one of its store pages:\r\n{storePagesMsg}"); } return(Exit.ERROR); } } return(Exit.OK); }