diff options
author | Jesse Plamondon-Willard <github@jplamondonw.com> | 2018-06-30 21:00:45 -0400 |
---|---|---|
committer | Jesse Plamondon-Willard <github@jplamondonw.com> | 2018-06-30 21:00:45 -0400 |
commit | c12777ad53583997dd9e1ee074e8376da827fc84 (patch) | |
tree | 78f2a4d2d02e37539a3ec1f5d74b551c65411c27 /src/StardewModdingAPI.Toolkit/Framework/ModScanning | |
parent | 34b0fd2870f0057b146dbac812cb7d673f2b11a4 (diff) | |
download | SMAPI-c12777ad53583997dd9e1ee074e8376da827fc84.tar.gz SMAPI-c12777ad53583997dd9e1ee074e8376da827fc84.tar.bz2 SMAPI-c12777ad53583997dd9e1ee074e8376da827fc84.zip |
move basic mod scanning into the toolkit (#532)
Diffstat (limited to 'src/StardewModdingAPI.Toolkit/Framework/ModScanning')
-rw-r--r-- | src/StardewModdingAPI.Toolkit/Framework/ModScanning/ModFolder.cs | 60 | ||||
-rw-r--r-- | src/StardewModdingAPI.Toolkit/Framework/ModScanning/ModScanner.cs | 103 |
2 files changed, 163 insertions, 0 deletions
diff --git a/src/StardewModdingAPI.Toolkit/Framework/ModScanning/ModFolder.cs b/src/StardewModdingAPI.Toolkit/Framework/ModScanning/ModFolder.cs new file mode 100644 index 00000000..9b6853b4 --- /dev/null +++ b/src/StardewModdingAPI.Toolkit/Framework/ModScanning/ModFolder.cs @@ -0,0 +1,60 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; +using StardewModdingAPI.Toolkit.Serialisation.Models; + +namespace StardewModdingAPI.Toolkit.Framework.ModScanning +{ + /// <summary>The info about a mod read from its folder.</summary> + public class ModFolder + { + /********* + ** Accessors + *********/ + /// <summary>The Mods subfolder containing this mod.</summary> + public DirectoryInfo SearchDirectory { get; } + + /// <summary>The folder containing manifest.json.</summary> + public DirectoryInfo ActualDirectory { get; } + + /// <summary>The mod manifest.</summary> + public Manifest Manifest { get; } + + /// <summary>The error which occurred parsing the manifest, if any.</summary> + public string ManifestParseError { get; } + + + /********* + ** Public methods + *********/ + /// <summary>Construct an instance when a mod wasn't found in a folder.</summary> + /// <param name="searchDirectory">The directory that was searched.</param> + public ModFolder(DirectoryInfo searchDirectory) + { + this.SearchDirectory = searchDirectory; + } + + /// <summary>Construct an instance.</summary> + /// <param name="searchDirectory">The Mods subfolder containing this mod.</param> + /// <param name="actualDirectory">The folder containing manifest.json.</param> + /// <param name="manifest">The mod manifest.</param> + /// <param name="manifestParseError">The error which occurred parsing the manifest, if any.</param> + public ModFolder(DirectoryInfo searchDirectory, DirectoryInfo actualDirectory, Manifest manifest, string manifestParseError = null) + { + this.SearchDirectory = searchDirectory; + this.ActualDirectory = actualDirectory; + this.Manifest = manifest; + this.ManifestParseError = manifestParseError; + } + + /// <summary>Get the update keys for a mod.</summary> + /// <param name="manifest">The mod manifest.</param> + public IEnumerable<string> GetUpdateKeys(Manifest manifest) + { + return + (manifest.UpdateKeys ?? new string[0]) + .Where(p => !string.IsNullOrWhiteSpace(p)) + .ToArray(); + } + } +} diff --git a/src/StardewModdingAPI.Toolkit/Framework/ModScanning/ModScanner.cs b/src/StardewModdingAPI.Toolkit/Framework/ModScanning/ModScanner.cs new file mode 100644 index 00000000..d3662c9c --- /dev/null +++ b/src/StardewModdingAPI.Toolkit/Framework/ModScanning/ModScanner.cs @@ -0,0 +1,103 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using StardewModdingAPI.Toolkit.Serialisation; +using StardewModdingAPI.Toolkit.Serialisation.Models; + +namespace StardewModdingAPI.Toolkit.Framework.ModScanning +{ + /// <summary>Scans folders for mod data.</summary> + public class ModScanner + { + /********* + ** Properties + *********/ + /// <summary>The JSON helper with which to read manifests.</summary> + private readonly JsonHelper JsonHelper; + + + /********* + ** Public methods + *********/ + /// <summary>Construct an instance.</summary> + /// <param name="jsonHelper">The JSON helper with which to read manifests.</param> + public ModScanner(JsonHelper jsonHelper) + { + this.JsonHelper = jsonHelper; + } + + /// <summary>Extract information about all mods in the given folder.</summary> + /// <param name="rootPath">The root folder containing mods.</param> + public IEnumerable<ModFolder> GetModFolders(string rootPath) + { + foreach (DirectoryInfo folder in new DirectoryInfo(rootPath).EnumerateDirectories()) + yield return this.ReadFolder(rootPath, folder); + } + + /// <summary>Extract information from a mod folder.</summary> + /// <param name="rootPath">The root folder containing mods.</param> + /// <param name="searchFolder">The folder to search for a mod.</param> + public ModFolder ReadFolder(string rootPath, DirectoryInfo searchFolder) + { + // find manifest.json + FileInfo manifestFile = this.FindManifest(searchFolder); + if (manifestFile == null) + return new ModFolder(searchFolder); + + // read mod info + Manifest manifest = null; + string manifestError = null; + { + try + { + manifest = this.JsonHelper.ReadJsonFile<Manifest>(manifestFile.FullName); + if (manifest == null) + { + manifestError = File.Exists(manifestFile.FullName) + ? "its manifest is invalid." + : "it doesn't have a manifest."; + } + } + catch (SParseException ex) + { + manifestError = $"parsing its manifest failed: {ex.Message}"; + } + catch (Exception ex) + { + manifestError = $"parsing its manifest failed:\n{ex}"; + } + } + + return new ModFolder(searchFolder, manifestFile.Directory, manifest, manifestError); + } + + + /********* + ** Private methods + *********/ + /// <summary>Find the manifest for a mod folder.</summary> + /// <param name="folder">The folder to search.</param> + private FileInfo FindManifest(DirectoryInfo folder) + { + while (true) + { + // check for manifest in current folder + FileInfo file = new FileInfo(Path.Combine(folder.FullName, "manifest.json")); + if (file.Exists) + return file; + + // check for single subfolder + FileSystemInfo[] entries = folder.EnumerateFileSystemInfos().Take(2).ToArray(); + if (entries.Length == 1 && entries[0] is DirectoryInfo subfolder) + { + folder = subfolder; + continue; + } + + // not found + return null; + } + } + } +} |