First Native compilation test passes

This commit is contained in:
Timothy Baldridge 2020-10-18 13:03:50 -06:00
parent c5c444b707
commit 18ac41729d
10 changed files with 435 additions and 66 deletions

View File

@ -180,7 +180,7 @@ namespace Wabbajack.Lib
{
if (UseGamePaths)
{
foreach (var ag in Settings.IncludedGames)
foreach (var ag in Settings.IncludedGames.Cons(CompilingGame.Game))
{
try
{

View File

@ -13,7 +13,7 @@ namespace Wabbajack.Lib.CompilationSteps
{
}
public static int GetFilePriority(MO2Compiler compiler, VirtualFile file)
public static int GetFilePriority(ACompiler compiler, VirtualFile file)
{
var archive = file.TopParent;
var adata = compiler.ArchivesByFullPath[archive.AbsoluteName];
@ -26,12 +26,11 @@ namespace Wabbajack.Lib.CompilationSteps
public override async ValueTask<Directive?> Run(RawSourceFile source)
{
var mo2Compiler = (MO2Compiler)_compiler;
if (!_compiler.IndexedFiles.TryGetValue(source.Hash, out var found)) return null;
var result = source.EvolveTo<FromArchive>();
var match = found.Where(f => f.Name.FileName == source.Path.FileName)
.OrderBy(f => GetFilePriority(mo2Compiler, f))
.OrderBy(f => GetFilePriority(_compiler, f))
.ThenBy(f => f.NestingFactor)
.FirstOrDefault()
?? found.OrderBy(f => f.NestingFactor).FirstOrDefault();

View File

@ -77,7 +77,7 @@ namespace Wabbajack.Lib
Info("Using Profiles: " + string.Join(", ", SelectedProfiles.OrderBy(p => p)));
Utils.Log($"Compiling Game: {CompilingGame}");
Utils.Log($"Compiling Game: {CompilingGame.Game}");
Utils.Log("Games from setting files:");
foreach (var game in Settings.IncludedGames)
{

View File

@ -0,0 +1,289 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Wabbajack.Common;
using Wabbajack.Lib.CompilationSteps;
using Wabbajack.Lib.Validation;
using Wabbajack.VirtualFileSystem;
namespace Wabbajack.Lib
{
public class NativeCompiler : ACompiler
{
public NativeCompiler(NativeCompilerSettings settings, AbsolutePath sourcePath, AbsolutePath downloadsPath, AbsolutePath outputModListPath)
: base(3, settings.ModListName, sourcePath, downloadsPath, outputModListPath)
{
CompilingGame = settings.CompilingGame.MetaData();
GamePath = CompilingGame.GameLocation();
NativeSettings = settings;
}
public NativeCompilerSettings NativeSettings { get; set; }
protected override async Task<bool> _Begin(CancellationToken cancel)
{
await Metrics.Send("begin_compiling", ModListName ?? "unknown");
if (cancel.IsCancellationRequested)
{
return false;
}
DesiredThreads.OnNext(DiskThreads);
FileExtractor2.FavorPerfOverRAM = FavorPerfOverRam;
UpdateTracker.Reset();
UpdateTracker.NextStep("Gathering information");
Utils.Log($"Compiling Game: {CompilingGame.Game}");
Utils.Log("Games from setting files:");
foreach (var game in Settings.IncludedGames)
{
Utils.Log($"- {game}");
}
Utils.Log($"VFS File Location: {VFSCacheName}");
Utils.Log($"MO2 Folder: {SourcePath}");
Utils.Log($"Downloads Folder: {DownloadsPath}");
Utils.Log($"Game Folder: {GamePath}");
var watcher = new DiskSpaceWatcher(cancel,
new[] {SourcePath, DownloadsPath, GamePath, AbsolutePath.EntryPoint}, (long)2 << 31,
drive =>
{
Utils.Log($"Aborting due to low space on {drive.Name}");
Abort();
});
var watcherTask = watcher.Start();
if (cancel.IsCancellationRequested)
{
return false;
}
List<AbsolutePath> roots = new List<AbsolutePath> {SourcePath, GamePath, DownloadsPath};
roots.AddRange(Settings.IncludedGames.Select(g => g.MetaData().GameLocation()));
UpdateTracker.NextStep("Indexing folders");
if (cancel.IsCancellationRequested)
{
return false;
}
await VFS.AddRoots(roots);
UpdateTracker.NextStep("Cleaning output folder");
await ModListOutputFolder.DeleteDirectory();
if (cancel.IsCancellationRequested)
{
return false;
}
UpdateTracker.NextStep("Inferring metas for game file downloads");
await InferMetas();
if (cancel.IsCancellationRequested)
{
return false;
}
UpdateTracker.NextStep("Reindexing downloads after meta inferring");
await VFS.AddRoot(DownloadsPath);
if (cancel.IsCancellationRequested)
{
return false;
}
UpdateTracker.NextStep("Pre-validating Archives");
// Find all Downloads
IndexedArchives = (await DownloadsPath.EnumerateFiles()
.Where(f => f.WithExtension(Consts.MetaFileExtension).Exists)
.PMap(Queue,
async f => new IndexedArchive(VFS.Index.ByRootPath[f])
{
Name = (string)f.FileName,
IniData = f.WithExtension(Consts.MetaFileExtension).LoadIniFile(),
Meta = await f.WithExtension(Consts.MetaFileExtension).ReadAllTextAsync()
})).ToList();
await IndexGameFileHashes();
IndexedArchives = IndexedArchives.DistinctBy(a => a.File.AbsoluteName).ToList();
await CleanInvalidArchivesAndFillState();
UpdateTracker.NextStep("Finding Install Files");
ModListOutputFolder.CreateDirectory();
var mo2Files = SourcePath.EnumerateFiles()
.Where(p => p.IsFile)
.Select(p =>
{
if (!VFS.Index.ByRootPath.ContainsKey(p))
{
Utils.Log($"WELL THERE'S YOUR PROBLEM: {p} {VFS.Index.ByRootPath.Count}");
}
return new RawSourceFile(VFS.Index.ByRootPath[p], p.RelativeTo(SourcePath));
});
// If Game Folder Files exists, ignore the game folder
IndexedFiles = IndexedArchives.SelectMany(f => f.File.ThisAndAllChildren)
.OrderBy(f => f.NestingFactor)
.GroupBy(f => f.Hash)
.ToDictionary(f => f.Key, f => f.AsEnumerable());
AllFiles.SetTo(mo2Files
.DistinctBy(f => f.Path));
Info($"Found {AllFiles.Count} files to build into mod list");
if (cancel.IsCancellationRequested)
{
return false;
}
UpdateTracker.NextStep("Verifying destinations");
var dups = AllFiles.GroupBy(f => f.Path)
.Where(fs => fs.Count() > 1)
.Select(fs =>
{
Utils.Log(
$"Duplicate files installed to {fs.Key} from : {String.Join(", ", fs.Select(f => f.AbsolutePath))}");
return fs;
}).ToList();
if (dups.Count > 0)
{
Error($"Found {dups.Count} duplicates, exiting");
}
if (cancel.IsCancellationRequested)
{
return false;
}
UpdateTracker.NextStep("Loading INIs");
ArchivesByFullPath = IndexedArchives.ToDictionary(a => a.File.AbsoluteName);
if (cancel.IsCancellationRequested)
{
return false;
}
var stack = MakeStack();
UpdateTracker.NextStep("Running Compilation Stack");
var results = await AllFiles.PMap(Queue, UpdateTracker, f => RunStack(stack, f));
// Add the extra files that were generated by the stack
if (cancel.IsCancellationRequested)
{
return false;
}
var noMatch = results.OfType<NoMatch>().ToArray();
PrintNoMatches(noMatch);
if (CheckForNoMatchExit(noMatch))
{
return false;
}
foreach (var ignored in results.OfType<IgnoredDirectly>())
{
Utils.Log($"Ignored {ignored.To} because {ignored.Reason}");
}
InstallDirectives.SetTo(results.Where(i => !(i is IgnoredDirectly)));
Info("Getting Nexus api_key, please click authorize if a browser window appears");
UpdateTracker.NextStep("Building Patches");
await BuildPatches();
UpdateTracker.NextStep("Gathering Archives");
await GatherArchives();
UpdateTracker.NextStep("Gathering Metadata");
await GatherMetaData();
ModList = new ModList
{
GameType = CompilingGame.Game,
WabbajackVersion = Consts.CurrentMinimumWabbajackVersion,
Archives = SelectedArchives.ToList(),
ModManager = ModManager.MO2,
Directives = InstallDirectives,
Name = ModListName ?? "untitled",
Author = ModListAuthor ?? "",
Description = ModListDescription ?? "",
Readme = ModlistReadme ?? "",
Image = ModListImage != default ? ModListImage.FileName : default,
Website = !string.IsNullOrWhiteSpace(ModListWebsite) ? new Uri(ModListWebsite) : null,
Version = ModlistVersion ?? new Version(1, 0, 0, 0),
IsNSFW = ModlistIsNSFW
};
UpdateTracker.NextStep("Including required files");
await InlineFiles();
UpdateTracker.NextStep("Running Validation");
await ValidateModlist.RunValidation(ModList);
UpdateTracker.NextStep("Generating Report");
GenerateManifest();
UpdateTracker.NextStep("Exporting Modlist");
await ExportModList();
ResetMembers();
UpdateTracker.NextStep("Done Building Modlist");
return true;
}
/// <summary>
/// Clear references to lists that hold a lot of data.
/// </summary>
private void ResetMembers()
{
AllFiles = new List<RawSourceFile>();
InstallDirectives = new List<Directive>();
SelectedArchives = new List<Archive>();
}
public override AbsolutePath GamePath { get; }
public override IEnumerable<ICompilationStep> GetStack()
{
return MakeStack();
}
public override IEnumerable<ICompilationStep> MakeStack()
{
List<ICompilationStep> steps = NativeSettings.CompilationSteps.Select(InterpretStep).ToList();
steps.Add(new DropAll(this));
return steps;
}
public ICompilationStep InterpretStep(string[] step)
{
return step[0] switch
{
"IgnoreStartsWith" => new IgnoreStartsWith(this, step[1]),
"IncludeConfigs" => new IncludeAllConfigs(this),
"IncludeDirectMatches" => new DirectMatch(this),
"IncludePatches" => new IncludePatches(this),
_ => throw new ArgumentException($"No interpretation for step {step[0]}")
};
}
}
}

View File

@ -0,0 +1,14 @@
using Wabbajack.Common;
namespace Wabbajack.Lib
{
public class NativeCompilerSettings : CompilerSettings
{
public Game CompilingGame { get; set; }
public string ModListName { get; set; } = "untitled";
public string[][] CompilationSteps = new string[0][];
}
}

View File

@ -36,8 +36,8 @@ namespace Wabbajack.Test
protected async Task<MO2Compiler> ConfigureAndRunCompiler(string profile, bool useGameFiles= false)
{
var compiler = new MO2Compiler(
sourcePath: utils.MO2Folder,
downloadsPath: utils.DownloadsFolder,
sourcePath: utils.SourcePath,
downloadsPath: utils.DownloadsPath,
mo2Profile: profile,
outputFile: OutputFile(profile));
compiler.UseGamePaths = useGameFiles;
@ -52,13 +52,35 @@ namespace Wabbajack.Test
await Install(compiler);
return compiler.ModList;
}
protected async Task<NativeCompiler> ConfigureAndRunCompiler(AbsolutePath configPath, bool useGameFiles= false)
{
var settings = configPath.FromJson<NativeCompilerSettings>();
var profile = utils.AddProfile();
var compiler = new NativeCompiler(
settings: settings,
sourcePath: utils.SourcePath,
downloadsPath: utils.DownloadsPath,
outputModListPath: OutputFile(profile))
{UseGamePaths = useGameFiles};
Assert.True(await compiler.Begin());
return compiler;
}
protected async Task<ModList> CompileAndInstall(AbsolutePath settingsPath, bool useGameFiles = false)
{
var compiler = await ConfigureAndRunCompiler(settingsPath, useGameFiles: useGameFiles);
Utils.Log("Finished Compiling");
await Install(compiler);
return compiler.ModList;
}
private static AbsolutePath OutputFile(string profile)
{
return ((RelativePath)profile).RelativeToEntryPoint().WithExtension(Consts.ModListExtension);
}
protected async Task Install(MO2Compiler compiler)
protected async Task Install(ACompiler compiler)
{
Utils.Log("Loading Modlist");
var modlist = AInstaller.LoadFromFile(compiler.ModListOutputFile);
@ -66,8 +88,8 @@ namespace Wabbajack.Test
var installer = new MO2Installer(
archive: compiler.ModListOutputFile,
modList: modlist,
outputFolder: utils.InstallFolder,
downloadFolder: utils.DownloadsFolder,
outputFolder: utils.InstallPath,
downloadFolder: utils.DownloadsPath,
parameters: CreateDummySystemParameters());
installer.WarnOnOverwrite = false;
installer.GameFolder = utils.GameFolder;

View File

@ -52,7 +52,7 @@ namespace Wabbajack.Test
await DownloadAndInstall(
"https://github.com/ModOrganizer2/modorganizer/releases/download/v2.2.1/Mod.Organizer.2.2.1.7z",
"Mod.Organizer.2.2.1.7z");
await utils.DownloadsFolder.Combine("Mod.Organizer.2.2.1.7z.meta").WriteAllLinesAsync(
await utils.DownloadsPath.Combine("Mod.Organizer.2.2.1.7z.meta").WriteAllLinesAsync(
"[General]",
"directURL=https://github.com/ModOrganizer2/modorganizer/releases/download/v2.2.1/Mod.Organizer.2.2.1.7z"
);
@ -75,7 +75,7 @@ namespace Wabbajack.Test
$"matchAll= {modfiles[2].Download.FileName}"
);
await utils.MO2Folder.Combine("startup.bat").WriteAllLinesAsync(
await utils.SourcePath.Combine("startup.bat").WriteAllLinesAsync(
"ModOrganizer2.exe SKSE"
);
@ -83,11 +83,11 @@ namespace Wabbajack.Test
await CompileAndInstall(profile);
await utils.VerifyAllFiles();
await utils.InstallFolder.Combine(Consts.LOOTFolderFilesDir).DeleteDirectory();
await utils.InstallPath.Combine(Consts.LOOTFolderFilesDir).DeleteDirectory();
var compiler = new MO2Compiler(
sourcePath: utils.InstallFolder,
downloadsPath: utils.DownloadsFolder,
sourcePath: utils.InstallPath,
downloadsPath: utils.DownloadsPath,
mo2Profile: profile,
outputFile: profile.RelativeTo(AbsolutePath.EntryPoint).WithExtension(Consts.ModListExtension));
Assert.True(await compiler.Begin());
@ -105,12 +105,12 @@ namespace Wabbajack.Test
await state.Download(new Archive(state: null!) { Name = "Unknown"}, src);
}
utils.DownloadsFolder.CreateDirectory();
utils.DownloadsPath.CreateDirectory();
var destFile = utils.DownloadsFolder.Combine(filename);
var destFile = utils.DownloadsPath.Combine(filename);
await src.CopyToAsync(destFile);
var modFolder = modName == null ? utils.MO2Folder : utils.ModsFolder.Combine(modName);
var modFolder = modName == null ? utils.SourcePath : utils.ModsPath.Combine(modName);
await FileExtractor2.ExtractAll(Queue, src, modFolder);
return (destFile, modFolder);
}
@ -140,12 +140,12 @@ namespace Wabbajack.Test
await state.Download(src);
}
utils.DownloadsFolder.CreateDirectory();
utils.DownloadsPath.CreateDirectory();
var dest = utils.DownloadsFolder.Combine(file.file_name);
var dest = utils.DownloadsPath.Combine(file.file_name);
await src.CopyToAsync(dest);
var modFolder = utils.ModsFolder.Combine(modName);
var modFolder = utils.ModsPath.Combine(modName);
await FileExtractor2.ExtractAll(Queue, src, modFolder);
await dest.WithExtension(Consts.MetaFileExtension).WriteAllTextAsync(ini);
@ -165,8 +165,8 @@ namespace Wabbajack.Test
var installer = new MO2Installer(
archive: compiler.ModListOutputFile,
modList: modlist,
outputFolder: utils.InstallFolder,
downloadFolder: utils.DownloadsFolder,
outputFolder: utils.InstallPath,
downloadFolder: utils.DownloadsPath,
parameters: ACompilerTest.CreateDummySystemParameters())
{
UseCompression = true
@ -178,8 +178,8 @@ namespace Wabbajack.Test
private async Task<MO2Compiler> ConfigureAndRunCompiler(string profile)
{
var compiler = new MO2Compiler(
sourcePath: utils.MO2Folder,
downloadsPath: utils.DownloadsFolder,
sourcePath: utils.SourcePath,
downloadsPath: utils.DownloadsPath,
mo2Profile: profile,
outputFile: profile.RelativeTo(AbsolutePath.EntryPoint).WithExtension(Consts.ModListExtension));
Assert.True(await compiler.Begin());

View File

@ -54,7 +54,7 @@ namespace Wabbajack.Test
await utils.AddManualDownload(
new Dictionary<string, byte[]> {{"/baz/biz.pex", await testPex.ReadAllBytesAsync()}});
await utils.DownloadsFolder.Combine("some_other_file.7z").WriteAllTextAsync("random data");
await utils.DownloadsPath.Combine("some_other_file.7z").WriteAllTextAsync("random data");
await CompileAndInstall(profile);
@ -90,14 +90,14 @@ namespace Wabbajack.Test
await utils.Configure();
utils.MO2Folder.Combine(Consts.GameFolderFilesDir).CreateDirectory();
utils.SourcePath.Combine(Consts.GameFolderFilesDir).CreateDirectory();
await utils.AddManualDownload(
new Dictionary<string, byte[]> {{"/baz/biz.pex", await testPex.ReadAllBytesAsync()}});
await CompileAndInstall(profile);
Assert.False(utils.InstallFolder.Combine(Consts.GameFolderFilesDir, (RelativePath)@"enbstuff\test.pex").IsFile);
Assert.False(utils.InstallPath.Combine(Consts.GameFolderFilesDir, (RelativePath)@"enbstuff\test.pex").IsFile);
}
[Fact]
@ -188,12 +188,12 @@ namespace Wabbajack.Test
var profile = utils.AddProfile();
var mod = await utils.AddMod("dummy");
var saveFolder = utils.MO2Folder.Combine("profiles", profile, "saves");
var saveFolder = utils.SourcePath.Combine("profiles", profile, "saves");
saveFolder.CreateDirectory();
await saveFolder.Combine("incompilation").WriteAllTextAsync("ignore this");
var installSaveFolderThisProfile = utils.InstallFolder.Combine("profiles", profile, "saves");
var installSaveFolderOtherProfile = utils.InstallFolder.Combine("profiles", "Other Profile", "saves");
var installSaveFolderThisProfile = utils.InstallPath.Combine("profiles", profile, "saves");
var installSaveFolderOtherProfile = utils.InstallPath.Combine("profiles", "Other Profile", "saves");
installSaveFolderThisProfile.CreateDirectory();
installSaveFolderOtherProfile.CreateDirectory();
@ -215,7 +215,7 @@ namespace Wabbajack.Test
var mod = await utils.AddMod("dummy");
await utils.Configure();
await utils.MO2Folder.Combine("profiles", profile, "somegameprefs.ini").WriteAllLinesAsync(
await utils.SourcePath.Combine("profiles", profile, "somegameprefs.ini").WriteAllLinesAsync(
// Beth inis are messy, let's make ours just as messy to catch some parse failures
"[Display]",
"foo=4",
@ -231,7 +231,7 @@ namespace Wabbajack.Test
var modlist = await CompileAndInstall(profile);
var ini = utils.InstallFolder.Combine("profiles", profile, "somegameprefs.ini").LoadIniFile();
var ini = utils.InstallPath.Combine("profiles", profile, "somegameprefs.ini").LoadIniFile();
var sysinfo = CreateDummySystemParameters();
@ -511,7 +511,7 @@ namespace Wabbajack.Test
await new CompilerSettings()
{
IncludedGames = new []{Game.Morrowind}
}.ToJsonAsync(utils.MO2Folder.Combine("profiles", profile, CompilerSettings.FileName), true);
}.ToJsonAsync(utils.SourcePath.Combine("profiles", profile, CompilerSettings.FileName), true);
Game.SkyrimSpecialEdition.MetaData().CanSourceFrom = new[] {Game.Morrowind, Game.Skyrim};
@ -540,7 +540,7 @@ namespace Wabbajack.Test
await utils.VerifyInstalledFile(mod, @"Data\SkyrimSE\Update.esm.old");
await utils.VerifyInstalledFile(mod, @"Data\SkyrimSE\Update.esm");
Assert.False(utils.InstallFolder.Combine(Consts.GameFolderFilesDir).IsDirectory);
Assert.False(utils.InstallPath.Combine(Consts.GameFolderFilesDir).IsDirectory);
}
@ -554,8 +554,8 @@ namespace Wabbajack.Test
await utils.Configure();
utils.MO2Folder.Combine(Consts.GameFolderFilesDir).CreateDirectory();
await utils.MO2Folder.Combine(Consts.GameFolderFilesDir).Combine("dx4242.dll")
utils.SourcePath.Combine(Consts.GameFolderFilesDir).CreateDirectory();
await utils.SourcePath.Combine(Consts.GameFolderFilesDir).Combine("dx4242.dll")
.WriteAllBytesAsync(utils.RandomData());
await utils.AddManualDownload(
@ -580,7 +580,7 @@ namespace Wabbajack.Test
var disabledMod = await utils.AddMod();
var disabledTestPex = await utils.AddModFile(disabledMod, @"Data\scripts\disabledTestPex.pex", 10);
await disabledMod.RelativeTo(utils.ModsFolder).Combine("meta.ini").WriteAllLinesAsync(
await disabledMod.RelativeTo(utils.ModsPath).Combine("meta.ini").WriteAllLinesAsync(
"[General]",
$"notes={Consts.WABBAJACK_ALWAYS_ENABLE}");
@ -602,7 +602,7 @@ namespace Wabbajack.Test
await utils.VerifyInstalledFile(enabledMod, @"Data\scripts\enabledTestPex.pex");
await utils.VerifyInstalledFile(disabledMod, @"Data\scripts\disabledTestPex.pex");
var modlistTxt = await utils.InstallFolder.Combine("profiles", profile, "modlist.txt").ReadAllLinesAsync();
var modlistTxt = await utils.InstallPath.Combine("profiles", profile, "modlist.txt").ReadAllLinesAsync();
Assert.Equal(new string[]
{
$"-{disabledMod}",
@ -610,5 +610,43 @@ namespace Wabbajack.Test
}, modlistTxt.ToArray());
}
[Fact]
public async Task CanCompileFromNativeSource()
{
utils.CreatePaths();
var gameFolder = Game.SkyrimSpecialEdition.MetaData().GameLocation();
await gameFolder.Combine("SkyrimSE.exe").CopyToAsync(utils.SourcePath.Combine("SkyrimSE.exe"));
var some_dds = utils.SourcePath.Combine("some_file.dds");
await some_dds.WriteAllBytesAsync(utils.RandomData());
await utils.AddManualDownload(
new Dictionary<string, byte[]>
{
{"/file1.blerg", await some_dds.ReadAllBytesAsync()},
});
var settings = new NativeCompilerSettings
{
CompilingGame = Game.SkyrimSpecialEdition,
CompilationSteps = new []
{
new []{"IgnoreStartsWith", "downloads"},
new []{"IncludeConfigs"},
new []{"IncludeDirectMatches"},
}
};
var settingsPath = utils.SourcePath.Combine("native_compiler_settings.json");
await settings.ToJsonAsync(utils.SourcePath.Combine("native_compiler_settings.json"), true);
await CompileAndInstall(settingsPath, true);
Assert.Equal(await some_dds.FileHashAsync(), await utils.InstallPath.Combine("some_file.dds").FileHashAsync());
Assert.Equal(await gameFolder.Combine("SkyrimSE.exe").FileHashAsync(),
await utils.InstallPath.Combine("SkyrimSE.exe").FileHashAsync());
}
}
}

View File

@ -32,11 +32,11 @@ namespace Wabbajack.Test
public AbsolutePath TestFolder => WorkingDirectory.Combine(ID);
public AbsolutePath GameFolder => WorkingDirectory.Combine(ID, "game_folder");
public AbsolutePath MO2Folder => WorkingDirectory.Combine(ID, "mo2_folder");
public AbsolutePath ModsFolder => MO2Folder.Combine(Consts.MO2ModFolderName);
public AbsolutePath DownloadsFolder => MO2Folder.Combine("downloads");
public AbsolutePath SourcePath => WorkingDirectory.Combine(ID, "source_folder");
public AbsolutePath ModsPath => SourcePath.Combine(Consts.MO2ModFolderName);
public AbsolutePath DownloadsPath => SourcePath.Combine("downloads");
public AbsolutePath InstallFolder => TestFolder.Combine("installed");
public AbsolutePath InstallPath => TestFolder.Combine("installed");
public HashSet<string> Profiles = new HashSet<string>();
@ -44,20 +44,20 @@ namespace Wabbajack.Test
public async Task Configure(IEnumerable<(string ModName, bool IsEnabled)> enabledMods = null)
{
await MO2Folder.Combine("ModOrganizer.ini").WriteAllLinesAsync(
await SourcePath.Combine("ModOrganizer.ini").WriteAllLinesAsync(
"[General]",
$"gameName={Game.MetaData().MO2Name}",
$"gamePath={((string)GameFolder).Replace("\\", "\\\\")}",
$"download_directory={DownloadsFolder}");
$"download_directory={DownloadsPath}");
DownloadsFolder.CreateDirectory();
DownloadsPath.CreateDirectory();
GameFolder.Combine("Data").CreateDirectory();
if (enabledMods == null)
{
Profiles.Do(profile =>
{
MO2Folder.Combine("profiles", profile, "modlist.txt").WriteAllLinesAsync(
SourcePath.Combine("profiles", profile, "modlist.txt").WriteAllLinesAsync(
Mods.Select(s => $"+{s}").ToArray());
});
}
@ -65,7 +65,7 @@ namespace Wabbajack.Test
{
Profiles.Do(profile =>
{
MO2Folder.Combine("profiles", profile, "modlist.txt").WriteAllLinesAsync(
SourcePath.Combine("profiles", profile, "modlist.txt").WriteAllLinesAsync(
enabledMods.Select(s => $"{(s.IsEnabled ? "+" : "-")}{s.ModName}").ToArray());
});
}
@ -74,7 +74,7 @@ namespace Wabbajack.Test
public string AddProfile(string name = null)
{
string profile_name = name ?? RandomName();
MO2Folder.Combine("profiles", profile_name).CreateDirectory();
SourcePath.Combine("profiles", profile_name).CreateDirectory();
Profiles.Add(profile_name);
return profile_name;
}
@ -82,7 +82,7 @@ namespace Wabbajack.Test
public async Task<string> AddMod(string name = null)
{
string mod_name = name ?? RandomName();
var mod_folder = MO2Folder.Combine(Consts.MO2ModFolderName, (RelativePath)mod_name);
var mod_folder = SourcePath.Combine(Consts.MO2ModFolderName, (RelativePath)mod_name);
mod_folder.CreateDirectory();
await mod_folder.Combine("meta.ini").WriteAllTextAsync("[General]");
Mods.Add(mod_name);
@ -99,7 +99,7 @@ namespace Wabbajack.Test
/// <returns></returns>
public async Task<AbsolutePath> AddModFile(string mod_name, string path, int random_fill=128)
{
var full_path = ModsFolder.Combine(mod_name, path);
var full_path = ModsPath.Combine(mod_name, path);
full_path.Parent.CreateDirectory();
await GenerateRandomFileData(full_path, random_fill);
return full_path;
@ -161,7 +161,7 @@ namespace Wabbajack.Test
{
var name = RandomName() + ".zip";
await using FileStream fs = await DownloadsFolder.Combine(name).Create();
await using FileStream fs = await DownloadsPath.Combine(name).Create();
using ZipArchive archive = new ZipArchive(fs, ZipArchiveMode.Create);
contents.Do(kv =>
{
@ -170,7 +170,7 @@ namespace Wabbajack.Test
os.Write(kv.Value, 0, kv.Value.Length);
});
await DownloadsFolder.Combine(name + Consts.MetaFileExtension).WriteAllLinesAsync(
await DownloadsPath.Combine(name + Consts.MetaFileExtension).WriteAllLinesAsync(
"[General]",
"manualURL=<TESTING>"
);
@ -180,10 +180,10 @@ namespace Wabbajack.Test
public async Task VerifyInstalledFile(string mod, string file)
{
var src = MO2Folder.Combine((string)Consts.MO2ModFolderName, mod, file);
var src = SourcePath.Combine((string)Consts.MO2ModFolderName, mod, file);
Assert.True(src.Exists);
var dest = InstallFolder.Combine((string)Consts.MO2ModFolderName, mod, file);
var dest = InstallPath.Combine((string)Consts.MO2ModFolderName, mod, file);
Assert.True(dest.Exists, $"Destination {dest} doesn't exist");
var srcData = await src.ReadAllBytesAsync();
@ -203,7 +203,7 @@ namespace Wabbajack.Test
var src = GameFolder.Combine(file);
Assert.True(src.Exists);
var dest = InstallFolder.Combine((string)Consts.GameFolderFilesDir, file);
var dest = InstallPath.Combine((string)Consts.GameFolderFilesDir, file);
Assert.True(dest.Exists);
var srcData = await src.ReadAllBytesAsync();
@ -219,7 +219,7 @@ namespace Wabbajack.Test
}
public AbsolutePath PathOfInstalledFile(string mod, string file)
{
return InstallFolder.Combine((string)Consts.MO2ModFolderName, mod, file);
return InstallPath.Combine((string)Consts.MO2ModFolderName, mod, file);
}
public async ValueTask VerifyAllFiles(bool gameFileShouldNotExistInGameFolder = true)
@ -228,32 +228,32 @@ namespace Wabbajack.Test
{
foreach (var file in Game.MetaData().RequiredFiles!)
{
Assert.False(InstallFolder.Combine(Consts.GameFolderFilesDir, (RelativePath)file).Exists);
Assert.False(InstallPath.Combine(Consts.GameFolderFilesDir, (RelativePath)file).Exists);
}
}
var skipFiles = new []{"portable.txt"}.Select(e => (RelativePath)e).ToHashSet();
foreach (var destFile in InstallFolder.EnumerateFiles())
foreach (var destFile in InstallPath.EnumerateFiles())
{
var relFile = destFile.RelativeTo(InstallFolder);
if (destFile.InFolder(Consts.LOOTFolderFilesDir.RelativeTo(MO2Folder)) || destFile.InFolder(Consts.GameFolderFilesDir.RelativeTo(MO2Folder)))
var relFile = destFile.RelativeTo(InstallPath);
if (destFile.InFolder(Consts.LOOTFolderFilesDir.RelativeTo(SourcePath)) || destFile.InFolder(Consts.GameFolderFilesDir.RelativeTo(SourcePath)))
continue;
if (!skipFiles.Contains(relFile))
Assert.True(MO2Folder.Combine(relFile).Exists, $"Only in Destination: {relFile}");
Assert.True(SourcePath.Combine(relFile).Exists, $"Only in Destination: {relFile}");
}
var skipExtensions = new []{".txt", ".ini"}.Select(e => new Extension(e)).ToHashSet();
foreach (var srcFile in MO2Folder.EnumerateFiles())
foreach (var srcFile in SourcePath.EnumerateFiles())
{
var relFile = srcFile.RelativeTo(MO2Folder);
var relFile = srcFile.RelativeTo(SourcePath);
if (relFile.StartsWith("downloads\\"))
continue;
var destFile = InstallFolder.Combine(relFile);
var destFile = InstallPath.Combine(relFile);
Assert.True(destFile.Exists, $"Only in Source: {relFile}");
if (!skipExtensions.Contains(srcFile.Extension))
@ -271,5 +271,12 @@ namespace Wabbajack.Test
await GenerateRandomFileData(fullPath, i);
return fullPath;
}
public void CreatePaths()
{
SourcePath.CreateDirectory();
DownloadsPath.CreateDirectory();
InstallPath.CreateDirectory();
}
}
}

View File

@ -236,7 +236,7 @@ namespace Wabbajack.VirtualFileSystem
}
}
await filesByParent[top].PMap(queue, async file => await HandleFile(file, new ExtractedNativeFile(file.AbsoluteName)));
await filesByParent[top].PMap(queue, async file => await HandleFile(file, new ExtractedNativeFile(file.AbsoluteName) {CanMove = false}));
}
#region KnownFiles