Installation optimizations and fixes

This commit is contained in:
Timothy Baldridge 2020-09-10 19:22:07 -06:00
parent d3ea54f4e2
commit d7371294f9
4 changed files with 54 additions and 21 deletions

View File

@ -334,7 +334,6 @@ namespace Wabbajack.Lib
.PMap(Queue, UpdateTracker, async f => .PMap(Queue, UpdateTracker, async f =>
{ {
var relativeTo = f.RelativeTo(OutputFolder); var relativeTo = f.RelativeTo(OutputFolder);
Utils.Status($"Checking if ModList file {relativeTo}");
if (indexed.ContainsKey(relativeTo) || f.InFolder(DownloadFolder)) if (indexed.ContainsKey(relativeTo) || f.InFolder(DownloadFolder))
return; return;
@ -378,17 +377,19 @@ namespace Wabbajack.Lib
Utils.Log("Error when trying to clean empty folders. This doesn't really matter."); Utils.Log("Error when trying to clean empty folders. This doesn't really matter.");
} }
var existingfiles = OutputFolder.EnumerateFiles().ToHashSet();
UpdateTracker.NextStep("Looking for unmodified files"); UpdateTracker.NextStep("Looking for unmodified files");
(await indexed.Values.PMap(Queue, UpdateTracker, async d => (await indexed.Values.PMap(Queue, UpdateTracker, async d =>
{ {
// Bit backwards, but we want to return null for // Bit backwards, but we want to return null for
// all files we *want* installed. We return the files // all files we *want* installed. We return the files
// to remove from the install list. // to remove from the install list.
Status($"Optimizing {d.To}");
var path = OutputFolder.Combine(d.To); var path = OutputFolder.Combine(d.To);
if (!path.Exists) return null; if (!existingfiles.Contains(path)) return null;
if (path.Size != d.Size) return null; if (path.Size != d.Size) return null;
Status($"Optimizing {d.To}");
return await path.FileHashCachedAsync() == d.Hash ? d : null; return await path.FileHashCachedAsync() == d.Hash ? d : null;
})) }))

View File

@ -248,23 +248,19 @@ namespace Wabbajack.Lib
private async Task InstallIncludedDownloadMetas() private async Task InstallIncludedDownloadMetas()
{ {
await ModList.Directives await ModList.Archives
.OfType<ArchiveMeta>() .PMap(Queue, async archive =>
.PMap(Queue, async directive =>
{ {
Status($"Writing .meta file {directive.To}"); if (HashedArchives.TryGetValue(archive.Hash, out var paths))
foreach (var archive in ModList.Archives)
{ {
if (HashedArchives.TryGetValue(archive.Hash, out var paths)) var metaPath = paths.WithExtension(Consts.MetaFileExtension);
if (!metaPath.Exists)
{ {
var metaPath = paths.WithExtension(Consts.MetaFileExtension); Status($"Writing {metaPath.FileName}");
if (!metaPath.Exists) var meta = AddInstalled(archive.State.GetMetaIni()).ToArray();
{ await metaPath.WriteAllLinesAsync(meta);
var meta = AddInstalled(archive.State.GetMetaIni()).ToArray();
await metaPath.WriteAllLinesAsync(meta);
}
} }
} }
}); });
} }

View File

@ -55,10 +55,10 @@ namespace Wabbajack.VirtualFileSystem.Test
var results = await FileExtractor2.GatheringExtract(new NativeFileStreamFactory(archive.Path), var results = await FileExtractor2.GatheringExtract(new NativeFileStreamFactory(archive.Path),
_ => true, _ => true,
async (path, sfn) => async (path, sfn) =>
{ {
await using var s = await sfn.GetStream(); await using var s = await sfn.GetStream();
return await s.xxHashAsync(); return await s.xxHashAsync();
}); });
Assert.Equal(10, results.Count); Assert.Equal(10, results.Count);
foreach (var (path, hash) in results) foreach (var (path, hash) in results)
@ -67,6 +67,35 @@ namespace Wabbajack.VirtualFileSystem.Test
} }
} }
[Fact]
public async Task CanExtractEmptyFiles()
{
await using var temp = await TempFolder.Create();
await using var archive = new TempFile();
for (int i = 0; i < 1; i ++)
{
await WriteRandomData(temp.Dir.Combine($"{i}.bin"), _rng.Next(10, 1024));
}
await (await temp.Dir.Combine("empty.txt").Create()).DisposeAsync();
await ZipUpFolder(temp.Dir, archive.Path, false);
var results = await FileExtractor2.GatheringExtract(new NativeFileStreamFactory(archive.Path),
_ => true,
async (path, sfn) =>
{
await using var s = await sfn.GetStream();
return await s.xxHashAsync();
});
Assert.Equal(2, results.Count);
foreach (var (path, hash) in results)
{
Assert.Equal(await temp.Dir.Combine(path).FileHashAsync(), hash);
}
}
private static Extension OMODExtension = new Extension(".omod"); private static Extension OMODExtension = new Extension(".omod");
private static Extension CRCExtension = new Extension(".crc"); private static Extension CRCExtension = new Extension(".crc");

View File

@ -25,7 +25,6 @@ namespace Wabbajack.VirtualFileSystem
public GatheringExtractor(Stream stream, Definitions.FileType sig, Predicate<RelativePath> shouldExtract, Func<RelativePath,IStreamFactory, ValueTask<T>> mapfn) public GatheringExtractor(Stream stream, Definitions.FileType sig, Predicate<RelativePath> shouldExtract, Func<RelativePath,IStreamFactory, ValueTask<T>> mapfn)
{ {
_shouldExtract = shouldExtract; _shouldExtract = shouldExtract;
_mapFn = mapfn; _mapFn = mapfn;
_results = new Dictionary<RelativePath, T>(); _results = new Dictionary<RelativePath, T>();
@ -89,6 +88,14 @@ namespace Wabbajack.VirtualFileSystem
{ {
if (_indexes.ContainsKey(index)) if (_indexes.ContainsKey(index))
{ {
var path = _indexes[index].Item1;
Utils.Status($"Extracting {path}", Percent.FactoryPutInRange(_results.Count, _indexes.Count));
// Empty files are never extracted via a write call, so we have to fake that now
if (_indexes[index].Item2 == 0)
{
var result = _mapFn(path, new MemoryStreamFactory(new MemoryStream(), path)).Result;
_results.Add(path, result);
}
outStream = new GatheringExtractorStream<T>(this, index); outStream = new GatheringExtractorStream<T>(this, index);
return 0; return 0;
} }