From e6ed407285077fffc3def8e92d3b66287ac24cda Mon Sep 17 00:00:00 2001 From: jackfiled Date: Mon, 19 Aug 2024 20:44:14 +0800 Subject: [PATCH] add: CLI support. --- YaeBlog/Commands/BlogOptionsBinder.cs | 30 +++++++++ YaeBlog/Commands/CommandExtensions.cs | 90 ++++++++++++++++++++++++++ YaeBlog/Dockerfile | 2 +- YaeBlog/Program.cs | 25 ++----- YaeBlog/Properties/launchSettings.json | 2 +- YaeBlog/YaeBlog.csproj | 1 + 6 files changed, 129 insertions(+), 21 deletions(-) create mode 100644 YaeBlog/Commands/BlogOptionsBinder.cs create mode 100644 YaeBlog/Commands/CommandExtensions.cs diff --git a/YaeBlog/Commands/BlogOptionsBinder.cs b/YaeBlog/Commands/BlogOptionsBinder.cs new file mode 100644 index 0000000..2641dbd --- /dev/null +++ b/YaeBlog/Commands/BlogOptionsBinder.cs @@ -0,0 +1,30 @@ +using System.CommandLine.Binding; +using System.Text.Json; +using YaeBlog.Core.Models; + +namespace YaeBlog.Commands; + +public sealed class BlogOptionsBinder : BinderBase +{ + protected override BlogOptions GetBoundValue(BindingContext bindingContext) + { + FileInfo settings = new(Path.Combine(Environment.CurrentDirectory, "appsettings.json")); + if (!settings.Exists) + { + throw new InvalidOperationException("Failed to load YaeBlog configurations."); + } + + using StreamReader reader = settings.OpenText(); + using JsonDocument document = JsonDocument.Parse(reader.ReadToEnd()); + JsonElement root = document.RootElement; + JsonElement optionSection = root.GetProperty(BlogOptions.OptionName); + + BlogOptions? result = optionSection.Deserialize(); + if (result is null) + { + throw new InvalidOperationException("Failed to load YaeBlog configuration in appsettings.json."); + } + + return result; + } +} diff --git a/YaeBlog/Commands/CommandExtensions.cs b/YaeBlog/Commands/CommandExtensions.cs new file mode 100644 index 0000000..b5b0b03 --- /dev/null +++ b/YaeBlog/Commands/CommandExtensions.cs @@ -0,0 +1,90 @@ +using System.CommandLine; +using YaeBlog.Components; +using YaeBlog.Core.Extensions; + +namespace YaeBlog.Commands; + +public static class CommandExtensions +{ + public static Command AddServeCommand(this RootCommand rootCommand) + { + Command serveCommand = new("serve", "Start http server."); + rootCommand.AddCommand(serveCommand); + + serveCommand.SetHandler(async context => + { + WebApplicationBuilder builder = WebApplication.CreateBuilder(); + + builder.Services.AddRazorComponents() + .AddInteractiveServerComponents(); + builder.Services.AddControllers(); + builder.Services.AddBlazorBootstrap(); + builder.AddYaeBlog(); + + WebApplication application = builder.Build(); + + application.UseStaticFiles(); + application.UseAntiforgery(); + application.UseYaeBlog(); + + application.MapRazorComponents() + .AddInteractiveServerRenderMode(); + application.MapControllers(); + + CancellationToken token = context.GetCancellationToken(); + await application.RunAsync(token); + }); + + return rootCommand; + } + + public static Command AddNewCommand(this RootCommand rootCommand) + { + Command newCommand = new("new", "Create a new blog file and image directory."); + rootCommand.AddCommand(newCommand); + + Argument filenameArgument = new(name: "blog name", description: "The created blog filename."); + newCommand.AddArgument(filenameArgument); + + newCommand.SetHandler(async (file, blogOptions) => + { + string fileWithExtension; + if (file.EndsWith(".md")) + { + fileWithExtension = file; + file = fileWithExtension[..fileWithExtension.LastIndexOf('.')]; + } + else + { + fileWithExtension = file + ".md"; + } + + DirectoryInfo rootDir = new(Path.Combine(Environment.CurrentDirectory, blogOptions.Root)); + if (!rootDir.Exists) + { + throw new InvalidOperationException($"Blog source directory '{blogOptions.Root} doesn't exist."); + } + + if (rootDir.EnumerateFiles().Any(f => f.Name == fileWithExtension)) + { + throw new InvalidOperationException($"Target blog '{file}' has been created!"); + } + + FileInfo newBlogFile = new(Path.Combine(rootDir.FullName, fileWithExtension)); + await using StreamWriter newStream = newBlogFile.CreateText(); + + await newStream.WriteAsync($""" + --- + title: {file} + tags: + --- + + """); + + Console.WriteLine($"Created new blog '{file}."); + }, filenameArgument, new BlogOptionsBinder()); + + + return newCommand; + } +} diff --git a/YaeBlog/Dockerfile b/YaeBlog/Dockerfile index 162308e..301432e 100644 --- a/YaeBlog/Dockerfile +++ b/YaeBlog/Dockerfile @@ -5,4 +5,4 @@ COPY bin/Release/net8.0/publish/ ./ COPY source/ ./source/ COPY appsettings.json . -ENTRYPOINT ["dotnet", "YaeBlog.dll"] +ENTRYPOINT ["dotnet", "YaeBlog.dll", "serve"] diff --git a/YaeBlog/Program.cs b/YaeBlog/Program.cs index dd92dde..fc5acd2 100644 --- a/YaeBlog/Program.cs +++ b/YaeBlog/Program.cs @@ -1,22 +1,9 @@ -using YaeBlog.Components; -using YaeBlog.Core.Extensions; +using System.CommandLine; +using YaeBlog.Commands; -WebApplicationBuilder builder = WebApplication.CreateBuilder(args); +RootCommand rootCommand = new("YaeBlog CLI"); -builder.Services.AddRazorComponents() - .AddInteractiveServerComponents(); -builder.Services.AddControllers(); -builder.Services.AddBlazorBootstrap(); -builder.AddYaeBlog(); +rootCommand.AddServeCommand(); +rootCommand.AddNewCommand(); -WebApplication application = builder.Build(); - -application.UseStaticFiles(); -application.UseAntiforgery(); -application.UseYaeBlog(); - -application.MapRazorComponents() - .AddInteractiveServerRenderMode(); -application.MapControllers(); - -await application.RunAsync(); +await rootCommand.InvokeAsync(args); diff --git a/YaeBlog/Properties/launchSettings.json b/YaeBlog/Properties/launchSettings.json index 37fd6e7..53831cc 100644 --- a/YaeBlog/Properties/launchSettings.json +++ b/YaeBlog/Properties/launchSettings.json @@ -12,7 +12,7 @@ "http": { "commandName": "Project", "dotnetRunMessages": true, - "launchBrowser": true, + "launchBrowser": false, "applicationUrl": "http://localhost:5275", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" diff --git a/YaeBlog/YaeBlog.csproj b/YaeBlog/YaeBlog.csproj index f43a4e6..976e76e 100644 --- a/YaeBlog/YaeBlog.csproj +++ b/YaeBlog/YaeBlog.csproj @@ -6,6 +6,7 @@ +