diff --git a/EftPatchHelper/EftPatchHelper/EftPatchHelper.csproj b/EftPatchHelper/EftPatchHelper/EftPatchHelper.csproj index f150611..446ef4f 100644 --- a/EftPatchHelper/EftPatchHelper/EftPatchHelper.csproj +++ b/EftPatchHelper/EftPatchHelper/EftPatchHelper.csproj @@ -8,12 +8,21 @@ + + + + + + Resources\Gitea.dll + + + Always diff --git a/EftPatchHelper/EftPatchHelper/Extensions/ObjectExtensions.cs b/EftPatchHelper/EftPatchHelper/Extensions/ObjectExtensions.cs new file mode 100644 index 0000000..bc7e81d --- /dev/null +++ b/EftPatchHelper/EftPatchHelper/Extensions/ObjectExtensions.cs @@ -0,0 +1,18 @@ +using Spectre.Console; + +namespace EftPatchHelper.Extensions +{ + public static class ObjectExtensions + { + public static T ValidateOrExit(this object? toValidate) + { + if (toValidate == null || toValidate is not T) + { + AnsiConsole.Prompt(new TextPrompt("Press [blue]enter[/] to close ...").AllowEmpty()); + Environment.Exit(0); + } + + return (T)toValidate; + } + } +} diff --git a/EftPatchHelper/EftPatchHelper/Interfaces/IFileProcessingTasks.cs b/EftPatchHelper/EftPatchHelper/Interfaces/IFileProcessingTasks.cs new file mode 100644 index 0000000..abc6228 --- /dev/null +++ b/EftPatchHelper/EftPatchHelper/Interfaces/IFileProcessingTasks.cs @@ -0,0 +1,6 @@ +namespace EftPatchHelper.Interfaces +{ + public interface IFileProcessingTasks : ITaskable + { + } +} diff --git a/EftPatchHelper/EftPatchHelper/Interfaces/IPatchGenTasks.cs b/EftPatchHelper/EftPatchHelper/Interfaces/IPatchGenTasks.cs new file mode 100644 index 0000000..1c21666 --- /dev/null +++ b/EftPatchHelper/EftPatchHelper/Interfaces/IPatchGenTasks.cs @@ -0,0 +1,6 @@ +namespace EftPatchHelper.Interfaces +{ + public interface IPatchGenTasks : ITaskable + { + } +} diff --git a/EftPatchHelper/EftPatchHelper/Interfaces/IPatchTestingTasks.cs b/EftPatchHelper/EftPatchHelper/Interfaces/IPatchTestingTasks.cs new file mode 100644 index 0000000..6c962ed --- /dev/null +++ b/EftPatchHelper/EftPatchHelper/Interfaces/IPatchTestingTasks.cs @@ -0,0 +1,6 @@ +namespace EftPatchHelper.Interfaces +{ + public interface IPatchTestingTasks : ITaskable + { + } +} diff --git a/EftPatchHelper/EftPatchHelper/Interfaces/IReleaseCreator.cs b/EftPatchHelper/EftPatchHelper/Interfaces/IReleaseCreator.cs new file mode 100644 index 0000000..e412c5f --- /dev/null +++ b/EftPatchHelper/EftPatchHelper/Interfaces/IReleaseCreator.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EftPatchHelper.Interfaces +{ + public interface IReleaseCreator : ITaskable + { + } +} diff --git a/EftPatchHelper/EftPatchHelper/Model/Options.cs b/EftPatchHelper/EftPatchHelper/Model/Options.cs index b257e56..ebdb44f 100644 --- a/EftPatchHelper/EftPatchHelper/Model/Options.cs +++ b/EftPatchHelper/EftPatchHelper/Model/Options.cs @@ -4,9 +4,29 @@ namespace EftPatchHelper.Model { public class Options { + /// + /// Whether or not the user opted to ignore existing directories. + /// public bool IgnoreExistingDirectories = false; + + /// + /// The target client used to generate patches + /// public EftClient TargetClient = null; + + /// + /// The source client used to generate patches + /// public EftClient SourceClient = null; + + /// + /// The path to the patch folder containing the patches that were generated + /// public string OutputPatchPath = null; + + /// + /// Whether or not the user opted to create a release on gitea + /// + public bool CreateRelease = false; } } diff --git a/EftPatchHelper/EftPatchHelper/Model/Settings.cs b/EftPatchHelper/EftPatchHelper/Model/Settings.cs index 4adb1cd..cd1400e 100644 --- a/EftPatchHelper/EftPatchHelper/Model/Settings.cs +++ b/EftPatchHelper/EftPatchHelper/Model/Settings.cs @@ -30,6 +30,18 @@ namespace EftPatchHelper.Model [JsonPropertyName("patcherExePath")] public string PatcherEXEPath { get; set; } = ""; + [JsonPropertyName("giteaApiBasePath")] + public string GiteaApiBasePath { get; set; } = ""; + + [JsonPropertyName("giteaApiKey")] + public string GiteaApiKey { get; set; } = ""; + + [JsonPropertyName("giteaReleaseRepoOwner")] + public string GiteaReleaseRepoOwner { get; set; } = ""; + + [JsonPropertyName("giteaReleaseRepoName")] + public string GiteaReleaseRepoName { get; set; } = ""; + public bool Save() { try @@ -53,6 +65,19 @@ namespace EftPatchHelper.Model } } + public bool UsingGitea() + { + if (string.IsNullOrWhiteSpace(GiteaApiBasePath)) return false; + + if (string.IsNullOrWhiteSpace(GiteaReleaseRepoOwner)) return false; + + if (string.IsNullOrWhiteSpace(GiteaReleaseRepoName)) return false; + + if (string.IsNullOrWhiteSpace(GiteaApiKey)) return false; + + return true; + } + public bool Validate() { if (string.IsNullOrWhiteSpace(TargetEftVersion)) return false; diff --git a/EftPatchHelper/EftPatchHelper/Program.cs b/EftPatchHelper/EftPatchHelper/Program.cs index 5a14347..546fe12 100644 --- a/EftPatchHelper/EftPatchHelper/Program.cs +++ b/EftPatchHelper/EftPatchHelper/Program.cs @@ -17,6 +17,7 @@ namespace EftPatchHelper ITaskable _fileProcessingTasks; ITaskable _patchGenTasks; ITaskable _patchTestingTasks; + ITaskable _createReleaseTasks; public static void Main(string[] args) { @@ -34,7 +35,8 @@ namespace EftPatchHelper IClientSelectionTask clientSelectionTasks, IFileProcessingTasks fileProcessingTasks, IPatchGenTasks patchGenTasks, - IPatchTestingTasks patchTestingTasks + IPatchTestingTasks patchTestingTasks, + IReleaseCreator createReleaseTasks ) { _settingsTasks = settingsTasks; @@ -42,6 +44,7 @@ namespace EftPatchHelper _fileProcessingTasks = fileProcessingTasks; _patchGenTasks = patchGenTasks; _patchTestingTasks = patchTestingTasks; + _createReleaseTasks = createReleaseTasks; } public void Run() @@ -51,6 +54,7 @@ namespace EftPatchHelper _fileProcessingTasks.Run(); _patchGenTasks.Run(); _patchTestingTasks.Run(); + _createReleaseTasks.Run(); } private static IHost ConfigureHost(string[] args) @@ -73,6 +77,7 @@ namespace EftPatchHelper services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); services.AddTransient(); }) .ConfigureAppConfiguration((_, config) => diff --git a/EftPatchHelper/EftPatchHelper/Resources/Gitea.dll b/EftPatchHelper/EftPatchHelper/Resources/Gitea.dll new file mode 100644 index 0000000..6d31cfb Binary files /dev/null and b/EftPatchHelper/EftPatchHelper/Resources/Gitea.dll differ diff --git a/EftPatchHelper/EftPatchHelper/Tasks/CreateReleaseTasks.cs b/EftPatchHelper/EftPatchHelper/Tasks/CreateReleaseTasks.cs new file mode 100644 index 0000000..67e0b65 --- /dev/null +++ b/EftPatchHelper/EftPatchHelper/Tasks/CreateReleaseTasks.cs @@ -0,0 +1,103 @@ +using EftPatchHelper.Interfaces; +using EftPatchHelper.Model; +using Gitea.Api; +using Gitea.Model; +using Gitea.Client; +using Spectre.Console; +using EftPatchHelper.Extensions; + +namespace EftPatchHelper.Tasks +{ + public class CreateReleaseTasks : IReleaseCreator + { + private Settings _settings; + private Options _options; + + public CreateReleaseTasks(Settings settings, Options options) + { + _settings = settings; + _options = options; + } + + private bool UploadAsset(FileInfo file, Release release, RepositoryApi repo) + { + return AnsiConsole.Status().Start("Uploading Asset", (StatusContext context) => + { + AnsiConsole.MarkupLine($"[blue]Adding release asset: {file.Name.EscapeMarkup()}[/]"); + + file.Refresh(); + + if (!file.Exists) + { + AnsiConsole.MarkupLine($"[red]File does not exist: {file.FullName}[/]"); + } + + using var fileStream = file.OpenRead(); + + try + { + var attachment = repo.RepoCreateReleaseAttachment(_settings.GiteaReleaseRepoOwner, _settings.GiteaReleaseRepoName, release.Id, fileStream, file.Name); + + AnsiConsole.MarkupLine("[green]Upload Complete[/]"); + + return true; + } + catch (Exception ex) + { + AnsiConsole.MarkupLine("[red]Failed to upload asset[/]"); + + AnsiConsole.WriteException(ex); + + return false; + } + }); + } + + private Release? MakeRelease(RepositoryApi repo) + { + AnsiConsole.Write("Adding release to gitea ... "); + + string sourceTail = _options.SourceClient.Version.Split('.').Last(); + + string targetTail = _options.TargetClient.Version.Split('.').Last(); + + string releaseName = $"{sourceTail} to {targetTail}"; + + try + { + var release = repo.RepoCreateRelease(_settings.GiteaReleaseRepoOwner, _settings.GiteaReleaseRepoName, new CreateReleaseOption(null, false, releaseName, false, sourceTail, null)); + + AnsiConsole.MarkupLine($"[green]Release added: {release.Name.EscapeMarkup()}[/]"); + + return release; + } + catch(Exception ex) + { + AnsiConsole.MarkupLine($"[red]Failed to create release[/]"); + + AnsiConsole.WriteException(ex); + + return null; + } + } + + public void Run() + { + AnsiConsole.WriteLine(); + + if (!_options.CreateRelease) return; + + Configuration.Default.BasePath = _settings.GiteaApiBasePath; + + Configuration.Default.AddApiKey("token", _settings.GiteaApiKey); + + var repo = new RepositoryApi(Configuration.Default); + + var release = MakeRelease(repo).ValidateOrExit(); + + var fileInfo = new FileInfo(_options.OutputPatchPath + ".zip"); + + UploadAsset(fileInfo, release, repo); + } + } +} diff --git a/EftPatchHelper/EftPatchHelper/Tasks/FileProcessingTasks.cs b/EftPatchHelper/EftPatchHelper/Tasks/FileProcessingTasks.cs new file mode 100644 index 0000000..6fc2039 --- /dev/null +++ b/EftPatchHelper/EftPatchHelper/Tasks/FileProcessingTasks.cs @@ -0,0 +1,55 @@ +using EftPatchHelper.EftInfo; +using EftPatchHelper.Extensions; +using EftPatchHelper.Helpers; +using EftPatchHelper.Interfaces; +using EftPatchHelper.Model; +using Spectre.Console; + +namespace EftPatchHelper.Tasks +{ + public class FileProcessingTasks : IFileProcessingTasks + { + Settings _settings; + Options _options; + + public FileProcessingTasks(Settings settings, Options options) + { + _settings = settings; + _options = options; + } + + private bool BackupClients() + { + bool targetOK = _options.TargetClient.Backup(_settings, _options.IgnoreExistingDirectories); + bool sourceOK = _options.SourceClient.Backup(_settings, _options.IgnoreExistingDirectories); + + return targetOK && sourceOK; + } + + private bool CopyData(EftClient client, string message) + { + AnsiConsole.WriteLine(); + AnsiConsole.MarkupLine(message); + + var folderCopy = new FolderCopy(client.FolderPath, client.PrepPath); + + return folderCopy.Start(_options.IgnoreExistingDirectories); + } + + private void CleanPrepFolders() + { + FolderCleaner.Clean(_options.TargetClient.PrepPath); + FolderCleaner.Clean(_options.SourceClient.PrepPath); + } + + public void Run() + { + BackupClients().ValidateOrExit(); + + CopyData(_options.SourceClient, "[gray]Copying[/] [blue]source[/][gray] to prep area ...[/]").ValidateOrExit(); + CopyData(_options.TargetClient, "[gray]Copying[/] [blue]target[/][gray] to prep area ...[/]").ValidateOrExit(); + + CleanPrepFolders(); + } + } +} diff --git a/EftPatchHelper/EftPatchHelper/Tasks/PatchGenTasks.cs b/EftPatchHelper/EftPatchHelper/Tasks/PatchGenTasks.cs new file mode 100644 index 0000000..1c8c877 --- /dev/null +++ b/EftPatchHelper/EftPatchHelper/Tasks/PatchGenTasks.cs @@ -0,0 +1,92 @@ +using EftPatchHelper.Extensions; +using EftPatchHelper.Interfaces; +using EftPatchHelper.Model; +using Spectre.Console; +using System.Diagnostics; + +namespace EftPatchHelper.Tasks +{ + internal class PatchGenTasks : IPatchGenTasks + { + private Settings _settings; + private Options _options; + + public PatchGenTasks(Settings settings, Options options) + { + _settings = settings; + _options = options; + } + + private bool RunPatchGenerator() + { + if (!File.Exists(_settings.PatcherEXEPath)) + { + AnsiConsole.WriteLine("Could not find patch generator exe"); + return false; + } + + string patcherOutputName = $"Patcher_{_options.SourceClient.Version}_to_{_options.TargetClient.Version}"; + + var patcherPath = new FileInfo(_settings.PatcherEXEPath)?.Directory?.FullName; + + if(patcherPath == null) + { + AnsiConsole.WriteLine("Could not find patch generator folder"); + return false; + } + + _options.OutputPatchPath = Path.Join(patcherPath, patcherOutputName); + + return AnsiConsole.Status().Start("Staring Patch Generator ...", (StatusContext context) => + { + var genProc = Process.Start(new ProcessStartInfo() + { + FileName = _settings.PatcherEXEPath, + WorkingDirectory = new FileInfo(_settings.PatcherEXEPath).Directory?.FullName ?? Directory.GetCurrentDirectory(), + ArgumentList = + { + $"OutputFolderName::{patcherOutputName}", + $"SourceFolderPath::{_options.SourceClient.PrepPath}", + $"TargetFolderPath::{_options.TargetClient.PrepPath}", + $"AutoZip::{_settings.AutoZip}", + $"AutoClose::{_settings.AutoClose}" + } + }); + + + context.Status = "Generating patches ..."; + + genProc?.WaitForExit(); + + switch ((PatcherExitCode)genProc.ExitCode) + { + case PatcherExitCode.ProgramClosed: + { + AnsiConsole.MarkupLine("[red]Program was closed[/]"); + return false; + } + case PatcherExitCode.Success: + { + AnsiConsole.MarkupLine("[green]Patches Generated[/]"); + return true; + } + case PatcherExitCode.MissingDir: + { + AnsiConsole.MarkupLine("[red]Missing Dir[/]"); + return false; + } + default: + { + AnsiConsole.MarkupLine("[red]Something went wrong[/]"); + return false; + } + } + }); + } + + public void Run() + { + RunPatchGenerator().ValidateOrExit(); + } + } +} \ No newline at end of file diff --git a/EftPatchHelper/EftPatchHelper/Tasks/PatchTestingTasks.cs b/EftPatchHelper/EftPatchHelper/Tasks/PatchTestingTasks.cs new file mode 100644 index 0000000..36bec98 --- /dev/null +++ b/EftPatchHelper/EftPatchHelper/Tasks/PatchTestingTasks.cs @@ -0,0 +1,84 @@ +using EftPatchHelper.Extensions; +using EftPatchHelper.Helpers; +using EftPatchHelper.Interfaces; +using EftPatchHelper.Model; +using Spectre.Console; +using System.Diagnostics; + +namespace EftPatchHelper.Tasks +{ + public class PatchTestingTasks : IPatchTestingTasks + { + private Settings _settings; + private Options _options; + + public PatchTestingTasks(Settings settings, Options options) + { + _settings = settings; + _options = options; + } + + private bool CopySourceToPrep() + { + AnsiConsole.WriteLine(); + AnsiConsole.MarkupLine($"Re-copying [blue]source[/] to prep area for testing ..."); + + var sourceCopy = new FolderCopy(_options.SourceClient.FolderPath, _options.SourceClient.PrepPath); + + return sourceCopy.Start(false, true); + } + + private bool RunPatcher() + { + var patcherCopy = new FolderCopy(_options.OutputPatchPath, _options.SourceClient.PrepPath); + + patcherCopy.Start(false, true); + + return AnsiConsole.Status().Start("Starting Patcher ...", (StatusContext context) => + { + var patchProcess = Process.Start(new ProcessStartInfo() + { + FileName = Path.Join(_options.SourceClient.PrepPath, "patcher.exe"), + ArgumentList = { "autoclose" }, + WorkingDirectory = _options.SourceClient.PrepPath + }); + + context.Status = "Running Patcher Test ..."; + + patchProcess.WaitForExit(); + + + switch ((PatcherExitCode)patchProcess.ExitCode) + { + case PatcherExitCode.Success: + { + AnsiConsole.MarkupLine("[green]Patch Test Succeeded[/]"); + return true; + } + case PatcherExitCode.NoPatchFolder: + { + AnsiConsole.MarkupLine("[red]No patch folder found[/]"); + return false; + } + case PatcherExitCode.MissingFile: + { + AnsiConsole.MarkupLine("[red]Missing file[/]"); + return false; + } + default: + { + AnsiConsole.MarkupLine("[red]Something went wrong[/]"); + return false; + } + } + }); + } + + public void Run() + { + CopySourceToPrep().ValidateOrExit(); + + RunPatcher().ValidateOrExit(); + } + } +} diff --git a/EftPatchHelper/EftPatchHelper/Tasks/StartupSettingsTask.cs b/EftPatchHelper/EftPatchHelper/Tasks/StartupSettingsTask.cs index 5fd57be..474f211 100644 --- a/EftPatchHelper/EftPatchHelper/Tasks/StartupSettingsTask.cs +++ b/EftPatchHelper/EftPatchHelper/Tasks/StartupSettingsTask.cs @@ -61,6 +61,10 @@ namespace EftPatchHelper.Tasks private void ConfirmOptions() { _options.IgnoreExistingDirectories = new ConfirmationPrompt("Skip existing directories? (you will be prompted if no)").Show(AnsiConsole.Console); + + if (!_settings.UsingGitea()) return; + + _options.CreateRelease = new ConfirmationPrompt("Create a release on gitea?").Show(AnsiConsole.Console); } public void Run() diff --git a/EftPatchHelper/EftPatchHelper/settings.json b/EftPatchHelper/EftPatchHelper/settings.json index ddde32b..1631198 100644 --- a/EftPatchHelper/EftPatchHelper/settings.json +++ b/EftPatchHelper/EftPatchHelper/settings.json @@ -5,5 +5,9 @@ "liveEftPath": "", "patcherExePath": "", "autoZip": true, - "autoClose": false + "autoClose": false, + "giteaApiBasePath": "", //You can leave the gitea settings blank if you don't need to create releases on gitea + "giteaApiKey": "", + "giteaReleaseRepoOwner": "", + "giteaReleaseRepoName": "" } \ No newline at end of file