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 System.CommandLine.Builder;
using System.CommandLine.Parsing;
using System.CommandLine;
using System.Diagnostics;
using System.Reflection;
@ -64,59 +66,70 @@ class Program
Stopwatch TotalExecutionTime = Stopwatch.StartNew();
/* WARN:
This code uses system.commandline
/* !! IMPORTANT !!
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
which may be useful if system.commandline has breaking changes
*/
// First the option for the project directory is created
Option<DirectoryInfo> ProjectDirectoryOption = new("--project","-p")
{
Description = "The directory of the project",
Required = false,
DefaultValueFactory = _ =>
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 =>
{
return new DirectoryInfo(Directory.GetCurrentDirectory());
}
};
// Add a validator as we want the directory to exist.
ProjectDirectoryOption.Validators.Add(result =>
if (!result.GetValueForOption(ProjectDirectoryOption)!.Exists)
{
if (! result.GetValue(ProjectDirectoryOption)!.Exists)
{
result.AddError($"Directory {result.GetValue(ProjectDirectoryOption)} does not exist");
Log.Fatal($"Passed directory '{result.GetValue(ProjectDirectoryOption)}' does not exist");
}
});
result.ErrorMessage = $"Project directory {result.GetValueForOption(ProjectDirectoryOption)} does not exist.";
}
}
);
// 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.
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.SetAction(parseResult =>
cleanCommand.AddOption(ProjectDirectoryOption); // This command can use the project directory option we created earlier
cleanCommand.SetHandler(async (ProjectDirectory) =>
{
Clean(parseResult.GetValue<DirectoryInfo>("--project")!);
});
await Task.Run(() =>
{
Clean(ProjectDirectory);
});
},ProjectDirectoryOption);
// 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.");
convertCommand.Options.Add(ProjectDirectoryOption); // This command can use the project directory option
convertCommand.SetAction(parseResult =>
convertCommand.AddOption(ProjectDirectoryOption); // This command can use the project directory option
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
rootCommand.Subcommands.Add(cleanCommand);
rootCommand.Subcommands.Add(convertCommand);
rootCommand.AddCommand(cleanCommand);
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();
Log.Information("TotalExecutionTime {time:000}ms", TotalExecutionTime.ElapsedMilliseconds);
@ -126,12 +139,12 @@ class Program
return 0;
}
static int Convert(DirectoryInfo ProjectDirectory)
static int Convert(DirectoryInfo? ProjectDirectory)
{
Log.Information("Convert command was called, beginning conversion.");
// 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;
@ -198,7 +211,7 @@ class Program
return 0;
}
static int Clean(DirectoryInfo ProjectDirectory)
static int Clean(DirectoryInfo? ProjectDirectory)
{
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.
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);
FileInfo projectFile = new (Path.Combine(ProjectDirectory.FullName,"cssitegen.json"));
@ -281,7 +299,6 @@ class Program
if (!projectFile.Exists)
{
Log.Fatal("Cannot locate project file {pf} in {dir}",projectFile,ProjectDirectory);
AnsiConsole.MarkupLineInterpolated($"[red]No project file found in [yellow]{ProjectDirectory}[/][/]");
Environment.Exit(1);
}

View File

@ -2,48 +2,43 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<Version Condition="'$(RELEASE_VERSION)' != ''">$(RELEASE_VERSION)</Version>
<VersionPrefix Condition="'$(RELEASE_VERSION)' == ''">0.0.3</VersionPrefix>
<VersionSuffix Condition="'$(RELEASE_VERSION)' == ''">$([System.DateTime]::UtcNow.ToString(`yyyyMMdd-HHmm`))</VersionSuffix>
<OutputPath>bin\$(Configuration)\</OutputPath>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<PublishSingleFile>True</PublishSingleFile>
<SelfContained>True</SelfContained>
<PublishTrimmed>True</PublishTrimmed>
<OutputPath>bin\$(Configuration)\</OutputPath>
<Version Condition="'$(RELEASE_VERSION)' != ''">$(RELEASE_VERSION)</Version>
<VersionPrefix Condition="'$(RELEASE_VERSION)' == ''">0.0.4</VersionPrefix>
<VersionSuffix Condition="'$(RELEASE_VERSION)' == ''">$([System.DateTime]::UtcNow.ToString(`yyyyMMdd-HHmm`))</VersionSuffix>
</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' ">
<!-- Here we define the Debug Build.
-->
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<DefineDebug>true</DefineDebug>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<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>
<PublishAOT>true</PublishAOT>
<SuppressTrimAnalysisWarnings>false</SuppressTrimAnalysisWarnings>
<TrimmerSingleWarn>false</TrimmerSingleWarn>
<DebugSymbols>false</DebugSymbols>
<DefineDebug>false</DefineDebug>
</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>