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
{
/// Scans folders for mod data.
public class ModScanner
{
/*********
** Properties
*********/
/// The JSON helper with which to read manifests.
private readonly JsonHelper JsonHelper;
/*********
** Public methods
*********/
/// Construct an instance.
/// The JSON helper with which to read manifests.
public ModScanner(JsonHelper jsonHelper)
{
this.JsonHelper = jsonHelper;
}
/// Extract information about all mods in the given folder.
/// The root folder containing mods.
public IEnumerable GetModFolders(string rootPath)
{
foreach (DirectoryInfo folder in new DirectoryInfo(rootPath).EnumerateDirectories())
yield return this.ReadFolder(rootPath, folder);
}
/// Extract information from a mod folder.
/// The root folder containing mods.
/// The folder to search for a mod.
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(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
*********/
/// Find the manifest for a mod folder.
/// The folder to search.
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;
}
}
}
}