Reworked *all the verbs*

This commit is contained in:
Halgari 2022-09-30 19:35:36 -06:00
parent 6a6f95d70f
commit 241682da76
29 changed files with 184 additions and 432 deletions

View File

@ -35,18 +35,18 @@ public partial class CommandLineBuilder
return await root.InvokeAsync(args); return await root.InvokeAsync(args);
} }
private static List<(Type, Func<Command>)> _commands { get; set; } = new(); private static List<(Type Type, VerbDefinition Definition, Func<IVerb, Delegate> Handler)> _commands { get; set; } = new();
public static IEnumerable<Type> Verbs => _commands.Select(c => c.Item1); public static IEnumerable<Type> Verbs => _commands.Select(c => c.Type);
public static void RegisterCommand<T>(Func<Command> makeCommand) public static void RegisterCommand<T>(VerbDefinition definition, Func<IVerb, Delegate> handler)
{ {
_commands.Add((typeof(T), makeCommand)); _commands.Add((typeof(T), definition, handler));
} }
} }
public record OptionDefinition(Type type, string ShortOption, string LongOption, string Description);
public record VerbDefinition() public record VerbDefinition(string Name, string Description, OptionDefinition[] Options)
{ {
} }
public static class CommandLineBuilderExtensions public static class CommandLineBuilderExtensions

View File

@ -5,30 +5,28 @@ using Wabbajack.CLI.Verbs;
public partial class CommandLineBuilder { public partial class CommandLineBuilder {
private static void RegisterAll() { private static void RegisterAll() {
RegisterCommand<Compile>(Compile.MakeCommand); RegisterCommand<Compile>(Compile.Definition, c => ((Compile)c).Run);
RegisterCommand<Decrypt>(Decrypt.MakeCommand); RegisterCommand<Decrypt>(Decrypt.Definition, c => ((Decrypt)c).Run);
RegisterCommand<DownloadAll>(DownloadAll.MakeCommand); RegisterCommand<DownloadAll>(DownloadAll.Definition, c => ((DownloadAll)c).Run);
RegisterCommand<DownloadCef>(DownloadCef.MakeCommand); RegisterCommand<DownloadUrl>(DownloadUrl.Definition, c => ((DownloadUrl)c).Run);
RegisterCommand<DownloadUrl>(DownloadUrl.MakeCommand); RegisterCommand<DumpZipInfo>(DumpZipInfo.Definition, c => ((DumpZipInfo)c).Run);
RegisterCommand<DumpZipInfo>(DumpZipInfo.MakeCommand); RegisterCommand<Encrypt>(Encrypt.Definition, c => ((Encrypt)c).Run);
RegisterCommand<Encrypt>(Encrypt.MakeCommand); RegisterCommand<Extract>(Extract.Definition, c => ((Extract)c).Run);
RegisterCommand<Extract>(Extract.MakeCommand); RegisterCommand<ForceHeal>(ForceHeal.Definition, c => ((ForceHeal)c).Run);
RegisterCommand<ForceHeal>(ForceHeal.MakeCommand); RegisterCommand<HashFile>(HashFile.Definition, c => ((HashFile)c).Run);
RegisterCommand<GenerateMetricsReports>(GenerateMetricsReports.MakeCommand); RegisterCommand<HashUrlString>(HashUrlString.Definition, c => ((HashUrlString)c).Run);
RegisterCommand<HashFile>(HashFile.MakeCommand); RegisterCommand<Install>(Install.Definition, c => ((Install)c).Run);
RegisterCommand<HashUrlString>(HashUrlString.MakeCommand); RegisterCommand<InstallCompileInstallVerify>(InstallCompileInstallVerify.Definition, c => ((InstallCompileInstallVerify)c).Run);
RegisterCommand<Install>(Install.MakeCommand); RegisterCommand<ListCreationClubContent>(ListCreationClubContent.Definition, c => ((ListCreationClubContent)c).Run);
RegisterCommand<InstallCompileInstallVerify>(InstallCompileInstallVerify.MakeCommand); RegisterCommand<ListGames>(ListGames.Definition, c => ((ListGames)c).Run);
RegisterCommand<ListCreationClubContent>(ListCreationClubContent.MakeCommand); RegisterCommand<ListModlists>(ListModlists.Definition, c => ((ListModlists)c).Run);
RegisterCommand<ListGames>(ListGames.MakeCommand); RegisterCommand<MirrorFile>(MirrorFile.Definition, c => ((MirrorFile)c).Run);
RegisterCommand<ListModlists>(ListModlists.MakeCommand); RegisterCommand<ModlistReport>(ModlistReport.Definition, c => ((ModlistReport)c).Run);
RegisterCommand<MirrorFile>(MirrorFile.MakeCommand); RegisterCommand<SteamDownloadFile>(SteamDownloadFile.Definition, c => ((SteamDownloadFile)c).Run);
RegisterCommand<ModlistReport>(ModlistReport.MakeCommand); RegisterCommand<SteamDumpAppInfo>(SteamDumpAppInfo.Definition, c => ((SteamDumpAppInfo)c).Run);
RegisterCommand<SteamDownloadFile>(SteamDownloadFile.MakeCommand); RegisterCommand<SteamLogin>(SteamLogin.Definition, c => ((SteamLogin)c).Run);
RegisterCommand<SteamDumpAppInfo>(SteamDumpAppInfo.MakeCommand); RegisterCommand<UploadToNexus>(UploadToNexus.Definition, c => ((UploadToNexus)c).Run);
RegisterCommand<SteamLogin>(SteamLogin.MakeCommand); RegisterCommand<ValidateLists>(ValidateLists.Definition, c => ((ValidateLists)c).Run);
RegisterCommand<UploadToNexus>(UploadToNexus.MakeCommand); RegisterCommand<VFSIndex>(VFSIndex.Definition, c => ((VFSIndex)c).Run);
RegisterCommand<ValidateLists>(ValidateLists.MakeCommand);
RegisterCommand<VFSIndex>(VFSIndex.MakeCommand);
} }
} }

