public void InstallModule(bool quiet, string uri) { if (quiet == true) { Module module = GetModule(uri, "Module.zip"); } else { Module module = GetModule(uri, "Module.zip"); ModuleInstaller moduleInstaller = new ModuleInstaller(ShellCore, module.Name, module.Author, module.Version, module.Copyright); moduleInstaller.Width = 810; // for some reason it f***s up moduleInstaller.ShowDialog(); if (ShellCore.ModuleInstallationAllowed == true) { InstallModule(module); } else { // clean up and return ShellCore.DeleteFileEx(module.Dll); ShellCore.DeleteFileEx("Modules/Module.xml"); ShellCore.DeleteFileEx("Module.zip"); return; } } }
private IEnumerable <InstallableFile> GetFilesBySuffix(CkanModule module, ZipFile zip, string suffix, KSP ksp = null) { return(ModuleInstaller .FindInstallableFiles(module, zip, ksp) .Where(instF => instF.source.Name.EndsWith(suffix, StringComparison.InvariantCultureIgnoreCase))); }
public IEnumerable <InstallableFile> GetPlugins(CkanModule module, ZipFile zip) { return(ModuleInstaller .FindInstallableFiles(module, zip, null) .Where(instF => instF.source.Name.EndsWith(".dll", StringComparison.InvariantCultureIgnoreCase))); }
private void Download() { ProgressScreen ps = new ProgressScreen($"Downloading {mod.identifier}"); NetAsyncModulesDownloader dl = new NetAsyncModulesDownloader(ps); ModuleInstaller inst = ModuleInstaller.GetInstance(manager.CurrentInstance, manager.Cache, ps); LaunchSubScreen( ps, () => { try { dl.DownloadModules(manager.Cache, new List <CkanModule> { mod }); if (!manager.Cache.IsMaybeCachedZip(mod)) { ps.RaiseError("Download failed, file is corrupted"); } } catch (Exception ex) { ps.RaiseError($"Download failed: {ex}"); } } ); // Don't let the installer re-use old screen references inst.User = null; }
private IEnumerable <InstallableFile> GetFilesBySuffix(CkanModule module, ZipFile zip, string suffix, GameInstance ksp) { return(ModuleInstaller .FindInstallableFiles(module, zip, ksp) .Where(instF => instF.destination.EndsWith(suffix, StringComparison.InvariantCultureIgnoreCase))); }
/// <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.KSP 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>(); ModuleInstaller inst = ModuleInstaller.GetInstance(ksp, user); inst.ImportFiles(toImport, user, id => toInstall.Add(id), !opts.Headless); if (toInstall.Count > 0) { inst.InstallList( toInstall, new RelationshipResolverOptions() ); } return(Exit.OK); } } catch (Exception ex) { user.RaiseError("Import error: {0}", ex.Message); return(Exit.ERROR); } }
// Uninstalls a module, if it exists. public int RunCommand(CKAN.KSP ksp, object raw_options) { RemoveOptions options = (RemoveOptions)raw_options; if (options.modules != null && options.modules.Count > 0) { try { var installer = ModuleInstaller.GetInstance(ksp, user); installer.UninstallList(options.modules); } 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); } } else { user.RaiseMessage("No mod selected, nothing to do"); return(Exit.BADOPT); } return(Exit.OK); }
public IEnumerable <string> FileDestinations(CkanModule module, string filePath) { return(ModuleInstaller .FindInstallableFiles(module, filePath, new KSP("/", "dummy", null, false)) .Where(f => !f.source.IsDirectory) .Select(f => f.destination)); }
/// <summary> /// Locate a version file in an archive. /// This requires a module object as we *first* search files we might install, /// falling back to a search of all files in the archive. /// Returns null if no version is found. /// Throws a Kraken if too many versions are found. /// </summary> /// <param name="module">The metadata associated with this module, used to find installable files</param> /// <param name="zipfile">The archive containing the module's files</param> /// <param name="internalFilePath">Filter for selecting a version file, either exact match or regular expression</param> /// <returns> /// Tuple consisting of the chosen file's entry in the archive plus a boolean /// indicating whether it's a file would be extracted to disk at installation /// </returns> public Tuple <ZipEntry, bool> FindInternalAvc(CkanModule module, ZipFile zipfile, string internalFilePath) { Log.DebugFormat("Finding AVC .version file for {0}", module); const string versionExt = ".version"; // Get all our version files var ksp = new GameInstance(new KerbalSpaceProgram(), "/", "dummy", new NullUser()); var files = ModuleInstaller.FindInstallableFiles(module, zipfile, ksp) .Select(x => x.source) .Where(source => source.Name.EndsWith(versionExt, StringComparison.InvariantCultureIgnoreCase)) .ToList(); // By default, we look for ones we can install var installable = true; if (files.Count == 0) { // Oh dear, no version file at all? Let's see if we can find *any* to use. files.AddRange(zipfile.Cast <ZipEntry>() .Where(file => file.Name.EndsWith(versionExt, StringComparison.InvariantCultureIgnoreCase))); if (files.Count == 0) { // Okay, there's *really* nothing there. return(null); } // Tell calling code that it may not be a "real" version file installable = false; } if (!string.IsNullOrWhiteSpace(internalFilePath)) { Regex internalRE = new Regex(internalFilePath, RegexOptions.Compiled); ZipEntry avcEntry = files .Where(f => f.Name == internalFilePath || internalRE.IsMatch(f.Name)) .FirstOrDefault(); if (avcEntry == null) { throw new Kraken( string.Format("AVC: Invalid path to remote {0}, doesn't match any of: {1}", internalFilePath, string.Join(", ", files.Select(f => f.Name)) )); } return(new Tuple <ZipEntry, bool>(avcEntry, installable)); } else if (files.Count > 1) { throw new Kraken( string.Format("Too many .version files located: {0}", string.Join(", ", files.Select(x => x.Name)))); } else { return(new Tuple <ZipEntry, bool>(files.First(), installable)); } }
public IEnumerable <string> FileDestinations(CkanModule module, string filePath) { var ksp = new KSP("/", "dummy", null, false); return(ModuleInstaller .FindInstallableFiles(module, filePath, ksp) .Where(f => !f.source.IsDirectory) .Select(f => ksp.ToRelativeGameDir(f.destination))); }
public string Download(string identifier, NetFileCache cache) { log.DebugFormat("Downloading {0}", download); string filename = ModuleInstaller.CachedOrDownload(identifier, version, download, cache); log.Debug("Downloaded."); return(filename); }
public string Download(string identifier, NetFileCache cache) { log.DebugFormat("Downloading {0}", download_path); string filename = ModuleInstaller.CachedOrDownload(identifier, friendly_version, new Uri(download_path), cache); log.Debug("Downloaded."); return(filename); }
internal static JObject HTTP(JObject orig_metadata, string remote_id, NetFileCache cache, IUser user) { var metadata = orig_metadata; // Check if we should auto-inflate. string kref = (string)metadata[expand_token]; if (kref == (string)orig_metadata[expand_token] || kref == "#/ckan/http") { log.InfoFormat("Inflating from HTTP download... {0}", metadata[expand_token]); metadata["download"] = remote_id; metadata["version"] = "0.0.0"; // add a dummy version that will be replaced by the KSP-AVC parser later metadata.Remove(expand_token); var remote_uri = new Uri(remote_id); var downloaded_file = Net.Download(remote_uri); var module = CkanModule.FromJson(metadata.ToString()); if (metadata[version_token] != null && (metadata[version_token].ToString()).StartsWith("#/ckan/ksp-avc")) { // TODO pass the correct vref here... var versionRemote = FindVersionRemote(metadata, metadata[version_token].ToString()); metadata.Remove(version_token); try { AVC avc = AVC.FromZipFile(module, downloaded_file, versionRemote.id); avc.InflateMetadata(metadata, null, null); metadata["version"] = avc.version.ToString(); module.version = avc.version; } catch (JsonReaderException) { user.RaiseMessage("Bad embedded KSP-AVC file for {0}, halting.", module); return(null); } // If we've done this, we need to re-inflate our mod, too. module = CkanModule.FromJson(metadata.ToString()); } else { throw new Kraken("No $vref specified, $kref HTTP method requires it, bailing out.."); } ModuleInstaller.CachedOrDownload(module.identifier, module.version, module.download, cache); } else { log.WarnFormat("Not inflating metadata for {0}", orig_metadata["identifier"]); } // metadata["download"] = metadata["download"].ToString() + '#' + metadata["version"].ToString(); return(metadata); }
public void Can_install_and_uninstall_modules() { // load all modules from local folder var catalogInternal = GetModuleCatalog(_CatalogSourceFolder); var modules = catalogInternal.Modules.OfType <ManifestModuleInfo>().ToArray(); // when local dependency defined, use that to create catalog if (!string.IsNullOrEmpty(_CatalogDependencySourceFolder)) { catalogInternal = GetModuleCatalog(_CatalogDependencySourceFolder); if (modules != null) { foreach (var module in modules) { catalogInternal.AddModule(module); } } } // initialize exteranl dependency loader var catalog = GetExternalModuleCatalog(catalogInternal); // make sure modules are populated catalog.Initialize(); // create installer var moduleInstaller = new ModuleInstaller(_tempDir, catalog); var progress = new Progress <ProgressMessage>(WriteProgressMessage); // list what we have defined so far ListModules(catalog); // install all modules with dependencies var modulesWithDependencies = catalog.CompleteListWithDependencies(modules) .OfType <ManifestModuleInfo>() .Where(x => !x.IsInstalled) .Except(modules) .ToArray(); moduleInstaller.Install(modules.Union(modulesWithDependencies), progress); ListModules(catalog); // validate installed modules, if it doesn't equal then modules were not installed Assert.Equal( modules.Union(modulesWithDependencies).Count(), modules.Union(modulesWithDependencies).OfType <ManifestModuleInfo>().Where(x => x.IsInstalled).Count() ); moduleInstaller.Uninstall(modules.Union(modulesWithDependencies), progress); ListModules(catalog); Assert.Equal( 0, modules.Union(modulesWithDependencies).OfType <ManifestModuleInfo>().Where(x => x.IsInstalled).Count() ); }
// Uninstalls a module, if it exists. public int RunCommand(CKAN.KSP ksp, object raw_options) { RemoveOptions options = (RemoveOptions)raw_options; // Use one (or more!) regex to select the modules to remove if (options.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 Registry registry = RegistryManager.Instance(ksp).registry; var installed = new SortedDictionary <string, Version>(registry.Installed(false)); // Try every regex on every installed module: // if it matches, select for removal foreach (string mod in installed.Keys) { 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.modules != null && options.modules.Count > 0) { try { var installer = ModuleInstaller.GetInstance(ksp, user); installer.UninstallList(options.modules); } 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); } } else { user.RaiseMessage("No mod selected, nothing to do"); return(Exit.BADOPT); } return(Exit.OK); }
public int RunCommand(CKAN.KSP ksp, object raw_options) { UpgradeOptions options = (UpgradeOptions)raw_options; if (options.ckan_file != null) { User.RaiseMessage("\nUnsupported option at this time."); return(Exit.BADOPT); } if (options.modules.Count == 0) { // What? No files specified? User.RaiseMessage("Usage: ckan upgrade Mod [Mod2, ...]"); return(Exit.BADOPT); } var to_upgrade = new List <CkanModule> (); foreach (string mod in options.modules) { Match match = Regex.Match(mod, @"^(?<mod>[^=]*)=(?<version>.*)$"); if (match.Success) { string ident = match.Groups["mod"].Value; string version = match.Groups["version"].Value; CkanModule module = ksp.Registry.GetModuleByVersion(ident, version); if (module == null) { User.RaiseMessage("Cannot install {0}, version {1} not available", ident, version); return(Exit.ERROR); } to_upgrade.Add(module); } else { to_upgrade.Add( ksp.Registry.LatestAvailable(mod, ksp.Version()) ); } } User.RaiseMessage("\nUpgrading modules...\n"); // TODO: These instances all need to go. ModuleInstaller.GetInstance(ksp, User).Upgrade(to_upgrade, new NetAsyncDownloader(User)); User.RaiseMessage("\nDone!\n"); return(Exit.OK); }
public bool HasInstallableFiles(CkanModule module, string filePath) { try { ModuleInstaller.FindInstallableFiles(module, filePath, null); } catch (BadMetadataKraken) { // TODO: DBB: Let's not use exceptions for flow control return(false); } return(true); }
/// <summary> /// Locates a version file in the zipfile specified, and returns an AVC object. /// This requires a module object as we *first* search files we might install, /// falling back to a search of all files in the archive. /// /// Returns null if no version is found. /// Throws a Kraken if too many versions are found. /// </summary> public static AVC FromZipFile(CkanModule module, ZipFile zipfile) { log.DebugFormat("Finding AVC .version file for {0}", module); string version_ext = ".version"; // Get all our version files. List <ZipEntry> files = ModuleInstaller.FindInstallableFiles(module, zipfile, null) .Select(x => x.source) .Where(source => source.Name.EndsWith(version_ext)) .ToList(); if (files.Count == 0) { // Oh dear, no version file at all? Let's see if we can find *any* to use. foreach (ZipEntry file in zipfile) { if (file.Name.EndsWith(version_ext)) { files.Add(file); } } // Okay, there's *really* nothing there. if (files.Count == 0) { return(null); } } if (files.Count > 1) { throw new Kraken( string.Format("Too may .version files located: {0}", string.Join(", ", files.Select(x => x.Name)))); } log.DebugFormat("Using AVC data from {0}", files[0].Name); // Hooray, found our entry. Extract and return it. using (var zipstream = zipfile.GetInputStream(files[0])) using (StreamReader stream = new StreamReader(zipstream)) { string json = stream.ReadToEnd(); log.DebugFormat("Parsing {0}", json); return(JsonConvert.DeserializeObject <AVC>(json)); } }
public bool HasInstallableFiles(CkanModule module, string filePath) { try { ModuleInstaller.FindInstallableFiles(module, filePath, new GameInstance(new KerbalSpaceProgram(), "/", "dummy", new NullUser())); } catch (BadMetadataKraken) { // TODO: DBB: Let's not use exceptions for flow control return(false); } return(true); }
public static ModuleInstaller GetModuleInstaller(string discoveryPath, string probingPath, string authToken, IEnumerable <string> manifestUrls) { if (_moduleInstaller == null) { var fileManager = new TransactionFileManager(); var fileSystem = new System.IO.Abstractions.FileSystem(); var zipFileWrapper = new ZipFileWrapper(fileSystem, fileManager); var localCatalogOptions = LocalModuleCatalog.GetOptions(discoveryPath, probingPath); var extCatalogOptions = ExtModuleCatalog.GetOptions(authToken, manifestUrls); var localModuleCatalog = LocalModuleCatalog.GetCatalog(localCatalogOptions); var externalModuleCatalog = ExtModuleCatalog.GetCatalog(extCatalogOptions, localModuleCatalog); var modulesClient = new ExternalModulesClient(extCatalogOptions); _moduleInstaller = new ModuleInstaller(externalModuleCatalog, modulesClient, fileManager, localCatalogOptions, fileSystem, zipFileWrapper); } return(_moduleInstaller); }
/// <summary> /// Let the user choose some zip files, then import them to the mod cache. /// </summary> /// <param name="gameInst">Game instance to import into</param> /// <param name="cp">Change plan object for marking things to be installed</param> public static void ImportDownloads(KSP gameInst, ChangePlan cp) { ConsoleFileMultiSelectDialog cfmsd = new ConsoleFileMultiSelectDialog( "Import Downloads", FindDownloadsPath(gameInst), "*.zip", "Import" ); HashSet<FileInfo> files = cfmsd.Run(); if (files.Count > 0) { ProgressScreen ps = new ProgressScreen("Importing Downloads", "Calculating..."); ModuleInstaller inst = ModuleInstaller.GetInstance(gameInst, ps); ps.Run(() => inst.ImportFiles(files, ps, (CkanModule mod) => cp.Install.Add(mod))); // Don't let the installer re-use old screen references inst.User = null; } }
/// <summary> /// Let the user choose some zip files, then import them to the mod cache. /// </summary> /// <param name="theme">The visual theme to use to draw the dialog</param> /// <param name="gameInst">Game instance to import into</param> /// <param name="cache">Cache object to import into</param> /// <param name="cp">Change plan object for marking things to be installed</param> public static void ImportDownloads(ConsoleTheme theme, GameInstance gameInst, NetModuleCache cache, ChangePlan cp) { ConsoleFileMultiSelectDialog cfmsd = new ConsoleFileMultiSelectDialog( "Import Downloads", FindDownloadsPath(gameInst), "*.zip", "Import" ); HashSet <FileInfo> files = cfmsd.Run(theme); if (files.Count > 0) { ProgressScreen ps = new ProgressScreen("Importing Downloads", "Calculating..."); ModuleInstaller inst = new ModuleInstaller(gameInst, cache, ps); ps.Run(theme, (ConsoleTheme th) => inst.ImportFiles(files, ps, (CkanModule mod) => cp.Install.Add(mod), RegistryManager.Instance(gameInst).registry)); // Don't let the installer re-use old screen references inst.User = null; } }
// Uninstalls a module, if it exists. private static int Remove(RemoveOptions options, CKAN.KSP current_instance, IUser user) { if (options.modules != null && options.modules.Count > 0) { try { var installer = ModuleInstaller.GetInstance(current_instance, user); installer.UninstallList(options.modules); return Exit.OK; } 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; } } else { user.RaiseMessage("No mod selected, nothing to do"); return Exit.BADOPT; } }
/// <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.KSP 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 = ModuleInstaller.GetInstance(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 addVersionBox(int l, int t, int r, int b, Func<string> title, Func<ConsoleColor> color, bool doubleLine, List<CkanModule> releases) { AddObject(new ConsoleFrame( l, t, r, b, title, color, doubleLine )); if (releases != null && releases.Count > 0) { ModuleVersion minMod = null, maxMod = null; KspVersion minKsp = null, maxKsp = null; Registry.GetMinMaxVersions(releases, out minMod, out maxMod, out minKsp, out maxKsp); AddObject(new ConsoleLabel( l + 2, t + 1, r - 2, () => minMod == maxMod ? $"{ModuleInstaller.WithAndWithoutEpoch(minMod?.ToString() ?? "???")}" : $"{ModuleInstaller.WithAndWithoutEpoch(minMod?.ToString() ?? "???")} - {ModuleInstaller.WithAndWithoutEpoch(maxMod?.ToString() ?? "???")}", null, color )); AddObject(new ConsoleLabel( l + 2, t + 2, r - 2, () => "Compatible with:", null, () => ConsoleTheme.Current.DimLabelFg )); AddObject(new ConsoleLabel( l + 4, t + 3, r - 2, () => KspVersionRange.VersionSpan(minKsp, maxKsp), null, color )); } }
/// <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]); } } } } }
private bool IsModuleSelectedForInstall(string identifier) { if (IsModuleInstalled(identifier)) { return(false); } IUser user = Main.Instance.CurrentInstance.User; var registry = Main.Instance.CurrentInstance.Registry; var installer = ModuleInstaller.GetInstance(Main.Instance.CurrentInstance, user); var changes = Main.Instance.mainModList.ComputeUserChangeSet(); var changeset = Main.Instance.mainModList.ComputeChangeSetFromModList(registry, changes, installer, _kspVersion).Result; foreach (var change in changeset) { if (change.ChangeType == GUIModChangeType.Install) { if (change.Mod.Identifier == identifier) { return(true); } } } return(false); }
public void Can_install_and_uninstall_modules() { // load all modules from local folder var catalogInternal = GetModuleCatalog(_CatalogSourceFolder); var modules = catalogInternal.Modules.OfType <ManifestModuleInfo>().ToArray(); // initialize exteranl dependency loader var catalog = GetExternalModuleCatalog(catalogInternal); // make sure modules are populated catalog.Initialize(); // create installer var moduleInstaller = new ModuleInstaller(_tempDir, catalog); var progress = new Progress <ProgressMessage>(WriteProgressMessage); // list what we have defined so far ListModules(catalog); // install all modules with dependencies var modulesWithDependencies = catalog.CompleteListWithDependencies(modules) .OfType <ManifestModuleInfo>() .Where(x => !x.IsInstalled) .Except(modules) .ToArray(); moduleInstaller.Install(modules.Union(modulesWithDependencies), progress); ListModules(catalog); // validate installed modules Assert.Equal(modules.Union(modulesWithDependencies).Count(), modules.Union(modulesWithDependencies).OfType <ManifestModuleInfo>().Where(x => x.IsInstalled).Count()); moduleInstaller.Uninstall(modules.Union(modulesWithDependencies), progress); ListModules(catalog); Assert.Equal(0, modules.Union(modulesWithDependencies).OfType <ManifestModuleInfo>().Where(x => x.IsInstalled).Count()); }
/// <summary> /// Initialize the screen /// </summary> /// <param name="mgr">Game instance manager object containing the current instance</param> /// <param name="dbg">True if debug options should be available, false otherwise</param> public ModListScreen(GameInstanceManager mgr, bool dbg) { debug = dbg; manager = mgr; registry = RegistryManager.Instance(manager.CurrentInstance).registry; moduleList = new ConsoleListBox <CkanModule>( 1, 4, -1, -2, GetAllMods(), new List <ConsoleListBoxColumn <CkanModule> >() { new ConsoleListBoxColumn <CkanModule>() { Header = "", Width = 1, Renderer = StatusSymbol }, new ConsoleListBoxColumn <CkanModule>() { Header = "Name", Width = 44, Renderer = m => m.name ?? "" }, new ConsoleListBoxColumn <CkanModule>() { Header = "Version", Width = 10, Renderer = m => ModuleInstaller.StripEpoch(m.version?.ToString() ?? ""), Comparer = (a, b) => a.version.CompareTo(b.version) }, new ConsoleListBoxColumn <CkanModule>() { Header = "Max game version", Width = 17, Renderer = m => registry.LatestCompatibleKSP(m.identifier)?.ToString() ?? "", Comparer = (a, b) => registry.LatestCompatibleKSP(a.identifier).CompareTo(registry.LatestCompatibleKSP(b.identifier)) } }, 1, 0, ListSortDirection.Descending, (CkanModule m, string filter) => { // Search for author if (filter.StartsWith("@")) { string authorFilt = filter.Substring(1); if (string.IsNullOrEmpty(authorFilt)) { return(true); } else { // Remove special characters from search term authorFilt = CkanModule.nonAlphaNums.Replace(authorFilt, ""); return(m.SearchableAuthors.Any((author) => author.IndexOf(authorFilt, StringComparison.CurrentCultureIgnoreCase) == 0)); } // Other special search params: installed, updatable, new, conflicting and dependends } else if (filter.StartsWith("~")) { if (filter.Length <= 1) { // Don't blank the list for just "~" by itself return(true); } else { switch (filter.Substring(1, 1)) { case "i": return(registry.IsInstalled(m.identifier, false)); case "u": return(registry.HasUpdate(m.identifier, manager.CurrentInstance.VersionCriteria())); case "n": // Filter new return(recent.Contains(m.identifier)); case "c": if (m.conflicts != null) { string conflictsWith = filter.Substring(2); // Search for mods depending on a given mod foreach (var rel in m.conflicts) { if (rel.StartsWith(conflictsWith)) { return(true); } } } return(false); case "d": if (m.depends != null) { string dependsOn = filter.Substring(2); // Search for mods depending on a given mod foreach (var rel in m.depends) { if (rel.StartsWith(dependsOn)) { return(true); } } } return(false); } } return(false); } else { filter = CkanModule.nonAlphaNums.Replace(filter, ""); return(m.SearchableIdentifier.IndexOf(filter, StringComparison.CurrentCultureIgnoreCase) >= 0 || m.SearchableName.IndexOf(filter, StringComparison.CurrentCultureIgnoreCase) >= 0 || m.SearchableAbstract.IndexOf(filter, StringComparison.CurrentCultureIgnoreCase) >= 0 || m.SearchableDescription.IndexOf(filter, StringComparison.CurrentCultureIgnoreCase) >= 0); } } ); searchBox = new ConsoleField(-searchWidth, 2, -1) { GhostText = () => Focused() == searchBox ? "<Type to search>" : "<Ctrl+F to search>" }; searchBox.OnChange += (ConsoleField sender, string newValue) => { moduleList.FilterString = newValue; }; AddObject(new ConsoleLabel( 1, 2, -searchWidth - 2, () => $"{moduleList.VisibleRowCount()} mods" )); AddObject(searchBox); AddObject(moduleList); AddBinding(Keys.CtrlQ, (object sender, ConsoleTheme theme) => false); AddBinding(Keys.AltX, (object sender, ConsoleTheme theme) => false); AddBinding(Keys.F1, (object sender, ConsoleTheme theme) => Help(theme)); AddBinding(Keys.AltH, (object sender, ConsoleTheme theme) => Help(theme)); AddBinding(Keys.F5, (object sender, ConsoleTheme theme) => UpdateRegistry(theme)); AddBinding(Keys.CtrlR, (object sender, ConsoleTheme theme) => UpdateRegistry(theme)); AddBinding(Keys.CtrlU, (object sender, ConsoleTheme theme) => UpgradeAll(theme)); // Now a bunch of convenience shortcuts so you don't get stuck in the search box searchBox.AddBinding(Keys.PageUp, (object sender, ConsoleTheme theme) => { SetFocus(moduleList); return(true); }); searchBox.AddBinding(Keys.PageDown, (object sender, ConsoleTheme theme) => { SetFocus(moduleList); return(true); }); searchBox.AddBinding(Keys.Enter, (object sender, ConsoleTheme theme) => { SetFocus(moduleList); return(true); }); moduleList.AddBinding(Keys.CtrlF, (object sender, ConsoleTheme theme) => { SetFocus(searchBox); return(true); }); moduleList.AddBinding(Keys.Escape, (object sender, ConsoleTheme theme) => { searchBox.Clear(); return(true); }); moduleList.AddTip("Enter", "Details", () => moduleList.Selection != null ); moduleList.AddBinding(Keys.Enter, (object sender, ConsoleTheme theme) => { if (moduleList.Selection != null) { LaunchSubScreen(theme, new ModInfoScreen(manager, plan, moduleList.Selection, debug)); } return(true); }); // Conditionally show only one of these based on selected mod status moduleList.AddTip("+", "Install", () => moduleList.Selection != null && !moduleList.Selection.IsDLC && !registry.IsInstalled(moduleList.Selection.identifier, false) ); moduleList.AddTip("+", "Upgrade", () => moduleList.Selection != null && !moduleList.Selection.IsDLC && registry.HasUpdate(moduleList.Selection.identifier, manager.CurrentInstance.VersionCriteria()) ); moduleList.AddTip("+", "Replace", () => moduleList.Selection != null && registry.GetReplacement(moduleList.Selection.identifier, manager.CurrentInstance.VersionCriteria()) != null ); moduleList.AddBinding(Keys.Plus, (object sender, ConsoleTheme theme) => { if (moduleList.Selection != null && !moduleList.Selection.IsDLC) { if (!registry.IsInstalled(moduleList.Selection.identifier, false)) { plan.ToggleInstall(moduleList.Selection); } else if (registry.IsInstalled(moduleList.Selection.identifier, false) && registry.HasUpdate(moduleList.Selection.identifier, manager.CurrentInstance.VersionCriteria())) { plan.ToggleUpgrade(moduleList.Selection); } else if (registry.GetReplacement(moduleList.Selection.identifier, manager.CurrentInstance.VersionCriteria()) != null) { plan.ToggleReplace(moduleList.Selection.identifier); } } return(true); }); moduleList.AddTip("-", "Remove", () => moduleList.Selection != null && !moduleList.Selection.IsDLC && registry.IsInstalled(moduleList.Selection.identifier, false) && !registry.IsAutodetected(moduleList.Selection.identifier) ); moduleList.AddBinding(Keys.Minus, (object sender, ConsoleTheme theme) => { if (moduleList.Selection != null && !moduleList.Selection.IsDLC && registry.IsInstalled(moduleList.Selection.identifier, false) && !registry.IsAutodetected(moduleList.Selection.identifier)) { plan.ToggleRemove(moduleList.Selection); } return(true); }); moduleList.AddTip("F8", "Mark auto-installed", () => moduleList.Selection != null && !moduleList.Selection.IsDLC && (!registry.InstalledModule(moduleList.Selection.identifier)?.AutoInstalled ?? false) ); moduleList.AddTip("F8", "Mark user-selected", () => moduleList.Selection != null && !moduleList.Selection.IsDLC && (registry.InstalledModule(moduleList.Selection.identifier)?.AutoInstalled ?? false) ); moduleList.AddBinding(Keys.F8, (object sender, ConsoleTheme theme) => { InstalledModule im = registry.InstalledModule(moduleList.Selection.identifier); if (im != null && !moduleList.Selection.IsDLC) { im.AutoInstalled = !im.AutoInstalled; RegistryManager.Instance(manager.CurrentInstance).Save(false); } return(true); }); AddTip("F9", "Apply changes", plan.NonEmpty); AddBinding(Keys.F9, (object sender, ConsoleTheme theme) => { ApplyChanges(theme); return(true); }); // Show total download size of all installed mods AddObject(new ConsoleLabel( 1, -1, searchWidth, () => $"{CkanModule.FmtSize(totalInstalledDownloadSize())} installed", null, th => th.DimLabelFg )); AddObject(new ConsoleLabel( -searchWidth, -1, -2, () => { int days = daysSinceUpdated(registryFilePath()); return(days < 1 ? "" : days == 1 ? $"Updated at least {days} day ago" : $"Updated at least {days} days ago"); }, null, (ConsoleTheme th) => { int daysSince = daysSinceUpdated(registryFilePath()); if (daysSince < daysTillStale) { return(th.RegistryUpToDate); } else if (daysSince < daystillVeryStale) { return(th.RegistryStale); } else { return(th.RegistryVeryStale); } } )); List <ConsoleMenuOption> opts = new List <ConsoleMenuOption>() { new ConsoleMenuOption("Sort...", "", "Change the sorting of the list of mods", true, null, null, moduleList.SortMenu()), null, new ConsoleMenuOption("Refresh mod list", "F5, Ctrl+R", "Refresh the list of mods", true, UpdateRegistry), new ConsoleMenuOption("Upgrade all", "Ctrl+U", "Mark all available updates for installation", true, UpgradeAll, null, null, HasAnyUpgradeable()), new ConsoleMenuOption("Audit recommendations", "", "List mods suggested and recommended by installed mods", true, ViewSuggestions), new ConsoleMenuOption("Import downloads...", "", "Select manually downloaded mods to import into CKAN", true, ImportDownloads), new ConsoleMenuOption("Export installed...", "", "Save your mod list", true, ExportInstalled), null, new ConsoleMenuOption("Select game instance...", "", "Switch to a different game instance", true, SelectInstall), new ConsoleMenuOption("Authentication tokens...", "", "Edit authentication tokens sent to download servers", true, EditAuthTokens), null, new ConsoleMenuOption("Help", helpKey, "Tips & tricks", true, Help), null, new ConsoleMenuOption("Quit", "Ctrl+Q", "Exit to DOS", true, (ConsoleTheme th) => false) }; if (debug) { opts.Add(null); opts.Add(new ConsoleMenuOption("DEBUG: Capture key...", "", "Print details of how your system reports a keystroke for debugging", true, CaptureKey)); } mainMenu = new ConsolePopupMenu(opts); }
/// <summary> /// Locates a version file in the zipfile specified, and returns an AVC object. /// This requires a module object as we *first* search files we might install, /// falling back to a search of all files in the archive. /// /// Returns null if no version is found. /// Throws a Kraken if too many versions are found. /// </summary> private static AvcVersion GetInternalAvc(CkanModule module, ZipFile zipfile, string internalFilePath) { Log.DebugFormat("Finding AVC .version file for {0}", module); const string versionExt = ".version"; // Get all our version files. var files = ModuleInstaller.FindInstallableFiles(module, zipfile, null) .Select(x => x.source) .Where(source => source.Name.EndsWith(versionExt)) .ToList(); if (files.Count == 0) { // Oh dear, no version file at all? Let's see if we can find *any* to use. var versionFiles = zipfile.Cast <ZipEntry>().Where(file => file.Name.EndsWith(versionExt)); files.AddRange(versionFiles); // Okay, there's *really* nothing there. if (files.Count == 0) { return(null); } } var remoteIndex = 0; if (!string.IsNullOrWhiteSpace(internalFilePath)) { remoteIndex = -1; for (var i = 0; i < files.Count; i++) { Log.DebugFormat("Testing file '{0}' against path '{1}'", files[i].Name, internalFilePath); // Test for either an exact match or using the filespec as a regexp if (internalFilePath.Equals(files[i]?.Name) || Regex.IsMatch(files[i]?.Name, internalFilePath)) { remoteIndex = i; break; } } if (remoteIndex == -1) { var remotes = files.Aggregate("", (current, file) => current + (file.Name + ", ")); throw new Kraken(string.Format("AVC: Invalid path to remote {0}, doesn't match any of: {1}", internalFilePath, remotes )); } } else if (files.Count > 1) { throw new Kraken( string.Format("Too many .version files located: {0}", string.Join(", ", files.Select(x => x.Name)))); } Log.DebugFormat("Using AVC data from {0}", files[remoteIndex].Name); // Hooray, found our entry. Extract and return it. using (var zipstream = zipfile.GetInputStream(files[remoteIndex])) using (var stream = new StreamReader(zipstream)) { var json = stream.ReadToEnd(); Log.DebugFormat("Parsing {0}", json); return(JsonConvert.DeserializeObject <AvcVersion>(json)); } }
public static ComponentInstallerBase GetInstaller(string installerType) { ComponentInstallerBase installer = null; switch (installerType) { case "File": installer = new FileInstaller(); break; case "Assembly": installer = new AssemblyInstaller(); break; case "ResourceFile": installer = new ResourceFileInstaller(); break; case "AuthenticationSystem": case "Auth_System": installer = new AuthenticationInstaller(); break; case "DashboardControl": installer = new DashboardInstaller(); break; case "Script": installer = new ScriptInstaller(); break; case "Config": installer = new ConfigInstaller(); break; case "Cleanup": installer = new CleanupInstaller(); break; case "Skin": installer = new SkinInstaller(); break; case "Container": installer = new ContainerInstaller(); break; case "Module": installer = new ModuleInstaller(); break; case "CoreLanguage": installer = new LanguageInstaller(LanguagePackType.Core); break; case "ExtensionLanguage": installer = new LanguageInstaller(LanguagePackType.Extension); break; case "Provider": installer = new ProviderInstaller(); break; case "SkinObject": installer = new SkinControlInstaller(); break; case "Widget": installer = new WidgetInstaller(); break; default: ListController listController = new ListController(); ListEntryInfo entry = listController.GetListEntryInfo("Installer", installerType); if (entry != null && !string.IsNullOrEmpty(entry.Text)) { installer = (ComponentInstallerBase)Reflection.CreateObject(entry.Text, "Installer_" + entry.Value); } break; } return installer; }