diff options
author | vnugent <public@vaughnnugent.com> | 2024-09-06 20:50:06 -0400 |
---|---|---|
committer | vnugent <public@vaughnnugent.com> | 2024-09-06 20:50:06 -0400 |
commit | 7f1482c5d77b1b5f7e369ade925d2351d7623fa1 (patch) | |
tree | c99a0c8a0137e940492892977ef1e4f6f42b6d52 | |
parent | 79d824cfb0e0cc9ff4fab0e0c546a83c0edaae1c (diff) |
cleanup and add fluent-ftp as an publishing location
-rw-r--r-- | Taskfile.yaml | 2 | ||||
-rw-r--r-- | src/BuildFailedException.cs | 16 | ||||
-rw-r--r-- | src/BuildPipeline.cs | 3 | ||||
-rw-r--r-- | src/BuildStepFailedException.cs | 20 | ||||
-rw-r--r-- | src/Commands/BaseCommand.cs | 14 | ||||
-rw-r--r-- | src/Commands/PublishCommand.cs | 97 | ||||
-rw-r--r-- | src/Constants/Utils.cs | 7 | ||||
-rw-r--r-- | src/Extensions/BuildExtensions.cs | 2 | ||||
-rw-r--r-- | src/Extensions/ProjectExtensions.cs | 16 | ||||
-rw-r--r-- | src/MinioUploadManager.cs | 60 | ||||
-rw-r--r-- | src/Model/IUploadManager.cs | 6 | ||||
-rw-r--r-- | src/Publishing/BuildPublisher.cs (renamed from src/BuildPublisher.cs) | 26 | ||||
-rw-r--r-- | src/Publishing/FtpUploadManager.cs | 98 | ||||
-rw-r--r-- | src/Publishing/GpgSigner.cs (renamed from src/GpgSigner.cs) | 8 | ||||
-rw-r--r-- | src/Publishing/MinioUploadManager.cs | 43 | ||||
-rw-r--r-- | src/Publishing/SleetFeedManager.cs (renamed from src/SleetFeedManager.cs) | 7 | ||||
-rw-r--r-- | src/TaskFile.cs | 18 | ||||
-rw-r--r-- | src/vnbuild.csproj | 11 |
18 files changed, 314 insertions, 140 deletions
diff --git a/Taskfile.yaml b/Taskfile.yaml index 0e42d83..9333200 100644 --- a/Taskfile.yaml +++ b/Taskfile.yaml @@ -17,7 +17,7 @@ tasks: - powershell -Command "Get-ChildItem -Include *.cs,*.csproj -Recurse | Where { \$_.FullName -notlike '*\obj\*' } | Resolve-Path -Relative | tar --files-from - -czf '{{.TARGET}}/src.tgz'" #run post in debug mode - - for: [ win-x64, linux-x64, osx-x64, linux-arm64, linux-arm ] + - for: [ win-x64, linux-x64, osx-x64, linux-arm64, linux-arm ] task: postbuild vars: { BUILD_MODE: debug, TARGET_OS: '{{ .ITEM }}'} diff --git a/src/BuildFailedException.cs b/src/BuildFailedException.cs new file mode 100644 index 0000000..7f8f695 --- /dev/null +++ b/src/BuildFailedException.cs @@ -0,0 +1,16 @@ +using System; + +namespace VNLib.Tools.Build.Executor +{ + internal class BuildFailedException : Exception + { + public BuildFailedException() + { } + + public BuildFailedException(string? message) : base(message) + { } + + public BuildFailedException(string? message, Exception? innerException) : base(message, innerException) + { } + } +}
\ No newline at end of file diff --git a/src/BuildPipeline.cs b/src/BuildPipeline.cs index 2435566..70f6fd8 100644 --- a/src/BuildPipeline.cs +++ b/src/BuildPipeline.cs @@ -11,9 +11,10 @@ using VNLib.Tools.Build.Executor.Model; using VNLib.Tools.Build.Executor.Modules; using VNLib.Tools.Build.Executor.Extensions; using VNLib.Tools.Build.Executor.Constants; +using VNLib.Tools.Build.Executor.Publishing; namespace VNLib.Tools.Build.Executor -{ +{ public sealed class BuildPipeline(Logger Log) : IDisposable { diff --git a/src/BuildStepFailedException.cs b/src/BuildStepFailedException.cs index 0b78bf3..3ba5633 100644 --- a/src/BuildStepFailedException.cs +++ b/src/BuildStepFailedException.cs @@ -2,7 +2,7 @@ namespace VNLib.Tools.Build.Executor { - sealed class BuildStepFailedException : Exception + internal sealed class BuildStepFailedException : BuildFailedException { public string? ArtifactName { get; set; } @@ -13,17 +13,17 @@ namespace VNLib.Tools.Build.Executor { } - public BuildStepFailedException(string? message, Exception? innerException) : base(message, innerException) + public BuildStepFailedException(string? message, Exception? innerException) + : base(message, innerException) { } - public BuildStepFailedException(string? message, Exception? innerException, string name) : base(message, innerException) - { - ArtifactName = name; - } + public BuildStepFailedException(string? message, Exception? innerException, string name) + : base(message, innerException) + => ArtifactName = name; - public BuildStepFailedException(string message, string artifactName):base(message) - { - this.ArtifactName = artifactName; - } + public BuildStepFailedException(string message, string artifactName) : base(message) + => ArtifactName = artifactName; + + public override string Message => $"in: {ArtifactName} msg -> {base.Message}"; } }
\ No newline at end of file diff --git a/src/Commands/BaseCommand.cs b/src/Commands/BaseCommand.cs index 6362c22..25dcb0a 100644 --- a/src/Commands/BaseCommand.cs +++ b/src/Commands/BaseCommand.cs @@ -21,7 +21,7 @@ namespace VNLib.Tools.Build.Executor.Commands [CommandOption("force", 'f', Description = "Forces the operation even if steps are required")] public bool Force { get; set; } - [CommandOption("modules", 'm', Description = "Only use the specified modules, comma separated list")] + [CommandOption("include", 'i', Description = "Only use the specified modules, comma separated list")] public string? Modules { get; set; } [CommandOption("exclude", 'x', Description = "Ignores the specified modules, comma separated list")] @@ -79,11 +79,17 @@ namespace VNLib.Tools.Build.Executor.Commands } catch (OperationCanceledException) { - console.WithForegroundColor(ConsoleColor.Red, static o => o.Output.WriteLine("Operation cancelled")); + console.WithForegroundColor( + ConsoleColor.Red, + static o => o.Error.WriteLine("Operation cancelled") + ); } - catch(BuildStepFailedException be) + catch(BuildFailedException be) { - console.WithForegroundColor(ConsoleColor.Red, o => o.Output.WriteLine("FATAL: Build step failed on module {0}, msg -> {1}", be.ArtifactName, be.Message)); + console.WithForegroundColor( + ConsoleColor.Red, + o => o.Error.WriteLine("FATAL: Build step failed {0}", be.Message) + ); } } diff --git a/src/Commands/PublishCommand.cs b/src/Commands/PublishCommand.cs index 4179f86..33a7329 100644 --- a/src/Commands/PublishCommand.cs +++ b/src/Commands/PublishCommand.cs @@ -2,20 +2,25 @@ using System; using System.Linq; using System.Threading.Tasks; +using System.Collections.Generic; using Typin.Console; using Typin.Attributes; using VNLib.Tools.Build.Executor.Model; using VNLib.Tools.Build.Executor.Constants; +using VNLib.Tools.Build.Executor.Publishing; namespace VNLib.Tools.Build.Executor.Commands { [Command("publish", Description = "Runs publishig build steps on a completed build")] public sealed class PublishCommand(BuildPipeline pipeline, ConfigManager bm) : BaseCommand(pipeline, bm) { - [CommandOption("upload-path", 'p', Description = "The path to upload the build artifacts")] - public string? UploadPath { get; set; } + [CommandOption("minio", Description = "The path to upload the build artifacts")] + public string? MinioPath { get; set; } + + [CommandOption("ftp", Description = "The FTP server address to upload the build artifacts. Enables FTP mode over s3")] + public string? FtpServerAddress { get; set; } [CommandOption("sign", 's', Description = "Enables gpg signing of build artifacts")] public bool Sign { get; set; } = false; @@ -35,46 +40,102 @@ namespace VNLib.Tools.Build.Executor.Commands public override async ValueTask ExecStepsAsync(IConsole console) { //Specify custom output dir - (base.Config.Index as Dirs)!.OutputDir = BuildDirs.GetOrCreateDir(Constants.Config.OUTPUT_DIR, CustomOutDir); + (Config.Index as Dirs)!.OutputDir = BuildDirs.GetOrCreateDir(Constants.Config.OUTPUT_DIR, CustomOutDir); - IUploadManager? uploads = MinioUploadManager.Create(UploadPath); + IUploadManager uploads = GetUploadManager(console); IFeedManager? feed = Feeds.FirstOrDefault(); //Optional gpg signer for signing published artifacts BuildPublisher pub = new(Config, new GpgSigner(Sign, GpgKey)); - console.WithForegroundColor(ConsoleColor.DarkGreen, static o => o.Output.WriteLine("Publishing modules")); + console.WithForegroundColor( + ConsoleColor.DarkGreen, + static o => o.Output.WriteLine("Publishing modules") + ); //Run publish steps - await pipeline.OnPublishingAsync().ConfigureAwait(false); + await pipeline.OnPublishingAsync() + .ConfigureAwait(false); - console.WithForegroundColor(ConsoleColor.DarkGreen, static o => o.Output.WriteLine("Preparing module output for upload")); + console.WithForegroundColor( + ConsoleColor.DarkGreen, + static o => o.Output.WriteLine("Preparing module output for upload") + ); //Prepare the output - await pipeline.PrepareOutputAsync(pub).ConfigureAwait(false); - - if(uploads is null) - { - console.WithForegroundColor(ConsoleColor.DarkYellow, static o => o.Output.WriteLine("No upload path specified. Skipping upload")); - console.WithForegroundColor(ConsoleColor.Green, static o => o.Output.WriteLine("Upload build complete")); - return; - } + await pipeline.PrepareOutputAsync(pub) + .ConfigureAwait(false); //Run upload - await pipeline.ManualUpload(pub, uploads).ConfigureAwait(false); + await pipeline.ManualUpload(pub, uploads) + .ConfigureAwait(false); //Publish feeds if (feed is not null) { - console.WithForegroundColor(ConsoleColor.DarkGreen, static o => o.Output.WriteLine("Uploading feeds...")); + console.WithForegroundColor( + ConsoleColor.DarkGreen, + static o => o.Output.WriteLine("Uploading feeds...") + ); //Exec feed upload await uploads.UploadDirectoryAsync(feed.FeedOutputDir); } - console.WithForegroundColor(ConsoleColor.Green, static o => o.Output.WriteLine("Upload build complete")); + console.WithForegroundColor( + ConsoleColor.Green, + static o => o.Output.WriteLine("Upload build complete") + ); } public override IFeedManager[] Feeds => SleetPath is null ? [] : [SleetFeedManager.GetSleetFeed(SleetPath)]; + + private MultiUploadManager GetUploadManager(IConsole console) + { + try + { + IUploadManager[] uploadMan = []; + + if (!string.IsNullOrWhiteSpace(MinioPath)) + { + console.Output.WriteLine("Creating Minio publisher"); + + uploadMan = [MinioUploadManager.Create(MinioPath), ..uploadMan]; + } + + if (!string.IsNullOrWhiteSpace(FtpServerAddress)) + { + console.Output.WriteLine("Using FTP publisher"); + + uploadMan = [FtpUploadManager.Create(FtpServerAddress), .. uploadMan]; + } + + if(uploadMan.Length == 0) + { + console.WithForegroundColor( + ConsoleColor.DarkYellow, + static o => o.Output.WriteLine("No upload manager specified, output will be skipped") + ); + } + + return new MultiUploadManager(uploadMan); + } + catch(UriFormatException urie) + { + throw new BuildFailedException("Invalid server address", urie); + } + } + + private sealed class MultiUploadManager(params IUploadManager[] managers) : IUploadManager + { + private readonly IUploadManager[] _managers = managers; + + public async Task UploadDirectoryAsync(string path) + { + IEnumerable<Task> tasks = _managers.Select(m => m.UploadDirectoryAsync(path)); + + await Task.WhenAll(tasks); + } + } } }
\ No newline at end of file diff --git a/src/Constants/Utils.cs b/src/Constants/Utils.cs index 6047c35..80e8ceb 100644 --- a/src/Constants/Utils.cs +++ b/src/Constants/Utils.cs @@ -20,7 +20,12 @@ namespace VNLib.Tools.Build.Executor.Constants /// <param name="process">The name of the process to run</param> /// <param name="args">CLI arguments to pass to the process</param> /// <returns>The process exit code</returns> - public static async Task<int> RunProcessAsync(string process, string? workingDir, string[] args, IReadOnlyDictionary<string, string>? env = null) + public static async Task<int> RunProcessAsync( + string process, + string? workingDir, + string[] args, + IReadOnlyDictionary<string, string>? env = null + ) { //Init new console cancellation token using ConsoleCancelToken ctToken = new(); diff --git a/src/Extensions/BuildExtensions.cs b/src/Extensions/BuildExtensions.cs index 24af05e..a7e5931 100644 --- a/src/Extensions/BuildExtensions.cs +++ b/src/Extensions/BuildExtensions.cs @@ -103,7 +103,7 @@ namespace VNLib.Tools.Build.Executor.Extensions SemVersion baseVersion; //Get latest version tag from git - Tag? vTag = mod.Repository.Tags.OrderByDescending(p => SemVersion.Parse(p.FriendlyName, style)).FirstOrDefault(); + Tag? vTag = mod.Repository.Tags.OrderByDescending(p => SemVersion.Parse(p.FriendlyName, style), SemVersion.SortOrderComparer).FirstOrDefault(); //Find the number of commits since the last tag if (vTag != null) diff --git a/src/Extensions/ProjectExtensions.cs b/src/Extensions/ProjectExtensions.cs index a24e6c5..9bb55c1 100644 --- a/src/Extensions/ProjectExtensions.cs +++ b/src/Extensions/ProjectExtensions.cs @@ -61,12 +61,14 @@ namespace VNLib.Tools.Build.Executor.Extensions //realtive file path outDir = Path.Combine(project.WorkingDir.FullName, outDir); - return new DirectoryInfo(outDir).EnumerateFiles(config.OutputFileType, SearchOption.TopDirectoryOnly); - } - else - { - return project.WorkingDir.EnumerateFiles(config.OutputFileType, SearchOption.AllDirectories); + if (Directory.Exists(outDir)) + { + return new DirectoryInfo(outDir) + .EnumerateFiles(config.OutputFileType, SearchOption.TopDirectoryOnly); + } } + + return project.WorkingDir.EnumerateFiles(config.OutputFileType, SearchOption.AllDirectories); } /// <summary> @@ -122,7 +124,9 @@ namespace VNLib.Tools.Build.Executor.Extensions public static string GetSafeProjectName(this IProject project) { - return project.ProjectName.Replace('/', '-').Replace('\\','-'); + return project.ProjectName + .Replace('/', '-') + .Replace('\\','-'); } } }
\ No newline at end of file diff --git a/src/MinioUploadManager.cs b/src/MinioUploadManager.cs deleted file mode 100644 index 8337438..0000000 --- a/src/MinioUploadManager.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System.Diagnostics.CodeAnalysis; -using System.Threading.Tasks; - -using VNLib.Tools.Build.Executor.Model; - -using static VNLib.Tools.Build.Executor.Constants.Utils; - -namespace VNLib.Tools.Build.Executor -{ - internal class MinioUploadManager : IUploadManager - { - private readonly string _minioPath; - - private MinioUploadManager(string minioPath) - { - _minioPath = minioPath; - } - - public Task CleanAllAsync(string path) - { - throw new System.NotImplementedException(); - } - - public Task DeleteFileAsync(string filePath) - { - throw new System.NotImplementedException(); - } - - public async Task UploadDirectoryAsync(string path) - { - //Recursivley copy all files in the working directory - string[] args = - { - "cp", - "--recursive", - ".", - _minioPath - }; - - //Set working dir to the supplied dir path, and run the command - int result = await RunProcessAsync("mc", path, args); - - if(result != 0) - { - throw new BuildStepFailedException($"Failed to upload directory {path} with status code {result:x}"); - } - } - - public Task UploadFileAsync(string filePath) - { - throw new System.NotImplementedException(); - } - - [return:NotNullIfNotNull(nameof(uploadPath))] - public static IUploadManager? Create(string? uploadPath) - { - return string.IsNullOrWhiteSpace(uploadPath) ? null : new MinioUploadManager(uploadPath); - } - } -}
\ No newline at end of file diff --git a/src/Model/IUploadManager.cs b/src/Model/IUploadManager.cs index 01d7081..a132af7 100644 --- a/src/Model/IUploadManager.cs +++ b/src/Model/IUploadManager.cs @@ -4,12 +4,6 @@ namespace VNLib.Tools.Build.Executor.Model { public interface IUploadManager { - Task CleanAllAsync(string path); - - Task DeleteFileAsync(string filePath); - Task UploadDirectoryAsync(string path); - - Task UploadFileAsync(string filePath); } }
\ No newline at end of file diff --git a/src/BuildPublisher.cs b/src/Publishing/BuildPublisher.cs index a2dc2bf..67807d5 100644 --- a/src/BuildPublisher.cs +++ b/src/Publishing/BuildPublisher.cs @@ -16,7 +16,7 @@ using VNLib.Tools.Build.Executor.Extensions; using VNLib.Tools.Build.Executor.Projects; using static VNLib.Tools.Build.Executor.Constants.Config; -namespace VNLib.Tools.Build.Executor +namespace VNLib.Tools.Build.Executor.Publishing { public sealed class BuildPublisher(BuildConfig config, GpgSigner signer) @@ -159,9 +159,9 @@ namespace VNLib.Tools.Build.Executor //Build project array writer.WriteStartArray("versions"); - + //Write all git hashes from head back to the first commit - foreach(Commit commit in mod.Repository.Commits) + foreach (Commit commit in mod.Repository.Commits) { writer.WriteStringValue(commit.Sha); } @@ -172,7 +172,7 @@ namespace VNLib.Tools.Build.Executor writer.WriteStartArray("releases"); //Write all git tags - foreach(Tag tag in mod.Repository.Tags.OrderByDescending(static p => p.FriendlyName)) + foreach (Tag tag in mod.Repository.Tags.OrderByDescending(static p => p.FriendlyName)) { writer.WriteStartObject(); @@ -230,7 +230,10 @@ namespace VNLib.Tools.Build.Executor await mod.FileManager.WriteFileAsync(ModuleFileType.GitHistory, ms.ToArray()); - await mod.FileManager.WriteFileAsync(ModuleFileType.LatestHash, Encoding.UTF8.GetBytes(mod.Repository.Head.Tip.Sha)); + await mod.FileManager.WriteFileAsync( + ModuleFileType.LatestHash, + Encoding.UTF8.GetBytes(mod.Repository.Head.Tip.Sha) + ); } /* @@ -263,9 +266,9 @@ namespace VNLib.Tools.Build.Executor ); //Sign synchronously - foreach(FileInfo artifact in artifacts) + foreach (FileInfo artifact in artifacts) { - await signer.SignFileAsync(artifact); + await signer.SignFileAsync(artifact); } } } @@ -297,7 +300,7 @@ namespace VNLib.Tools.Build.Executor //Write tag history for current repo writer.WriteStartArray("tags"); - + foreach (Tag tag in repo.Tags) { //clamp message length and ellipsis if too long @@ -312,7 +315,7 @@ namespace VNLib.Tools.Build.Executor writer.WriteString("sha", tag.Target.Sha); writer.WriteString("message", message); writer.WriteString("author", tag.Annotation?.Tagger.Name); - writer.WriteString("date", (tag.Annotation?.Tagger.When ?? default)); + writer.WriteString("date", tag.Annotation?.Tagger.When ?? default); writer.WriteEndObject(); } @@ -387,7 +390,8 @@ namespace VNLib.Tools.Build.Executor private IEnumerable<FileInfo> GetProjOutputFiles(IModuleFileManager man, IProject project) { - return man.GetArtifactOutputDir(project).EnumerateFiles("*.*", SearchOption.TopDirectoryOnly) + return man.GetArtifactOutputDir(project) + .EnumerateFiles("*.*", SearchOption.TopDirectoryOnly) .Where(p => p.Extension != $".{config.HashFuncName}"); } @@ -403,7 +407,7 @@ namespace VNLib.Tools.Build.Executor string? archiveFile = Directory.EnumerateFiles(mod.Repository.Info.WorkingDirectory, config.SourceArchiveName, SearchOption.TopDirectoryOnly).FirstOrDefault(); //If archive is null ignore and continue - if(string.IsNullOrWhiteSpace(archiveFile)) + if (string.IsNullOrWhiteSpace(archiveFile)) { Log.Information("No archive file found for module {mod}", mod.ModuleName); return null; diff --git a/src/Publishing/FtpUploadManager.cs b/src/Publishing/FtpUploadManager.cs new file mode 100644 index 0000000..a955bb8 --- /dev/null +++ b/src/Publishing/FtpUploadManager.cs @@ -0,0 +1,98 @@ +using System; +using System.IO; + +using FluentFTP; + +using System.Diagnostics.CodeAnalysis; +using System.Threading.Tasks; + +using VNLib.Tools.Build.Executor.Model; +using VNLib.Tools.Build.Executor.Constants; + +namespace VNLib.Tools.Build.Executor.Publishing +{ + internal sealed class FtpUploadManager(AsyncFtpClient client, string remotePath) : IUploadManager + { + public async Task UploadDirectoryAsync(string path) + { + path = Directory.GetParent(path)!.FullName; + + await client.AutoConnect(); + + var res = await client.UploadDirectory( + localFolder: path, + remoteFolder: remotePath, + FtpFolderSyncMode.Update, + FtpRemoteExists.Overwrite, + FtpVerify.Throw | FtpVerify.Retry + ); + + foreach(FtpResult fileResult in res) + { + switch (fileResult.ToStatus()) + { + case FtpStatus.Success: + Config.Log.Information( + "Uploaded {size} bytes, {0} -> {1}", + fileResult.Size, + fileResult.LocalPath, + fileResult.RemotePath + ); + break; + + case FtpStatus.Skipped: + Config.Log.Information("Skipped {0} -> {1}", fileResult.LocalPath, fileResult.RemotePath); + break; + + case FtpStatus.Failed: + Config.Log.Warning( + "Failed to upload {0}, reason: {exp}", + fileResult.LocalPath, + fileResult.Exception?.Message + ); + break; + } + } + } + + [return: NotNullIfNotNull(nameof(serverAddress))] + public static IUploadManager? Create(string? serverAddress) + { + if(string.IsNullOrWhiteSpace(serverAddress)) + { + return null; + } + + //Convert to uri, this may throw but this is currently the best way to validate the address + Uri serverUri = new(serverAddress); + + //Initlaize the client + AsyncFtpClient client = new() + { + Host = serverUri.Host, + Port = serverUri.Port, + + + Config = new() + { + LogToConsole = Config.Log.IsEnabled(Serilog.Events.LogEventLevel.Verbose), + + //Disable senstive logging in case running in automated CI pipelines where logs may be published + LogUserName = false, + LogPassword = false, + //EncryptionMode = FtpEncryptionMode.Auto, + RetryAttempts = 3, + }, + + Credentials = new() + { + //Pull credentials from the environment instead of command line + UserName = Environment.GetEnvironmentVariable("FTP_USERNAME"), + Password = Environment.GetEnvironmentVariable("FTP_PASSWORD") + }, + }; + + return new FtpUploadManager(client, serverUri.LocalPath); + } + } +}
\ No newline at end of file diff --git a/src/GpgSigner.cs b/src/Publishing/GpgSigner.cs index 76943f9..3ed216a 100644 --- a/src/GpgSigner.cs +++ b/src/Publishing/GpgSigner.cs @@ -5,7 +5,7 @@ using System.Collections.Generic; using VNLib.Tools.Build.Executor.Constants; -namespace VNLib.Tools.Build.Executor +namespace VNLib.Tools.Build.Executor.Publishing { public sealed class GpgSigner(bool enabled, string? defaultKey) { @@ -18,7 +18,9 @@ namespace VNLib.Tools.Build.Executor return; } - List<string> args = [ "--detach-sign" ]; + List<string> args = [ + "--detach-sign" + ]; if (!string.IsNullOrWhiteSpace(defaultKey)) { @@ -45,7 +47,7 @@ namespace VNLib.Tools.Build.Executor case 0: break; default: - throw new Exception($"Failed to sign file {file.FullName}"); + throw new BuildFailedException($"Failed to sign file {file.FullName}"); } } } diff --git a/src/Publishing/MinioUploadManager.cs b/src/Publishing/MinioUploadManager.cs new file mode 100644 index 0000000..502392f --- /dev/null +++ b/src/Publishing/MinioUploadManager.cs @@ -0,0 +1,43 @@ +using System.Threading.Tasks; +using System.Diagnostics.CodeAnalysis; + +using VNLib.Tools.Build.Executor.Model; + +using static VNLib.Tools.Build.Executor.Constants.Utils; + +namespace VNLib.Tools.Build.Executor.Publishing +{ + + internal sealed class MinioUploadManager : IUploadManager + { + private readonly string _minioPath; + + private MinioUploadManager(string minioPath) => _minioPath = minioPath; + + public async Task UploadDirectoryAsync(string path) + { + //Recursivley copy all files in the working directory + string[] args = + { + "cp", + "--recursive", + ".", + _minioPath + }; + + //Set working dir to the supplied dir path, and run the command + int result = await RunProcessAsync("mc", path, args); + + if (result != 0) + { + throw new BuildFailedException($"Failed to upload directory {path} with status code {result:x}"); + } + } + + [return: NotNullIfNotNull(nameof(uploadPath))] + public static IUploadManager? Create(string? uploadPath) + { + return string.IsNullOrWhiteSpace(uploadPath) ? null : new MinioUploadManager(uploadPath); + } + } +}
\ No newline at end of file diff --git a/src/SleetFeedManager.cs b/src/Publishing/SleetFeedManager.cs index bc77ff1..997dcf2 100644 --- a/src/SleetFeedManager.cs +++ b/src/Publishing/SleetFeedManager.cs @@ -2,10 +2,9 @@ using System.Diagnostics.CodeAnalysis; using System.IO; using System.Text.Json; - using VNLib.Tools.Build.Executor.Model; -namespace VNLib.Tools.Build.Executor +namespace VNLib.Tools.Build.Executor.Publishing { internal sealed class SleetFeedManager : IFeedManager { @@ -35,10 +34,10 @@ namespace VNLib.Tools.Build.Executor /// <returns>The feed manager if found, null otherwise</returns> /// <exception cref="FileNotFoundException"></exception> /// <exception cref="ArgumentException"></exception> - [return:NotNullIfNotNull(nameof(feedPath))] + [return: NotNullIfNotNull(nameof(feedPath))] public static IFeedManager? GetSleetFeed(string? feedPath) { - if(string.IsNullOrWhiteSpace(feedPath)) + if (string.IsNullOrWhiteSpace(feedPath)) { return null; } diff --git a/src/TaskFile.cs b/src/TaskFile.cs index 6eef779..e8fa26e 100644 --- a/src/TaskFile.cs +++ b/src/TaskFile.cs @@ -56,7 +56,7 @@ namespace VNLib.Tools.Build.Executor args.Add(GetCommand(command)); //Exec task in the module dir - int result = await RunProcessAsync(taskFilePath, scope.WorkingDir.FullName, args.ToArray(), vars); + int result = await RunProcessAsync(taskFilePath, scope.WorkingDir.FullName, [.. args], vars); if(throwIfFailed) { @@ -68,14 +68,14 @@ namespace VNLib.Tools.Build.Executor { return cmd switch { - TaskfileComamnd.Clean => "clean", - TaskfileComamnd.Build => "build", - TaskfileComamnd.Upload => "upload", - TaskfileComamnd.Update => "update", - TaskfileComamnd.PostbuildSuccess => "postbuild_success", - TaskfileComamnd.PostbuildFailure => "postbuild_failed", - TaskfileComamnd.Publish => "publish", - TaskfileComamnd.Test => "test", + TaskfileComamnd.Clean => "clean", + TaskfileComamnd.Build => "build", + TaskfileComamnd.Upload => "upload", + TaskfileComamnd.Update => "update", + TaskfileComamnd.PostbuildSuccess => "postbuild_success", + TaskfileComamnd.PostbuildFailure => "postbuild_failed", + TaskfileComamnd.Publish => "publish", + TaskfileComamnd.Test => "test", _ => throw new NotImplementedException() }; } diff --git a/src/vnbuild.csproj b/src/vnbuild.csproj index b3e32df..b506f59 100644 --- a/src/vnbuild.csproj +++ b/src/vnbuild.csproj @@ -33,13 +33,14 @@ </ItemGroup> <ItemGroup> + <PackageReference Include="FluentFTP" Version="51.0.0" /> <PackageReference Include="Typin" Version="3.1.0" /> <PackageReference Include="LibGit2Sharp" Version="0.30.0" /> - <PackageReference Include="Microsoft.Build" Version="17.10.0-preview-24081-01" /> - <PackageReference Include="Semver" Version="3.0.0-beta.1" /> - <PackageReference Include="Serilog" Version="4.0.0-dev-02166" /> - <PackageReference Include="Serilog.Sinks.Console" Version="5.1.0-dev-00943" /> - <PackageReference Include="Serilog.Sinks.File" Version="5.0.1-dev-00972" /> + <PackageReference Include="Microsoft.Build" Version="17.11.4" /> + <PackageReference Include="Semver" Version="2.3.0" /> + <PackageReference Include="Serilog" Version="4.0.1" /> + <PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" /> + <PackageReference Include="Serilog.Sinks.File" Version="6.0.0" /> </ItemGroup> </Project> |