Compare commits

...

5 Commits

Author SHA1 Message Date
6167461ad8
fix(publish) fix typo in publish.yaml
All checks were successful
Run Build / dotnet (push) Successful in 38s
Build and Generate Release Artifact / build (push) Successful in 24s
2026-01-04 02:17:27 +00:00
7b41afd790
chore(version): Bump version to 0.0.4
Some checks failed
Run Build / dotnet (push) Successful in 41s
Build and Generate Release Artifact / build (push) Failing after 17s
2026-01-04 02:13:00 +00:00
ddfae61fdc
ci(gitea): Automate building of linux artifact
Automate the building of the Linux artifact and creation of a release on
new tags
2026-01-04 02:10:51 +00:00
5169aede88
chore(csproj): Cleanup csproj file 2026-01-04 02:04:04 +00:00
700dc715fb
chore(dependencies): Upgrade dependencies
This commit brings the dependencies up to date.

This more importantly brings the stable version of system.commandline
and all the changes needed to make it work properly with the program.

Importantly this changes how validation is done, and how defaults are
passed to commandline. This also allows me to remove the original null
protection as when the argument is not specified commandline defaults to
the current directory.

This has also meant I can remove unnecessary async calls that appear to
have no performance benefits, and remove some null checking that isn't
needed any more.
2026-01-03 04:00:54 +00:00
3 changed files with 101 additions and 77 deletions

View File

@ -0,0 +1,36 @@
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,8 +17,6 @@
*/
using Serilog;
using System.CommandLine.Builder;
using System.CommandLine.Parsing;
using System.CommandLine;
using System.Diagnostics;
using System.Reflection;
@ -66,70 +64,59 @@ class Program
Stopwatch TotalExecutionTime = Stopwatch.StartNew();
/* !! IMPORTANT !!
WARN:
This code uses system.commandline which is still in pre-release
/* WARN:
This code uses system.commandline
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
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 =>
Option<DirectoryInfo> ProjectDirectoryOption = new("--project","-p")
{
Description = "The directory of the project",
Required = false,
DefaultValueFactory = _ =>
{
if (!result.GetValueForOption(ProjectDirectoryOption)!.Exists)
{
result.ErrorMessage = $"Project directory {result.GetValueForOption(ProjectDirectoryOption)} does not exist.";
}
return new DirectoryInfo(Directory.GetCurrentDirectory());
}
);
};
// 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.
var rootCommand = new RootCommand("csSiteGen");
// TODO: Verify if the use of async in these functions is necessary
RootCommand rootCommand = new("csSiteGen");
// This creates the command for cleaning a projects output directory.
var cleanCommand = new Command("clean", "Clean the projects output directory");
cleanCommand.AddOption(ProjectDirectoryOption); // This command can use the project directory option we created earlier
cleanCommand.SetHandler(async (ProjectDirectory) =>
cleanCommand.Options.Add(ProjectDirectoryOption); // This command can use the project directory option we created earlier
cleanCommand.SetAction(parseResult =>
{
await Task.Run(() =>
{
Clean(ProjectDirectory);
});
},ProjectDirectoryOption);
Clean(parseResult.GetValue<DirectoryInfo>("--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.");
convertCommand.AddOption(ProjectDirectoryOption); // This command can use the project directory option
convertCommand.SetHandler(async (ProjectDirectory) =>
convertCommand.Options.Add(ProjectDirectoryOption); // This command can use the project directory option
convertCommand.SetAction(parseResult =>
{
await Task.Run(() =>
{
Convert(ProjectDirectory);
});
},ProjectDirectoryOption);
Convert(parseResult.GetValue<DirectoryInfo>("--project")!);
});
// Adding the commands to the root command makes them actually callable on the commandline
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);
rootCommand.Subcommands.Add(cleanCommand);
rootCommand.Subcommands.Add(convertCommand);
// Parse the commandline and immediately execute.
rootCommand.Parse(args).Invoke();
TotalExecutionTime.Stop();
Log.Information("TotalExecutionTime {time:000}ms", TotalExecutionTime.ElapsedMilliseconds);
@ -139,12 +126,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
// A better solution that checks the terminal value and sets this option should be added in the future.
// TODO: A better solution that checks the terminal value and sets this option should be added in the future.
AnsiConsole.Console.Profile.Capabilities.Ansi = true;
@ -211,7 +198,7 @@ class Program
return 0;
}
static int Clean(DirectoryInfo? ProjectDirectory)
static int Clean(DirectoryInfo ProjectDirectory)
{
Log.Information("Clean command was called, Beginning cleaning");
@ -283,15 +270,10 @@ 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"));
@ -299,6 +281,7 @@ 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

@ -3,42 +3,47 @@
<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>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<PublishSingleFile>True</PublishSingleFile>
<SelfContained>True</SelfContained>
<PublishTrimmed>True</PublishTrimmed>
<OutputPath>bin\$(Configuration)\</OutputPath>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<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>true</TreatWarningsAsErrors>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<DefineDebug>true</DefineDebug>
</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>