Compare commits

..

No commits in common. "6167461ad884b3863a365cb600cde9e3a80498fb" and "9fe53b344ae49a94cf5433b5cf2f2c250c6cd21c" have entirely different histories.

3 changed files with 77 additions and 101 deletions

View File

@ -1,36 +0,0 @@
name: Build and Generate Release Artifact
on:
push:
tags:
- "*"
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Build csSiteGen
uses: actions/setup-dotnet@v3
with:
dotnet-version: 10.x
-run: |
dotnet publish csSiteGen.csproj \
-c Release \
-r linux-x64 \
--self-contained true \
/p:PublishSingleFile=true \
/p:PublishTrimmed=true \
-o ./publish
- name: Create Gitea Release
id: create_release
uses: akkuman/gitea-release-action@v1
env:
NODE_OPTIONS: '--experimental-fetch'
with:
files: |-
./publish/csSiteGen

View File

@ -17,6 +17,8 @@
*/ */
using Serilog; using Serilog;
using System.CommandLine.Builder;
using System.CommandLine.Parsing;
using System.CommandLine; using System.CommandLine;
using System.Diagnostics; using System.Diagnostics;
using System.Reflection; using System.Reflection;
@ -64,59 +66,70 @@ class Program
Stopwatch TotalExecutionTime = Stopwatch.StartNew(); Stopwatch TotalExecutionTime = Stopwatch.StartNew();
/* WARN: /* !! IMPORTANT !!
This code uses system.commandline WARN:
This code uses system.commandline which is still in pre-release
the following section of code will contain comments to explain the intent of the programmer the following section of code will contain comments to explain the intent of the programmer
which may be useful if system.commandline has breaking changes which may be useful if system.commandline has breaking changes
*/ */
// First the option for the project directory is created // First the option for the project directory is created
Option<DirectoryInfo> ProjectDirectoryOption = new("--project","-p") var ProjectDirectoryOption = new Option<DirectoryInfo>(
name: "--project",
description: "The Directory for the project");
ProjectDirectoryOption.IsRequired = false; // it is not required as not providing it infers that the current directory is the project directory
// If the option is used then the input is validated before control passes to any of the actual code.
ProjectDirectoryOption.AddValidator(result =>
{ {
Description = "The directory of the project", if (!result.GetValueForOption(ProjectDirectoryOption)!.Exists)
Required = false,
DefaultValueFactory = _ =>
{ {
return new DirectoryInfo(Directory.GetCurrentDirectory()); result.ErrorMessage = $"Project directory {result.GetValueForOption(ProjectDirectoryOption)} does not exist.";
} }
};
// Add a validator as we want the directory to exist.
ProjectDirectoryOption.Validators.Add(result =>
{
if (! result.GetValue(ProjectDirectoryOption)!.Exists)
{
result.AddError($"Directory {result.GetValue(ProjectDirectoryOption)} does not exist");
Log.Fatal($"Passed directory '{result.GetValue(ProjectDirectoryOption)}' does not exist");
} }
}); );
// The root command is the entry point for commandline but otherwise does nothing. // The root command is the entry point for commandline but otherwise does nothing.
RootCommand rootCommand = new("csSiteGen"); var rootCommand = new RootCommand("csSiteGen");
// TODO: Verify if the use of async in these functions is necessary
// This creates the command for cleaning a projects output directory. // This creates the command for cleaning a projects output directory.
var cleanCommand = new Command("clean", "Clean the projects output directory"); var cleanCommand = new Command("clean", "Clean the projects output directory");
cleanCommand.Options.Add(ProjectDirectoryOption); // This command can use the project directory option we created earlier cleanCommand.AddOption(ProjectDirectoryOption); // This command can use the project directory option we created earlier
cleanCommand.SetAction(parseResult => cleanCommand.SetHandler(async (ProjectDirectory) =>
{ {
Clean(parseResult.GetValue<DirectoryInfo>("--project")!); await Task.Run(() =>
{
Clean(ProjectDirectory);
}); });
},ProjectDirectoryOption);
// This creates the command for actually converting the project. // This creates the command for actually converting the project.
var convertCommand = new Command("convert", "Convert the projects input directory and place the files in the output directory."); var convertCommand = new Command("convert", "Convert the projects input directory and place the files in the output directory.");
convertCommand.Options.Add(ProjectDirectoryOption); // This command can use the project directory option convertCommand.AddOption(ProjectDirectoryOption); // This command can use the project directory option
convertCommand.SetAction(parseResult => convertCommand.SetHandler(async (ProjectDirectory) =>
{ {
Convert(parseResult.GetValue<DirectoryInfo>("--project")!); await Task.Run(() =>
{
Convert(ProjectDirectory);
}); });
},ProjectDirectoryOption);
// Adding the commands to the root command makes them actually callable on the commandline // Adding the commands to the root command makes them actually callable on the commandline
rootCommand.Subcommands.Add(cleanCommand); rootCommand.AddCommand(cleanCommand);
rootCommand.Subcommands.Add(convertCommand); rootCommand.AddCommand(convertCommand);
// The parser is what actually handles the arguments and dispatches them to the appropriate commands.
// This is used instead of the simpler method of just Invoking the root command as it automatically creates usage statements.
// It also makes a user aware that a subcommand needs to be used.
var parser = new CommandLineBuilder(rootCommand)
.UseDefaults()
.Build();
parser.Invoke(args);
// Parse the commandline and immediately execute.
rootCommand.Parse(args).Invoke();
TotalExecutionTime.Stop(); TotalExecutionTime.Stop();
Log.Information("TotalExecutionTime {time:000}ms", TotalExecutionTime.ElapsedMilliseconds); Log.Information("TotalExecutionTime {time:000}ms", TotalExecutionTime.ElapsedMilliseconds);
@ -126,12 +139,12 @@ class Program
return 0; return 0;
} }
static int Convert(DirectoryInfo ProjectDirectory) static int Convert(DirectoryInfo? ProjectDirectory)
{ {
Log.Information("Convert command was called, beginning conversion."); Log.Information("Convert command was called, beginning conversion.");
// WARN: This is only temporary as Spectre.Console does not recognise some Linux terminals // WARN: This is only temporary as Spectre.Console does not recognise some Linux terminals
// TODO: A better solution that checks the terminal value and sets this option should be added in the future. // A better solution that checks the terminal value and sets this option should be added in the future.
AnsiConsole.Console.Profile.Capabilities.Ansi = true; AnsiConsole.Console.Profile.Capabilities.Ansi = true;
@ -198,7 +211,7 @@ class Program
return 0; return 0;
} }
static int Clean(DirectoryInfo ProjectDirectory) static int Clean(DirectoryInfo? ProjectDirectory)
{ {
Log.Information("Clean command was called, Beginning cleaning"); Log.Information("Clean command was called, Beginning cleaning");
@ -270,10 +283,15 @@ class Program
} }
static ProjectSettings GetProjectSettings(DirectoryInfo ProjectDirectory) static ProjectSettings GetProjectSettings(DirectoryInfo? ProjectDirectory)
{ {
// TODO: implement proper error handling where file access is performed. // TODO: implement proper error handling where file access is performed.
if (ProjectDirectory is null)
{
// use the current directory if no project directory is passed.
ProjectDirectory = new DirectoryInfo(".");
}
Log.Information("{projectdir} => fullname {pdfn}",ProjectDirectory, ProjectDirectory.FullName); Log.Information("{projectdir} => fullname {pdfn}",ProjectDirectory, ProjectDirectory.FullName);
FileInfo projectFile = new (Path.Combine(ProjectDirectory.FullName,"cssitegen.json")); FileInfo projectFile = new (Path.Combine(ProjectDirectory.FullName,"cssitegen.json"));
@ -281,7 +299,6 @@ class Program
if (!projectFile.Exists) if (!projectFile.Exists)
{ {
Log.Fatal("Cannot locate project file {pf} in {dir}",projectFile,ProjectDirectory); Log.Fatal("Cannot locate project file {pf} in {dir}",projectFile,ProjectDirectory);
AnsiConsole.MarkupLineInterpolated($"[red]No project file found in [yellow]{ProjectDirectory}[/][/]");
Environment.Exit(1); Environment.Exit(1);
} }

View File

@ -3,47 +3,42 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework> <Version Condition="'$(RELEASE_VERSION)' != ''">$(RELEASE_VERSION)</Version>
<ImplicitUsings>enable</ImplicitUsings> <VersionPrefix Condition="'$(RELEASE_VERSION)' == ''">0.0.3</VersionPrefix>
<Nullable>enable</Nullable> <VersionSuffix Condition="'$(RELEASE_VERSION)' == ''">$([System.DateTime]::UtcNow.ToString(`yyyyMMdd-HHmm`))</VersionSuffix>
<PublishSingleFile>True</PublishSingleFile>
<SelfContained>True</SelfContained>
<PublishTrimmed>True</PublishTrimmed>
<OutputPath>bin\$(Configuration)\</OutputPath> <OutputPath>bin\$(Configuration)\</OutputPath>
<Version Condition="'$(RELEASE_VERSION)' != ''">$(RELEASE_VERSION)</Version> <TargetFramework>net10.0</TargetFramework>
<VersionPrefix Condition="'$(RELEASE_VERSION)' == ''">0.0.4</VersionPrefix> <ImplicitUsings>enable</ImplicitUsings>
<VersionSuffix Condition="'$(RELEASE_VERSION)' == ''">$([System.DateTime]::UtcNow.ToString(`yyyyMMdd-HHmm`))</VersionSuffix> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<PackageReference Include="Serilog" Version="4.0.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="5.0.1" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="spectre.console" Version="0.49.1" />
<PackageReference Include="system.commandline" Version="2.0.0-beta4.22272.1" />
</ItemGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<!-- Here we define the Debug Build. <!-- Here we define the Debug Build.
--> -->
<TreatWarningsAsErrors>false</TreatWarningsAsErrors> <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<DefineDebug>true</DefineDebug>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' "> <PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<!-- Here we define the release build.
The Release Build will be a Single file App
The Release Build will also do -Werror as I don't want to release shitty code
The Release Build will also be R2R as I don't want it to depend on the framework
NOTE: This build requires specifying a platform
-->
<TreatWarningsAsErrors>true</TreatWarningsAsErrors> <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<PublishAOT>true</PublishAOT>
<SuppressTrimAnalysisWarnings>false</SuppressTrimAnalysisWarnings> <SuppressTrimAnalysisWarnings>false</SuppressTrimAnalysisWarnings>
<TrimmerSingleWarn>false</TrimmerSingleWarn> <TrimmerSingleWarn>false</TrimmerSingleWarn>
<DebugSymbols>false</DebugSymbols>
<DefineDebug>false</DefineDebug>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<PackageReference Include="Serilog" Version="4.3.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="6.1.1" />
<PackageReference Include="Serilog.Sinks.File" Version="7.0.0" />
<PackageReference Include="spectre.console" Version="0.54.0" />
<PackageReference Include="system.commandline" Version="2.0.1" />
</ItemGroup>
</Project> </Project>