diff --git a/Wabbajack.CLI/Program.cs b/Wabbajack.CLI/Program.cs index e3cf38da..f67961fa 100644 --- a/Wabbajack.CLI/Program.cs +++ b/Wabbajack.CLI/Program.cs @@ -7,6 +7,9 @@ using System.Text.Json; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using NLog.Extensions.Logging; +using NLog.Targets; using Octokit; using Wabbajack.CLI.TypeConverters; using Wabbajack.CLI.Verbs; @@ -34,6 +37,7 @@ internal class Program new TypeConverterAttribute(typeof(ModListCategoryConverter))); var host = Host.CreateDefaultBuilder(Array.Empty()) + .ConfigureLogging(SetupLogging) .ConfigureServices((host, services) => { services.AddSingleton(new JsonSerializerOptions()); @@ -68,13 +72,41 @@ internal class Program services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + + + }).Build(); var service = host.Services.GetService(); return await service!.Run(args); } + + private static void SetupLogging(ILoggingBuilder loggingBuilder) + { + var config = new NLog.Config.LoggingConfiguration(); + + var fileTarget = new FileTarget("file") + { + FileName = "logs/wabbajack-cli.current.log", + ArchiveFileName = "logs/wabbajack-cli.{##}.log", + ArchiveOldFileOnStartup = true, + MaxArchiveFiles = 10, + Layout = "${processtime} [${level:uppercase=true}] (${logger}) ${message:withexception=true}", + Header = "############ Wabbajack log file - ${longdate} ############" + }; + + var consoleTarget = new ConsoleTarget("console"); + + config.AddRuleForAllLevels(fileTarget); + config.AddRuleForAllLevels(consoleTarget); + + loggingBuilder.ClearProviders(); + loggingBuilder.SetMinimumLevel(LogLevel.Trace); + loggingBuilder.AddNLog(config); + } } \ No newline at end of file diff --git a/Wabbajack.CLI/Verbs/Install.cs b/Wabbajack.CLI/Verbs/Install.cs new file mode 100644 index 00000000..df373c82 --- /dev/null +++ b/Wabbajack.CLI/Verbs/Install.cs @@ -0,0 +1,111 @@ +using System; +using System.CommandLine; +using System.CommandLine.Invocation; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Wabbajack.Downloaders; +using Wabbajack.Downloaders.GameFile; +using Wabbajack.DTOs; +using Wabbajack.DTOs.JsonConverters; +using Wabbajack.Installer; +using Wabbajack.Networking.WabbajackClientApi; +using Wabbajack.Paths; + +namespace Wabbajack.CLI.Verbs; + +public class Install : IVerb +{ + private readonly ILogger _logger; + private readonly DownloadDispatcher _dispatcher; + private readonly Client _wjClient; + private readonly IServiceProvider _serviceProvider; + private readonly DTOSerializer _dtos; + private readonly GameLocator _gameLocator; + + public Install(ILogger logger, DownloadDispatcher dispatcher, Client wjClient, IServiceProvider serviceProvider, + DTOSerializer dtos, GameLocator gameLocator) + { + _logger = logger; + _dispatcher = dispatcher; + _wjClient = wjClient; + _serviceProvider = serviceProvider; + _dtos = dtos; + _gameLocator = gameLocator; + } + + public Command MakeCommand() + { + var command = new Command("install"); + command.Add(new Option(new[] {"-m", "-machineUrl"}, "MachineURL to download and install")); + command.Add(new Option(new[] {"-i", "-inputModlist"}, "Input modlist to install")); + command.Add(new Option(new[] {"-d", "-downloads"}, "Downloads Folder")); + command.Add(new Option(new[] {"-o", "-output"}, "Install output Folder")); + command.Description = "Installs a modlist"; + command.Handler = CommandHandler.Create(Run); + return command; + } + + private async Task Run(CancellationToken token, AbsolutePath inputModlist, string machineUrl, AbsolutePath downloads, AbsolutePath output) + { + if (string.IsNullOrWhiteSpace(machineUrl) && inputModlist == default) + { + _logger.LogError("Need either a inputModlist or a machineUrl"); + return 1; + } + + if (!string.IsNullOrWhiteSpace(machineUrl)) + { + + var list = (await _wjClient.LoadLists()) + .FirstOrDefault(l => l.Links.MachineURL == machineUrl); + + if (list == null) + { + _logger.LogError("Cannot find list with machineUrl"); + return 2; + } + + inputModlist = downloads.Combine($"{machineUrl}_modlist.wabbajack"); + var hash = await _dispatcher.Download(new Archive + { + Hash = list.DownloadMetadata!.Hash, + Size = list.DownloadMetadata.Size, + Name = list.Title, + State = _dispatcher.Parse(new Uri(list.Links.Download))! + }, inputModlist, token); + if (hash != list.DownloadMetadata.Hash) + _logger.LogError($"Downloaded hash ({hash}) did not match expected hash ({list.DownloadMetadata.Hash})."); + } + + _logger.LogInformation("Loading Modlist"); + var modlist = await StandardInstaller.LoadFromFile(_dtos, inputModlist); + + var installer = StandardInstaller.Create(_serviceProvider, new InstallerConfiguration + { + Game = modlist.GameType, + Downloads = downloads, + Install = output, + ModList = modlist, + ModlistArchive = inputModlist, + SystemParameters = new SystemParameters() + { + ScreenWidth = 1920, + ScreenHeight = 1080, + SystemMemorySize = 16_000_000, + SystemPageSize = 16_000_000, + VideoMemorySize = 8_000_000 + }, + GameFolder = _gameLocator.GameLocation(modlist.GameType) + }); + var result = await installer.Begin(token); + if (result) + _logger.LogInformation("Modlist installed, enjoy!"); + else + _logger.LogInformation("Modlist install error!"); + + return 0; + } +} \ No newline at end of file diff --git a/Wabbajack.CLI/Wabbajack.CLI.csproj b/Wabbajack.CLI/Wabbajack.CLI.csproj index 19bc0a15..86f8f4e0 100644 --- a/Wabbajack.CLI/Wabbajack.CLI.csproj +++ b/Wabbajack.CLI/Wabbajack.CLI.csproj @@ -18,6 +18,7 @@ + diff --git a/Wabbajack.Downloaders.Dispatcher.Test/DownloaderTests.cs b/Wabbajack.Downloaders.Dispatcher.Test/DownloaderTests.cs index 7964ebe7..d012a9d6 100644 --- a/Wabbajack.Downloaders.Dispatcher.Test/DownloaderTests.cs +++ b/Wabbajack.Downloaders.Dispatcher.Test/DownloaderTests.cs @@ -192,7 +192,7 @@ public class DownloaderTests Game = Game.SkyrimSpecialEdition, IsCCMod = true, ProductId = 4, - BranchID = 90898, + BranchId = 90898, ContentId = "4059054" } }, @@ -204,7 +204,7 @@ public class DownloaderTests Game = Game.SkyrimSpecialEdition, IsCCMod = true, ProductId = 6, - BranchID = 9898, + BranchId = 9898, ContentId = "059054" } },