public void ToRelative() { string absolute = Path.Combine(ksp_dir, "GameData/HydrazinePrincess"); Assert.AreEqual( "GameData/HydrazinePrincess", ksp.ToRelativeGameDir(absolute) ); }
/// <summary> /// Ensures all files for this module have relative paths. /// Called when upgrading registry versions. Should be a no-op /// if called on newer registries. /// </summary> public void Renormalise(GameInstance ksp) { var normalised_installed_files = new Dictionary <string, InstalledModuleFile>(); foreach (KeyValuePair <string, InstalledModuleFile> tuple in installed_files) { string path = CKANPathUtils.NormalizePath(tuple.Key); if (Path.IsPathRooted(path)) { path = ksp.ToRelativeGameDir(path); } normalised_installed_files[path] = tuple.Value; } installed_files = normalised_installed_files; }
/// <summary> /// Set up the display for interaction. /// This is separate from Wait so we can set up /// before the calling code switches to the tab. /// </summary> /// <param name="possibleConfigOnlyDirs">Directories that the user may want to delete</param> public void LoadDirs(GameInstance ksp, HashSet <string> possibleConfigOnlyDirs) { instance = ksp; var items = possibleConfigOnlyDirs .OrderBy(d => d) .Select(d => new ListViewItem(instance.ToRelativeGameDir(d).Replace('/', Path.DirectorySeparatorChar)) { Tag = d, Checked = true }) .ToArray(); Util.Invoke(this, () => { DirectoriesListView.Items.Clear(); DirectoriesListView.Items.AddRange(items); DirectoriesListView.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent); DirectoriesListView_ItemSelectionChanged(null, null); }); }
/// <summary> /// Ensures all files for this module have relative paths. /// Called when upgrading registry versions. Should be a no-op /// if called on newer registries. /// </summary> public void Renormalise(GameInstance ksp) { // We need case insensitive path matching on Windows var normalised_installed_files = Platform.IsWindows ? new Dictionary <string, InstalledModuleFile>(StringComparer.OrdinalIgnoreCase) : new Dictionary <string, InstalledModuleFile>(); foreach (KeyValuePair <string, InstalledModuleFile> tuple in installed_files) { string path = CKANPathUtils.NormalizePath(tuple.Key); if (Path.IsPathRooted(path)) { path = ksp.ToRelativeGameDir(path); } normalised_installed_files[path] = tuple.Value; } installed_files = normalised_installed_files; }
/// <summary> /// Given an open zipfile, returns all files that would be installed /// for this stanza. /// /// If a KSP instance is provided, it will be used to generate output paths, otherwise these will be null. /// /// Throws a BadInstallLocationKraken if the install stanza targets an /// unknown install location (eg: not GameData, Ships, etc) /// /// Throws a BadMetadataKraken if the stanza resulted in no files being returned. /// </summary> /// <exception cref="BadInstallLocationKraken">Thrown when the installation path is not valid according to the spec.</exception> public List <InstallableFile> FindInstallableFiles(ZipFile zipfile, GameInstance ksp) { string installDir; var files = new List <InstallableFile>(); // Normalize the path before doing everything else string install_to = CKANPathUtils.NormalizePath(this.install_to); // The installation path cannot contain updirs if (install_to.Contains("/../") || install_to.EndsWith("/..")) { throw new BadInstallLocationKraken("Invalid installation path: " + install_to); } if (ksp == null) { installDir = null; } else if (install_to == ksp.game.PrimaryModDirectoryRelative || install_to.StartsWith($"{ksp.game.PrimaryModDirectoryRelative}/")) { // The installation path can be either "GameData" or a sub-directory of "GameData" string subDir = install_to.Substring(ksp.game.PrimaryModDirectoryRelative.Length); // remove "GameData" subDir = subDir.StartsWith("/") ? subDir.Substring(1) : subDir; // remove a "/" at the beginning, if present // Add the extracted subdirectory to the path of KSP's GameData installDir = CKANPathUtils.NormalizePath(ksp.game.PrimaryModDirectory(ksp) + "/" + subDir); } else { switch (install_to) { case "GameRoot": installDir = ksp.GameDir(); break; default: if (ksp.game.AllowInstallationIn(install_to, out string path)) { installDir = ksp.ToAbsoluteGameDir(path); } else { throw new BadInstallLocationKraken("Unknown install_to " + install_to); } break; } } EnsurePattern(); // `find` is supposed to match the "topmost" folder. Find it. var shortestMatch = find == null ? (int?)null : zipfile.Cast <ZipEntry>() .Select(entry => inst_pattern.Match(entry.Name.Replace('\\', '/'))) .Where(match => match.Success) .DefaultIfEmpty() .Min(match => match?.Index); // O(N^2) solution, as we're walking the zipfile for each stanza. // Surely there's a better way, although this is fast enough we may not care. foreach (ZipEntry entry in zipfile) { // Skips dirs and things not prescribed by our install stanza. if (!IsWanted(entry.Name, shortestMatch)) { continue; } // Prepare our file info. InstallableFile file_info = new InstallableFile { source = entry, makedir = false, destination = null }; // If we have a place to install it, fill that in... if (installDir != null) { // Get the full name of the file. // Update our file info with the install location file_info.destination = TransformOutputName( ksp.game, entry.Name, installDir, @as); file_info.makedir = AllowDirectoryCreation( ksp.game, ksp?.ToRelativeGameDir(file_info.destination) ?? file_info.destination); } files.Add(file_info); } // If we have no files, then something is wrong! (KSP-CKAN/CKAN#93) if (files.Count == 0) { // We have null as the first argument here, because we don't know which module we're installing throw new BadMetadataKraken(null, String.Format("No files found matching {0} to install!", DescribeMatch())); } return(files); }