View File

@ -17,7 +17,7 @@ foreach (var verb in Directory.EnumerateFiles("Verbs"))
var klass = verb.Split('\\').Last().Split('.').First(); var klass = verb.Split('\\').Last().Split('.').First();
if (klass == "IVerb") continue; if (klass == "IVerb") continue;
#> #>
RegisterCommand<<#=klass#>>(<#=klass#>.MakeCommand); RegisterCommand<<#=klass#>>(<#=klass#>.Definition, c => ((<#=klass#>)c).Run);
<# <#
} }

View File

@ -38,16 +38,12 @@ public class Compile : IVerb
_inferencer = inferencer; _inferencer = inferencer;
} }
public static Command MakeCommand() public static VerbDefinition Definition = new("compile", "Compiles a modlist",
new[]
{ {
var command = new Command("compile"); new OptionDefinition(typeof(AbsolutePath), "i", "installPath", "Install Path"),
command.Add(new Option<AbsolutePath>(new[] {"-i", "-installPath"}, "Install Path")); new OptionDefinition(typeof(AbsolutePath), "o", "outputPath", "OutputPath")
command.Add(new Option<AbsolutePath>(new[] {"-o", "-output"}, "Output")); });
command.Description = "Installs a modlist, compiles it, installs it again, verifies it";
command.Handler = CommandHandler.Create(Run);
return command;
}
public async Task<int> Run(AbsolutePath installPath, AbsolutePath outputPath, public async Task<int> Run(AbsolutePath installPath, AbsolutePath outputPath,
CancellationToken token) CancellationToken token)
{ {

View File

@ -19,15 +19,13 @@ public class Decrypt : IVerb
_logger = logger; _logger = logger;
} }
public Command MakeCommand() public static VerbDefinition Definition = new VerbDefinition("decrypt",
{ "Decrypts a file from the wabbajack encrypted storage",
var command = new Command("decrypt"); new[]
command.Add(new Option<AbsolutePath>(new[] {"-o", "-output"}, "Output file path")); {
command.Add(new Option<string>(new[] {"-n", "-name"}, "Name of the key to load data from")); new OptionDefinition(typeof(AbsolutePath), "o", "output", "Output file path"),
command.Description = "Decrypts a file from the Wabbajack encrypted storage"; new OptionDefinition(typeof(string), "n", "name", "Name of the key to load data from")
command.Handler = CommandHandler.Create(Run); });
return command;
}
public async Task<int> Run(AbsolutePath output, string name) public async Task<int> Run(AbsolutePath output, string name)
{ {

View File

@ -41,16 +41,14 @@ public class DownloadAll : IVerb
_cache = cache; _cache = cache;
} }
public Command MakeCommand() public static VerbDefinition Definition = new VerbDefinition("download-all",
{ "Downloads all files for all modlists in the gallery",
var command = new Command("download-all"); new[]
command.Add(new Option<AbsolutePath>(new[] {"-o", "-output"}, "Output folder")); {
command.Description = "Downloads all files for all modlists in the gallery"; new OptionDefinition(typeof(AbsolutePath), "o", "output", "Output folder")
command.Handler = CommandHandler.Create(Run); });
return command;
}
private async Task<int> Run(AbsolutePath output, CancellationToken token) internal async Task<int> Run(AbsolutePath output, CancellationToken token)
{ {
_logger.LogInformation("Downloading modlists"); _logger.LogInformation("Downloading modlists");

View File

@ -1,115 +0,0 @@
using System;
using System.CommandLine;
using System.CommandLine.Invocation;
using System.CommandLine.NamingConventionBinder;
using System.Diagnostics;
using System.IO;
using System.Net.Http;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using ICSharpCode.SharpZipLib.BZip2;
using ICSharpCode.SharpZipLib.Tar;
using Microsoft.Extensions.Logging;
using Wabbajack.CLI.DTOs;
using Wabbajack.Downloaders;
using Wabbajack.DTOs;
using Wabbajack.Paths;
using Wabbajack.Paths.IO;
using Version = System.Version;
namespace Wabbajack.CLI.Verbs;
public class DownloadCef : IVerb
{
private readonly DownloadDispatcher _dispatcher;
private readonly FileExtractor.FileExtractor _fileExtractor;
private readonly HttpClient _httpClient;
private readonly ILogger<DownloadCef> _logger;
public DownloadCef(ILogger<DownloadCef> logger, DownloadDispatcher dispatcher,
FileExtractor.FileExtractor fileExtractor, HttpClient httpClient)
{
_logger = logger;
_dispatcher = dispatcher;
_fileExtractor = fileExtractor;
_httpClient = httpClient;
}
public Command MakeCommand()
{
var command = new Command("download-cef");
command.Add(new Option<AbsolutePath>(new[] {"-f", "-folder"}, "Path to Wabbajack"));
command.Add(new Option<bool>(new[] {"--force"}, "Force the download even if the output already exists"));
command.Description = "Downloads CEF into this folder";
command.Handler = CommandHandler.Create(Run);
return command;
}
public async Task<int> Run(AbsolutePath folder, bool force = false)
{
if (folder == default) folder = KnownFolders.EntryPoint;
var cefNet = folder.Combine("CefNet.dll");
if (!cefNet.FileExists())
{
_logger.LogError("Cannot find CefNet.dll in {folder}", folder);
return 1;
}
var version = Version.Parse(FileVersionInfo.GetVersionInfo(cefNet.ToString()).FileVersion!);
var downloadVersion = $"{version.Major}.{version.Minor}";
var runtime = RuntimeInformation.RuntimeIdentifier;
if (folder.Combine("libcef.dll").FileExists() && !force)
{
_logger.LogInformation("Not downloading, cef already exists");
return 0;
}
_logger.LogInformation("Downloading Cef version {version} for {runtime}", downloadVersion, runtime);
var versions = await CefCDNResponse.Load(_httpClient);
var findSource = versions.FindSource(downloadVersion);
var fileUri = new Uri($"https://cef-builds.spotifycdn.com/{findSource.Name}");
var parsed = _dispatcher.Parse(fileUri);
var tempFile = folder.Combine(findSource.Name);
await _dispatcher.Download(new Archive {State = parsed!}, tempFile, CancellationToken.None);
{
_logger.LogInformation("Extracting {file}", tempFile);
await using var istream = tempFile.Open(FileMode.Open, FileAccess.Read, FileShare.Read);
await using var bzip2 = new BZip2InputStream(istream);
await using var tar = new TarInputStream(bzip2, Encoding.UTF8);
var prefix = tempFile.FileName.WithoutExtension().WithoutExtension().Combine("Release");
var fullPrefix = prefix.RelativeTo(folder);
while (true)
{
var entry = tar.GetNextEntry();
if (entry == null) break;
var path = entry.Name.ToRelativePath();
if (path.InFolder(prefix) && entry.Size > 0)
{
var outputPath = path.RelativeTo(folder).RelativeTo(fullPrefix).RelativeTo(folder);
outputPath.Parent.CreateDirectory();
_logger.LogInformation("Extracting {FileName} to {Folder}", outputPath.FileName,
outputPath.RelativeTo(folder));
await using var os = outputPath.Open(FileMode.Create, FileAccess.Write);
tar.CopyEntryContents(os);
}
}
}
tempFile.Delete();
return 0;
}
}

View File

@ -24,18 +24,15 @@ public class DownloadUrl : IVerb
_dispatcher = dispatcher; _dispatcher = dispatcher;
} }
public Command MakeCommand() public static VerbDefinition Definition = new VerbDefinition("download-url", "Downloads a file to a given output",
{ new[]
var command = new Command("download-url"); {
command.Add(new Option<Uri>(new[] {"-u", "-url"}, "Url to parse")); new OptionDefinition(typeof(Uri), "u", "url", "Url to parse"),
command.Add(new Option<AbsolutePath>(new[] {"-o", "-output"}, "Output file")); new OptionDefinition(typeof(AbsolutePath), "o", "output", "Output File"),
command.Add(new Option<bool>(new [] {"-p", "--proxy"}, "Use the Wabbajack Proxy (default: true)")); new OptionDefinition(typeof(bool), "p", "proxy", "Use the Wabbajack Proxy (default true)")
command.Description = "Downloads a file to a given output"; });
command.Handler = CommandHandler.Create(Run);
return command;
}
private async Task<int> Run(Uri url, AbsolutePath output, bool proxy = true) internal async Task<int> Run(Uri url, AbsolutePath output, bool proxy = true)
{ {
var parsed = _dispatcher.Parse(url); var parsed = _dispatcher.Parse(url);
if (parsed == null) if (parsed == null)

View File

@ -25,17 +25,15 @@ public class DumpZipInfo : IVerb
_logger = logger; _logger = logger;
} }
public Command MakeCommand() public static VerbDefinition Definition = new("dump-zip-info",
{ "Dumps the contents of a zip file to the console, for use in debugging wabbajack files",
var command = new Command("dump-zip-info"); new[]
command.Add(new Option<AbsolutePath>(new[] {"-i", "-input"}, "Zip file ot parse")); {
command.Add(new Option<bool>(new[] {"-t", "-test"}, "Test extracting each file")); new OptionDefinition(typeof(AbsolutePath), "i", "input", "Zip file to parse"),
command.Description = "Dumps the contents of a zip file to the console, for use in debugging wabbajack files"; new OptionDefinition(typeof(bool), "t", "test", "Test extracting each file")
command.Handler = CommandHandler.Create(Run); });
return command;
}
private async Task<int> Run(AbsolutePath input, bool test) internal async Task<int> Run(AbsolutePath input, bool test)
{ {
await using var ar = new ZipReader(input.Open(FileMode.Open), false); await using var ar = new ZipReader(input.Open(FileMode.Open), false);
foreach (var value in (await ar.GetFiles())) foreach (var value in (await ar.GetFiles()))

View File

@ -18,17 +18,15 @@ public class Encrypt : IVerb
_logger = logger; _logger = logger;
} }
public Command MakeCommand() public static VerbDefinition Definition = new("encrypt",
{ "Encrypts a file and stores it in the Wabbajack encrypted storage",
var command = new Command("encrypt"); new[]
command.Add(new Option<AbsolutePath>(new[] {"-i", "-input"}, "Path to the file to enrypt")); {
command.Add(new Option<string>(new[] {"-n", "-name"}, "Name of the key to store the data into")); new OptionDefinition(typeof(AbsolutePath), "i", "input", "Path to the file to encrypt"),
command.Description = "Encrypts a file and stores it in the Wabbajack encrypted storage"; new OptionDefinition(typeof(string), "n", "name", "Name of the key to store the data into")
command.Handler = CommandHandler.Create(Run); });
return command;
}
public async Task<int> Run(AbsolutePath input, string name) internal async Task<int> Run(AbsolutePath input, string name)
{ {
var data = await input.ReadAllBytesAsync(); var data = await input.ReadAllBytesAsync();
_logger.LogInformation("Encrypting {bytes} bytes into `{key}`", data.Length, name); _logger.LogInformation("Encrypting {bytes} bytes into `{key}`", data.Length, name);

View File

@ -25,17 +25,14 @@ public class Extract : IVerb
_extractor = extractor; _extractor = extractor;
} }
public Command MakeCommand() public static VerbDefinition Definition = new("extract",
{ "Extracts the contents of an archive into a folder", new[]
var command = new Command("extract"); {
command.Add(new Option<AbsolutePath>(new[] {"-i", "-input"}, "Input Archive")); new OptionDefinition(typeof(AbsolutePath), "i", "input", "Input Archive"),
command.Add(new Option<AbsolutePath>(new[] {"-o", "-output"}, "Output folder")); new OptionDefinition(typeof(AbsolutePath), "o", "output", "Output Folder")
command.Description = "Extracts the contents of an archive into a folder"; });
command.Handler = CommandHandler.Create(Run);
return command;
}
private async Task<int> Run(AbsolutePath input, AbsolutePath output, CancellationToken token) internal async Task<int> Run(AbsolutePath input, AbsolutePath output, CancellationToken token)
{ {
if (!output.DirectoryExists()) if (!output.DirectoryExists())
output.Parent.CreateDirectory(); output.Parent.CreateDirectory();

View File

@ -43,15 +43,13 @@ public class ForceHeal : IVerb
_httpClient = httpClient; _httpClient = httpClient;
} }
public Command MakeCommand() public static VerbDefinition Definition = new("force-heal",
{ "Creates a patch from New file to Old file and uploads it",
var command = new Command("force-heal"); new[]
command.Add(new Option<AbsolutePath>(new[] {"-n", "-new-file"}, "New File")); {
command.Add(new Option<string>(new[] {"-o", "-old-file"}, "Old File")); new OptionDefinition(typeof(AbsolutePath), "n", "new-file", "New file"),
command.Description = "Creates a patch from New file to Old File and uploads it"; new OptionDefinition(typeof(AbsolutePath), "o", "old-file", "Old File")
command.Handler = CommandHandler.Create(Run); });
return command;
}
public async Task<int> Run(AbsolutePath oldFile, AbsolutePath newFile) public async Task<int> Run(AbsolutePath oldFile, AbsolutePath newFile)
{ {

View File

@ -1,69 +0,0 @@
using System;
using System.Collections.Generic;
using System.CommandLine;
using System.CommandLine.Invocation;
using System.CommandLine.NamingConventionBinder;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using Wabbajack.Common;
using Wabbajack.DTOs.JsonConverters;
using Wabbajack.DTOs.ServerResponses;
using Wabbajack.Paths;
namespace Wabbajack.CLI.Verbs;
public class GenerateMetricsReports : IVerb
{
private readonly HttpClient _client;
private readonly DTOSerializer _dtos;
public GenerateMetricsReports(HttpClient client, DTOSerializer dtos)
{
_client = client;
_dtos = dtos;
}
public Command MakeCommand()
{
var command = new Command("generate-metrics-report");
command.Add(new Option<AbsolutePath>(new[] {"-o", "-output"}, "Output folder"));
command.Description = "Generates usage metrics and outputs a html report about them";
command.Handler = CommandHandler.Create(Run);
return command;
}
private async Task<int> Run(AbsolutePath output)
{
var subjects = await GetMetrics("one day ago", "now", "finish_install")
.Where(d => d.Action != d.Subject)
.Select(async d => d.GroupingSubject)
.ToHashSet();
var allTime = await GetMetrics("10 days ago", "now", "finish_install")
.Where(d => subjects.Contains(d.GroupingSubject))
.ToList();
var grouped = allTime.GroupBy(g => (g.Timestamp.ToString("yyyy-MM-dd"), g.GroupingSubject)).ToArray();
return 0;
}
private async IAsyncEnumerable<MetricResult> GetMetrics(string start, string end, string action)
{
await using var response = await _client.GetStreamAsync(new Uri($"https://build.wabbajack.org/metrics/report?action={action}&from={start}&end={end}"));
var sr = new StreamReader(response, leaveOpen: false);
while (true)
{
var line = await sr.ReadLineAsync();
if (line == null) break;
yield return _dtos.Deserialize<MetricResult>(line)!;
}
}
}

View File

@ -20,15 +20,11 @@ public class HashFile : IVerb
_logger = logger; _logger = logger;
} }
public Command MakeCommand() public static VerbDefinition Definition = new VerbDefinition("hash-file",
{ "Hashes a file with Wabbajack's hashing routines", new[]
var command = new Command("hash-file"); {
command.Add(new Option<AbsolutePath>(new[] {"-i", "-input"}, "Path to the file to hash")); new OptionDefinition(typeof(AbsolutePath), "i", "input", "Path to the file to hash")
command.Description = "Hashes a file with Wabbajack's xxHash64 implementation"; });
command.Handler = CommandHandler.Create(Run);
return command;
}
public async Task<int> Run(AbsolutePath input) public async Task<int> Run(AbsolutePath input)
{ {

View File

@ -17,15 +17,11 @@ public class HashUrlString : IVerb
_logger = logger; _logger = logger;
} }
public Command MakeCommand() public static VerbDefinition Definition = new VerbDefinition("hash-url-string",
{ "Hashes a URL string and returns the hashcode as hex", new[]
var command = new Command("hash-url-string"); {
command.Add(new Option<AbsolutePath>(new[] {"-u", "-url"}, "Url string to hash")); new OptionDefinition(typeof(AbsolutePath), "u", "url", "Url string to hash")
command.Description = "Hashes a URL string and returns the hashcode as hex"; });
command.Handler = CommandHandler.Create(Run);
return command;
}
public async Task<int> Run(string u) public async Task<int> Run(string u)
{ {

View File

@ -4,5 +4,4 @@ namespace Wabbajack.CLI.Verbs;
public interface IVerb public interface IVerb
{ {
public Command MakeCommand();
} }

View File

@ -39,18 +39,16 @@ public class Install : IVerb
_cache = cache; _cache = cache;
_gameLocator = gameLocator; _gameLocator = gameLocator;
} }
public Command MakeCommand()
public static VerbDefinition Definition = new VerbDefinition("install", "Installs a wabbajack file", new[]
{ {
var command = new Command("install"); new OptionDefinition(typeof(AbsolutePath), "w", "wabbajack", "Wabbajack file"),
command.Add(new Option<AbsolutePath>(new[] {"-w", "-wabbajack"}, "Wabbajack file")); new OptionDefinition(typeof(string), "m", "machineUrl", "Machine url to download"),
command.Add(new Option<AbsolutePath>(new[] {"-m", "-machineUrl"}, "Machine url to download")); new OptionDefinition(typeof(AbsolutePath), "o", "output", "Output path"),
command.Add(new Option<AbsolutePath>(new[] {"-o", "-output"}, "Output path")); new OptionDefinition(typeof(AbsolutePath), "d", "downloads", "Downloads path")
command.Add(new Option<AbsolutePath>(new[] {"-d", "-downloads"}, "Downloads path")); });
command.Description = "Installs a wabbajack file";
command.Handler = CommandHandler.Create(Run); internal async Task<int> Run(AbsolutePath wabbajack, AbsolutePath output, AbsolutePath downloads, string machineUrl, CancellationToken token)
return command;
}
public async Task<int> Run(AbsolutePath wabbajack, AbsolutePath output, AbsolutePath downloads, string machineUrl, CancellationToken token)
{ {
if (!string.IsNullOrEmpty(machineUrl)) if (!string.IsNullOrEmpty(machineUrl))
{ {

View File

@ -47,16 +47,13 @@ public class InstallCompileInstallVerify : IVerb
_inferencer = inferencer; _inferencer = inferencer;
} }
public Command MakeCommand() public static VerbDefinition Definition = new VerbDefinition("install-compile-install-verify",
{ "Installs a modlist, compiles it, installs it again, verifies it", new[]
var command = new Command("install-compile-install-verify"); {
command.Add(new Option<AbsolutePath>(new[] {"-m", "-machineUrls"}, "Machine url(s) to download")); new OptionDefinition(typeof(AbsolutePath), "m", "machineUrl", "Machine url(s) to download"),
command.Add(new Option<AbsolutePath>(new[] {"-d", "-downloads"}, "Downloads path")); new OptionDefinition(typeof(AbsolutePath), "d", "downloads", "Downloads path"),
command.Add(new Option<AbsolutePath>(new[] {"-o", "-outputs"}, "Outputs path")); new OptionDefinition(typeof(AbsolutePath), "o", "outputs", "Output paths")
command.Description = "Installs a modlist, compiles it, installs it again, verifies it"; });
command.Handler = CommandHandler.Create(Run);
return command;
}
public async Task<int> Run(AbsolutePath outputs, AbsolutePath downloads, IEnumerable<string> machineUrls, CancellationToken token) public async Task<int> Run(AbsolutePath outputs, AbsolutePath downloads, IEnumerable<string> machineUrls, CancellationToken token)
{ {

View File

@ -29,13 +29,9 @@ public class ListCreationClubContent : IVerb
_client = wjClient; _client = wjClient;
_downloader = downloader; _downloader = downloader;
} }
public Command MakeCommand()
{ public static VerbDefinition Definition =
var command = new Command("list-creation-club-content"); new("list-creation-club-content", "Lists all known creation club content", Array.Empty<OptionDefinition>());
command.Description = "Lists all known creation club content";
command.Handler = CommandHandler.Create(Run);
return command;
}
public async Task<int> Run(CancellationToken token) public async Task<int> Run(CancellationToken token)
{ {

View File

@ -1,3 +1,4 @@
using System;
using System.CommandLine; using System.CommandLine;
using System.CommandLine.Invocation; using System.CommandLine.Invocation;
using System.CommandLine.NamingConventionBinder; using System.CommandLine.NamingConventionBinder;
@ -22,15 +23,11 @@ public class ListGames : IVerb
_logger = logger; _logger = logger;
_locator = locator; _locator = locator;
} }
public Command MakeCommand()
{
var command = new Command("list-games");
command.Description = "Lists all games Wabbajack recognizes, and their installed versions/locations (if any)";
command.Handler = CommandHandler.Create(Run);
return command;
}
public async Task<int> Run(CancellationToken token) public static VerbDefinition Definition = new VerbDefinition("list-games",
"Lists all games Wabbajack recognizes, and their installed versions/locations (if any)", Array.Empty<OptionDefinition>());
internal async Task<int> Run(CancellationToken token)
{ {
foreach (var game in GameRegistry.Games.OrderBy(g => g.Value.HumanFriendlyGameName)) foreach (var game in GameRegistry.Games.OrderBy(g => g.Value.HumanFriendlyGameName))
{ {

View File

@ -24,13 +24,9 @@ public class ListModlists : IVerb
_logger = logger; _logger = logger;
_client = wjClient; _client = wjClient;
} }
public Command MakeCommand()
{ public static VerbDefinition Definition =
var command = new Command("list-modlists"); new("list-modlists", "Lists all known modlists", Array.Empty<OptionDefinition>());
command.Description = "Lists all known modlists";
command.Handler = CommandHandler.Create(Run);
return command;
}
public async Task<int> Run(CancellationToken token) public async Task<int> Run(CancellationToken token)
{ {

View File

@ -18,15 +18,12 @@ public class MirrorFile : IVerb
_logger = logger; _logger = logger;
_client = wjClient; _client = wjClient;
} }
public Command MakeCommand()
{
var command = new Command("mirror-file");
command.Add(new Option<AbsolutePath>(new[] {"-i", "-input"}, "File to Mirror"));
command.Description = "Mirrors a file to the Wabbajack CDN";
command.Handler = CommandHandler.Create(Run);
return command;
}
public static VerbDefinition Definition = new("mirror-file", "Mirrors a file to the Wabbajack CDN",
new[]
{
new OptionDefinition(typeof(AbsolutePath), "i", "input", "File to Mirror")
});
public async Task<int> Run(AbsolutePath input) public async Task<int> Run(AbsolutePath input)
{ {
_logger.LogInformation("Generating File Definition for {Name}", input.FileName); _logger.LogInformation("Generating File Definition for {Name}", input.FileName);

View File

@ -28,14 +28,12 @@ public class ModlistReport : IVerb
_logger = logger; _logger = logger;
_dtos = dtos; _dtos = dtos;
} }
public Command MakeCommand()
{ public static VerbDefinition Definition = new("modlist-report",
var command = new Command("modlist-report"); "Generates a usage report for a Modlist file", new[]
command.Add(new Option<AbsolutePath>(new[] {"-i", "-input"}, "Wabbajack file from which to generate a report")); {
command.Description = "Generates a usage report for a Modlist file"; new OptionDefinition(typeof(AbsolutePath), "i", "input", "Wabbajack file from which to generate a report")
command.Handler = CommandHandler.Create(Run); });
return command;
}
private static async Task<string> ReportTemplate(object o) private static async Task<string> ReportTemplate(object o)
{ {

View File

@ -34,21 +34,18 @@ public class SteamDownloadFile : IVerb
_dtos = dtos; _dtos = dtos;
_wjClient = wjClient; _wjClient = wjClient;
} }
public Command MakeCommand()
{
var command = new Command("steam-download-file");
command.Description = "Dumps information to the console about the given app";
command.Add(new Option<string>(new[] {"-g", "-game", "-gameName"}, "Wabbajack game name")); public static VerbDefinition Definition = new VerbDefinition("steam-download-file",
"Dumps information to the console about the given app",
new[]
{
new OptionDefinition(typeof(string), "g", "game", "Wabbajack game name"),
new OptionDefinition(typeof(string), "v", "version", "Version of the game to download for"),
new OptionDefinition(typeof(string), "f", "file", "File to download (relative path)"),
new OptionDefinition(typeof(string), "o", "output", "Output location")
});
command.Add(new Option<string>(new[] {"-v", "-version"}, "Version of the game to download for")); internal async Task<int> Run(string gameName, string version, string file, AbsolutePath output)
command.Add(new Option<string>(new[] {"-f", "-file"}, "File to download (relative path)"));
command.Add(new Option<string>(new[] {"-o", "-output"}, "Output location"));
command.Handler = CommandHandler.Create(Run);
return command;
}
private async Task<int> Run(string gameName, string version, string file, AbsolutePath output)
{ {
if (!GameRegistry.TryGetByFuzzyName(gameName, out var game)) if (!GameRegistry.TryGetByFuzzyName(gameName, out var game))
_logger.LogError("Can't find definition for {Game}", gameName); _logger.LogError("Can't find definition for {Game}", gameName);

View File

@ -15,15 +15,15 @@ using JsonSerializer = System.Text.Json.JsonSerializer;
namespace Wabbajack.CLI.Verbs; namespace Wabbajack.CLI.Verbs;
public class SteamAppDumpInfo : IVerb public class SteamDumpAppInfo : IVerb
{ {
private readonly ILogger<SteamAppDumpInfo> _logger; private readonly ILogger<SteamDumpAppInfo> _logger;
private readonly Client _client; private readonly Client _client;
private readonly ITokenProvider<SteamLoginState> _token; private readonly ITokenProvider<SteamLoginState> _token;
private readonly DepotDownloader _downloader; private readonly DepotDownloader _downloader;
private readonly DTOSerializer _dtos; private readonly DTOSerializer _dtos;
public SteamAppDumpInfo(ILogger<SteamAppDumpInfo> logger, Client steamClient, ITokenProvider<SteamLoginState> token, public SteamDumpAppInfo(ILogger<SteamDumpAppInfo> logger, Client steamClient, ITokenProvider<SteamLoginState> token,
DepotDownloader downloader, DTOSerializer dtos) DepotDownloader downloader, DTOSerializer dtos)
{ {
_logger = logger; _logger = logger;
@ -32,6 +32,13 @@ public class SteamAppDumpInfo : IVerb
_downloader = downloader; _downloader = downloader;
_dtos = dtos; _dtos = dtos;
} }
public static VerbDefinition Definition = new VerbDefinition("steam-app-dump-info",
"Dumps information to the console about the given app", new[]
{
new OptionDefinition(typeof(string), "g", "game", "Wabbajack game name")
});
public Command MakeCommand() public Command MakeCommand()
{ {
var command = new Command("steam-app-dump-info"); var command = new Command("steam-app-dump-info");

View File

@ -22,15 +22,12 @@ public class SteamLogin : IVerb
_client = steamClient; _client = steamClient;
_token = token; _token = token;
} }
public Command MakeCommand()
{
var command = new Command("steam-login");
command.Description = "Logs into Steam via interactive prompts";
command.Add(new Option<string>(new[] {"-u", "-user"}, "Username for login")); public static VerbDefinition Definition = new("steam-login",
command.Handler = CommandHandler.Create(Run); "Logs into Steam via interactive prompts", new[]
return command; {
} new OptionDefinition(typeof(string), "u", "user", "Username for login")
});
public async Task<int> Run(string user) public async Task<int> Run(string user)
{ {

View File

@ -26,14 +26,13 @@ public class UploadToNexus : IVerb
_client = wjClient; _client = wjClient;
_dtos = dtos; _dtos = dtos;
} }
public Command MakeCommand()
{ public static VerbDefinition Definition = new("upload-to-nexus",
var command = new Command("upload-to-nexus"); "Uploads a file to the Nexus defined by the given .json definition file", new[]
command.Add(new Option<AbsolutePath>(new[] {"-d", "-definition"}, "Definition JSON file")); {
command.Description = "Uploads a file to the Nexus defined by the given .json definition file"; new OptionDefinition(typeof(AbsolutePath), "d", "definition", "Definition JSON file")
command.Handler = CommandHandler.Create(Run); });
return command;
}
public async Task<int> Run(AbsolutePath definition) public async Task<int> Run(AbsolutePath definition)
{ {

View File

@ -8,24 +8,20 @@ using Wabbajack.VFS;
namespace Wabbajack.CLI.Verbs; namespace Wabbajack.CLI.Verbs;
public class VFSIndexFolder : IVerb public class VFSIndex : IVerb
{ {
private readonly Context _context; private readonly Context _context;
public VFSIndexFolder(Context context) public VFSIndex(Context context)
{ {
_context = context; _context = context;
} }
public Command MakeCommand() public static VerbDefinition Definition = new VerbDefinition("vfs-index",
{ "Index and cache the contents of a folder", new[]
var command = new Command("vfs-index"); {
command.Add(new Option<AbsolutePath>(new[] {"-f", "--folder"}, "Folder to index")); new OptionDefinition(typeof(AbsolutePath), "f", "folder", "Folder to index")
command.Description = "Index and cache the contents of a folder"; });
command.Handler = CommandHandler.Create(Run);
return command;
}
public async Task<int> Run(AbsolutePath folder) public async Task<int> Run(AbsolutePath folder)
{ {

View File

@ -74,19 +74,11 @@ public class ValidateLists : IVerb
_httpLimiter = httpLimiter; _httpLimiter = httpLimiter;
} }
public Command MakeCommand() public static VerbDefinition Definition = new VerbDefinition("validate-lists",
{ "Gets a list of modlists, validates them and exports a result list", new[]
var command = new Command("validate-lists"); {
command.Add(new Option<AbsolutePath>(new[] {"-r", "--reports"}, "Location to store validation report outputs")); new OptionDefinition(typeof(AbsolutePath), "r", "reports", "Location to store validation report outputs")
});
command.Add(new Option<AbsolutePath>(new[] {"--other-archives"},
"Look for files here before downloading (stored by hex hash name)")
{IsRequired = false});
command.Description = "Gets a list of modlists, validates them and exports a result list";
command.Handler = CommandHandler.Create(Run);
return command;
}
public async Task<int> Run(AbsolutePath reports, AbsolutePath otherArchives) public async Task<int> Run(AbsolutePath reports, AbsolutePath otherArchives)
{ {