// TODO: This needs work! See GH #160. private static int Upgrade(UpgradeOptions options) { if (options.ckan_file == null) { // Typical case, install from cached CKAN info. if (options.modules.Count == 0) { // What? No files specified? User.WriteLine( "Usage: ckan upgrade [--with-suggests] [--with-all-suggests] [--no-recommends] Mod [Mod2, ...]"); return(Exit.BADOPT); } // Do our un-installs and re-installs in a transaction. If something goes wrong, // we put the user's data back the way it was. (Both Install and Uninstall support transactions.) using (var transaction = new TransactionScope()) { var installer = ModuleInstaller.Instance; try { installer.UninstallList(options.modules); } catch (ModNotInstalledKraken kraken) { User.WriteLine("I can't do that, {0} is not installed.", kraken.mod); return(Exit.BADOPT); } // Prepare options. Can these all be done in the new() somehow? var install_ops = new RelationshipResolverOptions(); install_ops.with_all_suggests = options.with_all_suggests; install_ops.with_suggests = options.with_suggests; install_ops.with_recommends = !options.no_recommends; // Install everything requested. :) try { installer.InstallList(options.modules, install_ops); } catch (ModuleNotFoundKraken ex) { User.WriteLine("Module {0} required, but not listed in index.", ex.module); User.WriteLine("If you're lucky, you can do a `ckan update` and try again."); return(Exit.ERROR); } transaction.Complete(); } User.WriteLine("\nDone!\n"); return(Exit.OK); } User.WriteLine("\nUnsupported option at this time."); return(Exit.BADOPT); }
public void Setup() { registry = CKAN.Registry.Empty(); options = RelationshipResolver.DefaultOpts(); generator = new RandomModuleGenerator(new Random(0451)); //Sanity checker means even incorrect RelationshipResolver logic was passing options.without_enforce_consistency = true; }
public void Constructor_WithoutModules_AlwaysReturns() { registry = Registry.Empty(); options = RelationshipResolver.DefaultOpts(); Assert.DoesNotThrow(() => new RelationshipResolver(new List <string>(), options, registry)); }
public void Constructor_WithoutModules_AlwaysReturns() { registry = CKAN.Registry.Empty(); options = RelationshipResolver.DefaultOpts(); Assert.DoesNotThrow(() => new RelationshipResolver(new List <CfanModuleIdAndVersion>(), options, registry, null)); }
private static int Install(InstallOptions options, CKAN.KSP current_instance, IUser user) { if (options.ckan_file != null) { // Oooh! We're installing from a CKAN file. log.InfoFormat("Installing from CKAN file {0}", options.ckan_file); CkanModule module = CkanModule.FromFile(options.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); // Add our module to the things we should install... options.modules.Add(module.identifier); // And continue with our install as per normal. } if (options.modules.Count == 0) { // What? No files specified? user.RaiseMessage( "Usage: ckan install [--with-suggests] [--with-all-suggests] [--no-recommends] 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 }; // Install everything requested. :) try { var installer = ModuleInstaller.GetInstance(current_instance, user); installer.InstallList(options.modules, install_ops); } catch (ModuleNotFoundKraken ex) { user.RaiseMessage("Module {0} required, but not listed in index, or not available for your version of KSP", ex.module); 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"); return Exit.ERROR; } catch (BadMetadataKraken ex) { user.RaiseMessage("Bad metadata detected for module {0}", ex.module); user.RaiseMessage(ex.Message); return Exit.ERROR; } catch (TooManyModsProvideKraken ex) { user.RaiseMessage("Too many mods provide {0}. Please pick from the following:\n", ex.requested); foreach (CkanModule mod in ex.modules) { user.RaiseMessage("* {0} ({1})", mod.identifier, mod.name); } user.RaiseMessage(String.Empty); // Looks tidier. return Exit.ERROR; } catch (FileExistsKraken ex) { if (ex.owning_module != null) { user.RaiseMessage( "\nOh no! We tried to overwrite a file owned by another mod!\n"+ "Please try a `ckan update` and try again.\n\n"+ "If this problem re-occurs, then it maybe a packaging bug.\n"+ "Please report it at:\n\n" + "https://github.com/KSP-CKAN/CKAN-meta/issues/new\n\n"+ "Please including the following information in your report:\n\n" + "File : {0}\n" + "Installing Mod : {1}\n" + "Owning Mod : {2}\n" + "CKAN Version : {3}\n", ex.filename, ex.installing_module, ex.owning_module, Meta.Version() ); } else { user.RaiseMessage( "\n\nOh no!\n\n"+ "It looks like you're trying to install a mod which is already installed,\n"+ "or which conflicts with another mod which is already installed.\n\n"+ "As a safety feature, the CKAN will *never* overwrite or alter a file\n"+ "that it did not install itself.\n\n"+ "If you wish to install {0} via the CKAN,\n"+ "then please manually uninstall the mod which owns:\n\n"+ "{1}\n\n"+"and try again.\n", ex.installing_module, ex.filename ); } user.RaiseMessage("Your GameData has been returned to its original state.\n"); return Exit.ERROR; } catch (InconsistentKraken ex) { // The prettiest Kraken formats itself for us. user.RaiseMessage(ex.InconsistenciesPretty); return Exit.ERROR; } catch (CancelledActionKraken) { user.RaiseMessage("Installation cancelled at user request."); return Exit.ERROR; } catch (MissingCertificateKraken kraken) { // Another very pretty kraken. user.RaiseMessage(kraken.ToString()); return Exit.ERROR; } catch (DownloadErrorsKraken) { user.RaiseMessage("One or more files failed to download, stopped."); return Exit.ERROR; } return Exit.OK; }
void MigrateMods(object sender, DoWorkEventArgs e) { SetStatus("Starting mod migration process"); SetProgressMarquee(); var registry = Main.Instance.CurrentInstance.Registry; var identifiers = (List <string>)e.Argument; foreach (var identifier in identifiers) { CkanModule module = null; try { module = registry.LatestAvailable(identifier, Main.Instance.CurrentInstance.Version()); } catch (Exception ex) { e.Result = ex; return; } if (module == null) { e.Result = null; return; } var installer = ModuleInstaller.GetInstance(Main.Instance.CurrentInstance, Main.Instance.m_User); SetStatus(String.Format("Downloading mod - {0}", identifier)); string zip = installer.CachedOrDownload(module); var files = ModuleInstaller.FindInstallableFiles(module, new ZipFile(zip), Main.Instance.CurrentInstance); SetStatus(String.Format("Removing existing files for {0}", identifier)); foreach (var file in files) { if (File.Exists(file.destination)) { try { File.Delete(file.destination); log.InfoFormat("Deleted \"{0}\"", file); } catch (Exception ex) { log.WarnFormat("Failed to delete \"{0}\" - {1}", file, ex.Message); break; } } } SetStatus("Scanning GameData"); Main.Instance.CurrentInstance.ScanGameData(); SetStatus("Unregistering auto-detected module"); // registry.DeregisterModule(Main.Instance.CurrentInstance, identifier); var opts = new RelationshipResolverOptions() { with_all_suggests = false, with_recommends = true, with_suggests = false, without_toomanyprovides_kraken = true }; SetStatus(String.Format("Installing {0} using CKAN", identifier)); installer.User = new NullUser(); bool success = false; while (!success) { try { installer.InstallList(new List <string>() { identifier }, opts); success = true; } catch (FileExistsKraken ex) { File.Delete(Path.Combine(Main.Instance.CurrentInstance.GameDir(), ex.filename)); } catch (Exception ex) { e.Result = ex; return; } } } }
public int RunCommand(CKAN.KSP 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 = 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; } // Install everything requested. :) try { var installer = ModuleInstaller.GetInstance(ksp, user); installer.InstallList(options.modules, install_ops); } catch (DependencyNotSatisfiedKraken ex) { if (ex.version == null) { user.RaiseMessage("{0} requires {1} but it is not listed in the index, or not available for your version of KSP.", ex.parent, ex.module); } else { user.RaiseMessage("{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); } 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.RaiseMessage("Module {0} required but it is not listed in the index, or not available for your version of KSP.", ex.module); } else { user.RaiseMessage("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.RaiseMessage("Bad metadata detected for module {0}.", ex.module); user.RaiseMessage(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. options.modules.Add(ex.modules[result].identifier); return(new Install(user).RunCommand(ksp, options)); } catch (FileExistsKraken ex) { if (ex.owningModule != null) { user.RaiseMessage( "\r\nOh 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.RaiseMessage( "\r\n\r\nOh 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, the 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 the 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.\r\n"); return(Exit.ERROR); } catch (InconsistentKraken ex) { // The prettiest Kraken formats itself for us. user.RaiseMessage(ex.InconsistenciesPretty); user.RaiseMessage("Install canceled. Your files have been returned to their initial state."); return(Exit.ERROR); } catch (CancelledActionKraken) { user.RaiseMessage("Installation canceled at user request."); return(Exit.ERROR); } catch (MissingCertificateKraken kraken) { // Another very pretty kraken. user.RaiseMessage(kraken.ToString()); return(Exit.ERROR); } catch (DownloadThrottledKraken kraken) { user.RaiseMessage(kraken.ToString()); user.RaiseMessage($"Try the authtoken command. See {kraken.infoUrl} for details."); return(Exit.ERROR); } catch (DownloadErrorsKraken) { user.RaiseMessage("One or more files failed to download, stopped."); return(Exit.ERROR); } catch (ModuleDownloadErrorsKraken kraken) { user.RaiseMessage(kraken.ToString()); return(Exit.ERROR); } catch (DirectoryNotFoundKraken kraken) { user.RaiseMessage("\r\n{0}", kraken.Message); return(Exit.ERROR); } return(Exit.OK); }
public int RunCommand(CKAN.KSP 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) { log.InfoFormat("Installing from local CKAN file \"{0}\"", filename); filename = ckan_uri.LocalPath; } 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. options.modules.Add(LoadCkanFromFile(ksp, filename).identifier); } // 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; } 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 }; if (user.Headless) { install_ops.without_toomanyprovides_kraken = true; install_ops.without_enforce_consistency = true; } // Install everything requested. :) try { var installer = ModuleInstaller.GetInstance(ksp, user); installer.InstallList(options.modules, install_ops); } catch (ModuleNotFoundKraken ex) { user.RaiseMessage("Module {0} required, but not listed in index, or not available for your version of KSP", ex.module); 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"); return Exit.ERROR; } catch (BadMetadataKraken ex) { user.RaiseMessage("Bad metadata detected for module {0}", ex.module); user.RaiseMessage(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. options.modules.Add(ex.modules[result].identifier); return (new Install(user).RunCommand(ksp, options)); } catch (FileExistsKraken ex) { if (ex.owningModule != null) { user.RaiseMessage( "\r\nOh 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.Version() ); } else { user.RaiseMessage( "\r\n\r\nOh 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, the 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 the 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.\r\n"); return Exit.ERROR; } catch (InconsistentKraken ex) { // The prettiest Kraken formats itself for us. user.RaiseMessage(ex.InconsistenciesPretty); user.RaiseMessage("Install canceled. Your files have been returned to their initial state."); return Exit.ERROR; } catch (CancelledActionKraken) { user.RaiseMessage("Installation canceled at user request."); return Exit.ERROR; } catch (MissingCertificateKraken kraken) { // Another very pretty kraken. user.RaiseMessage(kraken.ToString()); return Exit.ERROR; } catch (DownloadErrorsKraken) { user.RaiseMessage("One or more files failed to download, stopped."); return Exit.ERROR; } catch (DirectoryNotFoundKraken kraken) { user.RaiseMessage("\r\n{0}", kraken.Message); return Exit.ERROR; } return Exit.OK; }
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); }
public int RunCommand(CKAN.KSP 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) { log.InfoFormat("Installing from local CFAN file \"{0}\"", filename); filename = ckan_uri.LocalPath; } else { log.InfoFormat("Installing from remote CFAN 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. options.modules.Add(LoadCkanFromFile(ksp, filename).identifier); } // 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; } 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 }; if (user.Headless) { install_ops.without_toomanyprovides_kraken = true; install_ops.without_enforce_consistency = true; } // Install everything requested. :) try { var installer = ModuleInstaller.GetInstance(ksp, user); var modules = options.modules.Select(p => new CfanModuleIdAndVersion(p)); installer.InstallList(modules, install_ops); } catch (ModuleAndVersionStringInvalidKraken ex) { user.RaiseMessage("One of mod names given was invalid, it has to be a module identifier, or in a format of <modId>=<modVersion>."); user.RaiseMessage("Mod identifier can only contain letters, digits, hyphen, space and underscore"); user.RaiseMessage("Mod version must be in the format x.y.z"); user.RaiseMessage($"Invalid string was: {ex.givenString}."); return(Exit.ERROR); } catch (ModuleNotFoundKraken ex) { user.RaiseMessage("Module {0} required, but not listed in index, or not available for your version of Factorio", ex.module); user.RaiseMessage("If you're lucky, you can do a `cfan update` and try again."); user.RaiseMessage("Try `cfan install --no-recommends` to skip installation of recommended modules"); return(Exit.ERROR); } catch (BadMetadataKraken ex) { user.RaiseMessage("Bad metadata detected for module {0}", ex.module); user.RaiseMessage(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].title); } string message = String.Format("Too many mods provide {0}. Please pick from the following:\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. options.modules.Add(ex.modules[result].identifier); return(new Install(user).RunCommand(ksp, options)); } catch (FileExistsKraken ex) { if (ex.owning_module != null) { user.RaiseMessage( "\nOh no! We tried to overwrite a file owned by another mod!\n" + "Please try a `cfan update` and try again.\n\n" + "If this problem re-occurs, then it maybe a packaging bug.\n" + "Please report it at:\n\n" + // @todo: add link here "(here should be a link to my github issues)\n" + "(but I screwed up and forgot to add it, sorry)\n\n" + //"https://github.com/KSP-CKAN/CKAN-meta/issues/new\n\n"+ "Please including the following information in your report:\n\n" + "File : {0}\n" + "Installing Mod : {1}\n" + "Owning Mod : {2}\n" + "CFAN Version : {3}\n", ex.filename, ex.installing_module, ex.owning_module, Meta.Version() ); } else { user.RaiseMessage( "\n\nOh no!\n\n" + "It looks like you're trying to install a mod which is already installed,\n" + "or which conflicts with another mod which is already installed.\n\n" + "As a safety feature, the CFAN will *never* overwrite or alter a file\n" + "that it did not install itself.\n\n" + "If you wish to install {0} via the CFAN,\n" + "then please manually uninstall the mod which owns:\n\n" + "{1}\n\n" + "and try again.\n", ex.installing_module, ex.filename ); } user.RaiseMessage("Your GameData has been returned to its original state.\n"); return(Exit.ERROR); } catch (InconsistentKraken ex) { // The prettiest Kraken formats itself for us. user.RaiseMessage(ex.InconsistenciesPretty); user.RaiseMessage("Install canceled. Your files have been returned to their initial state."); return(Exit.ERROR); } catch (CancelledActionKraken) { user.RaiseMessage("Installation canceled at user request."); return(Exit.ERROR); } catch (MissingCertificateKraken kraken) { // Another very pretty kraken. user.RaiseMessage(kraken.ToString()); return(Exit.ERROR); } catch (DownloadErrorsKraken) { user.RaiseMessage("One or more files failed to download, stopped."); return(Exit.ERROR); } catch (DirectoryNotFoundKraken kraken) { user.RaiseMessage("\n{0}", kraken.Message); return(Exit.ERROR); } return(Exit.OK); }