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