2019-08-31 05:07:31 +00:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using Wabbajack.Common;
|
2019-09-26 20:18:41 +00:00
|
|
|
|
using Wabbajack.NexusApi;
|
2019-10-01 22:39:25 +00:00
|
|
|
|
using File = Alphaleonis.Win32.Filesystem.File;
|
|
|
|
|
using Path = Alphaleonis.Win32.Filesystem.Path;
|
2019-08-31 05:07:31 +00:00
|
|
|
|
|
|
|
|
|
namespace Wabbajack
|
|
|
|
|
{
|
|
|
|
|
public class ReportBuilder : IDisposable
|
|
|
|
|
{
|
2019-09-14 04:35:42 +00:00
|
|
|
|
private const int WRAP_SIZE = 80;
|
|
|
|
|
private readonly StreamWriter wtr;
|
2019-10-01 22:39:25 +00:00
|
|
|
|
private string _output_folder;
|
2019-09-14 04:35:42 +00:00
|
|
|
|
|
2019-10-01 22:39:25 +00:00
|
|
|
|
public ReportBuilder(Stream str, string output_folder)
|
2019-08-31 05:07:31 +00:00
|
|
|
|
{
|
2019-10-01 22:39:25 +00:00
|
|
|
|
_output_folder = output_folder;
|
2019-08-31 05:07:31 +00:00
|
|
|
|
wtr = new StreamWriter(str);
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-14 04:35:42 +00:00
|
|
|
|
public void Dispose()
|
|
|
|
|
{
|
|
|
|
|
wtr.Flush();
|
|
|
|
|
wtr?.Dispose();
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-31 05:07:31 +00:00
|
|
|
|
public void Text(string txt)
|
|
|
|
|
{
|
2019-09-14 04:35:42 +00:00
|
|
|
|
var offset = 0;
|
2019-08-31 05:07:31 +00:00
|
|
|
|
while (offset + WRAP_SIZE < txt.Length)
|
|
|
|
|
{
|
|
|
|
|
wtr.WriteLine(txt.Substring(offset, WRAP_SIZE));
|
|
|
|
|
offset += WRAP_SIZE;
|
|
|
|
|
}
|
2019-09-14 04:35:42 +00:00
|
|
|
|
|
|
|
|
|
if (offset < txt.Length) wtr.WriteLine(txt.Substring(offset, txt.Length - offset));
|
2019-08-31 05:07:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void NoWrapText(string txt)
|
|
|
|
|
{
|
|
|
|
|
wtr.WriteLine(txt);
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-01 23:06:15 +00:00
|
|
|
|
public void Build(Compiler c, ModList lst)
|
2019-08-31 05:07:31 +00:00
|
|
|
|
{
|
2019-10-07 14:44:28 +00:00
|
|
|
|
Text($"### {lst.Name} by {lst.Author} - Installation Summary");
|
|
|
|
|
Text(lst.Description);
|
|
|
|
|
Text($"#### Website:");
|
|
|
|
|
NoWrapText($"[{lst.Website}]({lst.Website})");
|
2019-10-01 23:06:15 +00:00
|
|
|
|
|
|
|
|
|
var readme_file = Path.Combine(c.MO2ProfileDir, "readme.md");
|
|
|
|
|
if (File.Exists(readme_file))
|
|
|
|
|
File.ReadAllLines(readme_file)
|
|
|
|
|
.Do(NoWrapText);
|
|
|
|
|
|
2019-09-14 04:35:42 +00:00
|
|
|
|
Text(
|
|
|
|
|
$"#### Download Summary ({lst.Archives.Count} archives - {lst.Archives.Sum(a => a.Size).ToFileSizeString()})");
|
2019-08-31 05:07:31 +00:00
|
|
|
|
foreach (var archive in SortArchives(lst.Archives))
|
|
|
|
|
{
|
2019-09-05 22:18:54 +00:00
|
|
|
|
var hash = archive.Hash.FromBase64().ToHEX();
|
2019-08-31 05:07:31 +00:00
|
|
|
|
switch (archive)
|
|
|
|
|
{
|
|
|
|
|
case NexusMod m:
|
2019-09-14 04:35:42 +00:00
|
|
|
|
var profile = m.UploaderProfile.Replace("/games/",
|
2019-09-26 20:18:41 +00:00
|
|
|
|
"/" + NexusApiUtils.ConvertGameName(m.GameName).ToLower() + "/");
|
2019-09-14 04:35:42 +00:00
|
|
|
|
NoWrapText(
|
2019-09-26 20:18:41 +00:00
|
|
|
|
$"* [{m.Name}](http://nexusmods.com/{NexusApiUtils.ConvertGameName(m.GameName)}/mods/{m.ModID})");
|
2019-09-05 22:18:54 +00:00
|
|
|
|
NoWrapText($" * Author : [{m.UploadedBy}]({profile})");
|
|
|
|
|
NoWrapText($" * Version : {m.Version}");
|
2019-08-31 05:07:31 +00:00
|
|
|
|
break;
|
|
|
|
|
case MODDBArchive m:
|
|
|
|
|
NoWrapText($"* MODDB - [{m.Name}]({m.URL})");
|
|
|
|
|
break;
|
|
|
|
|
case MEGAArchive m:
|
|
|
|
|
NoWrapText($"* MEGA - [{m.Name}]({m.URL})");
|
|
|
|
|
break;
|
|
|
|
|
case GoogleDriveMod m:
|
2019-09-14 04:35:42 +00:00
|
|
|
|
NoWrapText(
|
|
|
|
|
$"* GoogleDrive - [{m.Name}](https://drive.google.com/uc?id={m.Id}&export=download)");
|
2019-08-31 05:07:31 +00:00
|
|
|
|
break;
|
|
|
|
|
case DirectURLArchive m:
|
|
|
|
|
NoWrapText($"* URL - [{m.Name} - {m.URL}]({m.URL})");
|
|
|
|
|
break;
|
|
|
|
|
}
|
2019-09-14 04:35:42 +00:00
|
|
|
|
|
2019-09-10 13:02:25 +00:00
|
|
|
|
NoWrapText($" * Size : {archive.Size.ToFileSizeString()}");
|
|
|
|
|
NoWrapText($" * SHA256 : [{hash}](https://www.virustotal.com/gui/file/{hash})");
|
2019-08-31 05:07:31 +00:00
|
|
|
|
}
|
2019-09-14 04:35:42 +00:00
|
|
|
|
|
|
|
|
|
Text("\n\n");
|
2019-08-31 05:07:31 +00:00
|
|
|
|
var patched = lst.Directives.OfType<PatchedFromArchive>().OrderBy(p => p.To).ToList();
|
|
|
|
|
Text($"#### Summary of ({patched.Count}) patches");
|
|
|
|
|
foreach (var directive in patched)
|
2019-09-14 04:35:42 +00:00
|
|
|
|
NoWrapText(
|
2019-10-01 22:39:25 +00:00
|
|
|
|
$"* Applying {SizeForID(directive.PatchID)} byte patch `{directive.FullPath}` to create `{directive.To}`");
|
2019-09-14 04:35:42 +00:00
|
|
|
|
|
2019-08-31 05:07:31 +00:00
|
|
|
|
|
|
|
|
|
var files = lst.Directives.OrderBy(d => d.To).ToList();
|
|
|
|
|
Text($"\n\n### Install Plan of ({files.Count}) files");
|
2019-09-14 04:35:42 +00:00
|
|
|
|
Text("(ignoring files that are directly copied from archives or listed in the patches section above)");
|
2019-09-02 22:36:57 +00:00
|
|
|
|
foreach (var directive in files.OrderBy(f => f.GetType().Name).ThenByDescending(f => f.To))
|
2019-08-31 05:07:31 +00:00
|
|
|
|
switch (directive)
|
|
|
|
|
{
|
2019-10-11 11:09:34 +00:00
|
|
|
|
case PropertyFile i:
|
|
|
|
|
NoWrapText($"* `{i.OriginalName}` as a `{Enum.GetName(typeof(PropertyType),i.Type)}`");
|
|
|
|
|
break;
|
2019-08-31 05:07:31 +00:00
|
|
|
|
case FromArchive f:
|
|
|
|
|
//NoWrapText($"* `{f.To}` from `{f.FullPath}`");
|
|
|
|
|
break;
|
|
|
|
|
case CleanedESM i:
|
|
|
|
|
NoWrapText($"* `{i.To}` by applying a patch to a game ESM ({i.SourceESMHash})");
|
|
|
|
|
break;
|
|
|
|
|
case RemappedInlineFile i:
|
2019-09-02 22:36:57 +00:00
|
|
|
|
NoWrapText($"* `{i.To}` by remapping the contents of an inline file");
|
2019-08-31 05:07:31 +00:00
|
|
|
|
break;
|
|
|
|
|
case InlineFile i:
|
2019-10-01 22:39:25 +00:00
|
|
|
|
NoWrapText($"* `{i.To}` from `{SizeForID(i.SourceDataID).ToFileSizeString()}` file included in modlist");
|
2019-08-31 05:07:31 +00:00
|
|
|
|
break;
|
|
|
|
|
case CreateBSA i:
|
2019-09-14 04:35:42 +00:00
|
|
|
|
NoWrapText(
|
|
|
|
|
$"* `{i.To}` by creating a BSA of files found in `{Consts.BSACreationDir}\\{i.TempID}`");
|
2019-08-31 05:07:31 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
2019-09-20 22:49:32 +00:00
|
|
|
|
|
|
|
|
|
var inlined = lst.Directives.OfType<InlineFile>()
|
2019-10-01 22:39:25 +00:00
|
|
|
|
.Select(f => (f.To, "inlined", SizeForID(f.SourceDataID)))
|
2019-09-20 22:49:32 +00:00
|
|
|
|
.Concat(lst.Directives
|
|
|
|
|
.OfType<PatchedFromArchive>()
|
2019-10-01 22:39:25 +00:00
|
|
|
|
.Select(f => (f.To, "patched", SizeForID(f.PatchID))))
|
2019-09-20 22:49:32 +00:00
|
|
|
|
.ToHashSet()
|
2019-10-01 22:39:25 +00:00
|
|
|
|
.OrderByDescending(f => f.Item3);
|
2019-09-20 22:49:32 +00:00
|
|
|
|
|
|
|
|
|
NoWrapText("\n\n### Summary of inlined files in this installer");
|
|
|
|
|
foreach (var inline in inlined)
|
|
|
|
|
{
|
2019-10-01 22:39:25 +00:00
|
|
|
|
NoWrapText($"* {inline.Item3.ToFileSizeString()} for {inline.Item2} file {inline.To}");
|
2019-09-20 22:49:32 +00:00
|
|
|
|
}
|
2019-08-31 05:07:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-10-01 22:39:25 +00:00
|
|
|
|
private long SizeForID(string id)
|
|
|
|
|
{
|
|
|
|
|
return File.GetSize(Path.Combine(_output_folder, id));
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-31 05:07:31 +00:00
|
|
|
|
private IEnumerable<Archive> SortArchives(List<Archive> lstArchives)
|
|
|
|
|
{
|
|
|
|
|
var lst = lstArchives.OfType<NexusMod>().OrderBy(m => m.Author).ThenBy(m => m.Name);
|
|
|
|
|
return lst.Concat(lstArchives.Where(m => !(m is NexusMod)).OrderBy(m => m.Name));
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-09-14 04:35:42 +00:00
|
|
|
|
}
|