aboutsummaryrefslogtreecommitdiff
path: root/src/Constants
diff options
context:
space:
mode:
Diffstat (limited to 'src/Constants')
-rw-r--r--src/Constants/BuildConfig.cs77
-rw-r--r--src/Constants/BuildDirs.cs35
-rw-r--r--src/Constants/Config.cs95
-rw-r--r--src/Constants/ConfigManager.cs41
-rw-r--r--src/Constants/ConsoleCancelToken.cs29
-rw-r--r--src/Constants/Utils.cs151
6 files changed, 428 insertions, 0 deletions
diff --git a/src/Constants/BuildConfig.cs b/src/Constants/BuildConfig.cs
new file mode 100644
index 0000000..39758ea
--- /dev/null
+++ b/src/Constants/BuildConfig.cs
@@ -0,0 +1,77 @@
+using System.Text.Json.Serialization;
+
+using Semver;
+
+using VNLib.Tools.Build.Executor.Model;
+
+namespace VNLib.Tools.Build.Executor.Constants
+{
+ public sealed class BuildConfig
+ {
+ [JsonPropertyName("soure_file_extensions")]
+ public string[] SourceFileEx { get; set; } = [
+ "c",
+ "cpp",
+ "cxx",
+ "h",
+ "hpp",
+ "cs",
+ "proj",
+ "sln",
+ "ts",
+ "js",
+ "java",
+ "json",
+ "yaml",
+ "yml",
+ ];
+
+ [JsonPropertyName("excluded_dirs")]
+ public string[] ExcludedSourceDirs { get; set; } = [
+ "bin",
+ "obj",
+ "packages",
+ "node_modules",
+ "dist",
+ "build",
+ "out",
+ "target",
+ ];
+
+ [JsonPropertyName("default_sha_method")]
+ public string HashFuncName { get; set; } = "sha256";
+
+ [JsonPropertyName("head_file_name")]
+ public string HeadFileName { get; set; } = "@latest";
+
+ [JsonPropertyName("module_task_file_name")]
+ public string ModuleTaskFileName { get; set; } = "Module.Taskfile.yaml";
+
+ [JsonPropertyName("main_taskfile_name")]
+ public string MainTaskFileName { get; set; } = "build.taskfile.yaml";
+
+ [JsonPropertyName("output_file_type")]
+ public string OutputFileType { get; set; } = "*.tgz";
+
+ [JsonPropertyName("task_exe_name")]
+ public string TaskExeName { get; set; } = "task";
+
+ [JsonPropertyName("source_archive_name")]
+ public string SourceArchiveName { get; set; } = "archive.tgz";
+
+ [JsonPropertyName("source_archive_format")]
+ public string SourceArchiveFormat { get; set; } = "tgz";
+
+ [JsonPropertyName("project_bin_dir")]
+ public string ProjectBinDir { get; set; } = "bin";
+
+ [JsonPropertyName("default_ci_version")]
+ public string DefaultCiVersion { get; set; } = "0.1.0";
+
+ [JsonPropertyName("semver_style")]
+ public SemVersionStyles SemverStyle { get; set; }
+
+ [JsonIgnore]
+ public IDirectoryIndex Index { get; set; } = default!;
+ }
+} \ No newline at end of file
diff --git a/src/Constants/BuildDirs.cs b/src/Constants/BuildDirs.cs
new file mode 100644
index 0000000..78609f5
--- /dev/null
+++ b/src/Constants/BuildDirs.cs
@@ -0,0 +1,35 @@
+using System;
+using System.IO;
+
+namespace VNLib.Tools.Build.Executor.Constants
+{
+ internal static class BuildDirs
+ {
+
+ private static DirectoryInfo GetProjectDir()
+ {
+ //See if dir was specified on command line
+ string[] args = Environment.GetCommandLineArgs();
+
+ //Get the build dir
+ DirectoryInfo dir = new(args.Length > 1 && Directory.Exists(args[1]) ? args[1] : Directory.GetCurrentDirectory());
+
+ if (!dir.Exists)
+ {
+ dir.Create();
+ }
+ return dir;
+ }
+
+ public static DirectoryInfo GetOrCreateDir(string @default, string? other = null)
+ {
+ //Get the scratch dir
+ DirectoryInfo logDir = new(Path.Combine(GetProjectDir().FullName, other?? @default));
+ if (!logDir.Exists)
+ {
+ logDir.Create();
+ }
+ return logDir;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/Constants/Config.cs b/src/Constants/Config.cs
new file mode 100644
index 0000000..fc35928
--- /dev/null
+++ b/src/Constants/Config.cs
@@ -0,0 +1,95 @@
+using System;
+using System.IO;
+using System.Linq;
+
+using Serilog;
+using Serilog.Core;
+
+using VNLib.Tools.Build.Executor.Model;
+
+namespace VNLib.Tools.Build.Executor.Constants
+{
+
+ internal static class Config
+ {
+
+ //relative local directores to the project root
+ public const string BUILD_DIR_NAME = ".build";
+ public const string LOG_DIR_NAME = ".build/log";
+ public const string BUILD_CONFIG = "build.conf.json";
+ public const string SCRATCH_DIR = ".build/scratch";
+ public const string SUM_DIR = ".build/sums";
+ public const string OUTPUT_DIR = ".build/output";
+ public const string SLEET_DIR = ".build/feed";
+
+ /// <summary>
+ /// Gets the system wide <see cref="Logger"/> log writer instance
+ /// </summary>
+ public static Logger Log { get; } = GetLog();
+
+ const string Template = "{Message:lj}{NewLine}{Exception}";
+
+ private static Logger GetLog()
+ {
+ string[] args = Environment.GetCommandLineArgs();
+
+ LoggerConfiguration conf = new();
+
+ if (args.Contains("-v") || args.Contains("--verbose"))
+ {
+ //Check for verbose logging level
+ conf.MinimumLevel.Verbose();
+ }
+ else if (args.Contains("-d") || args.Contains("--debug"))
+ {
+ //Check for debug
+ conf.MinimumLevel.Debug();
+ }
+ else
+ {
+ //Default information level
+ conf.MinimumLevel.Information();
+ }
+
+ //Create a console logger unless the silent flag is set
+ if (!args.Contains("-s"))
+ {
+ conf.WriteTo.Console(outputTemplate: Template);
+ }
+
+ //Creat the new log file
+ string logFilePath = Path.Combine(LOG_DIR_NAME, $"{DateTimeOffset.Now.ToUnixTimeSeconds()}-log.txt");
+
+ //Setup the log file output
+ conf.WriteTo.File(logFilePath, outputTemplate: Template);
+
+ return conf.CreateLogger();
+ }
+
+ /// <summary>
+ /// Cleans up old build log files, so that only 100 log files remain in the log directory
+ /// </summary>
+ public static void TrimLogs(IDirectoryIndex dirIndex, int maxLogs)
+ {
+ try
+ {
+ //Get all log files in the log directory and cleanup any files after the max log count
+ FileInfo[] toDelete = dirIndex.LogDir.EnumerateFiles("*.txt", SearchOption.TopDirectoryOnly)
+ .OrderByDescending(static f => f.LastWriteTimeUtc)
+ .Skip(maxLogs)
+ .ToArray();
+
+ foreach (FileInfo file in toDelete)
+ {
+ file.Delete();
+ }
+
+ Log.Debug("Cleaned {file} log files", toDelete.Length);
+ }
+ catch (Exception ex)
+ {
+ Log.Warning(ex, "Failed to cleanup log files");
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/Constants/ConfigManager.cs b/src/Constants/ConfigManager.cs
new file mode 100644
index 0000000..3a0b295
--- /dev/null
+++ b/src/Constants/ConfigManager.cs
@@ -0,0 +1,41 @@
+using System.IO;
+using System.Text.Json;
+using System.Threading.Tasks;
+
+using Semver;
+
+using VNLib.Tools.Build.Executor.Model;
+
+namespace VNLib.Tools.Build.Executor.Constants
+{
+ public class ConfigManager(SemVersionStyles semver)
+ {
+ public async Task<BuildConfig> GetOrCreateConfig(IDirectoryIndex index, bool overwrite)
+ {
+ //Get the config file path
+ string configFilePath = Path.Combine(index.BuildDir.FullName, Config.BUILD_CONFIG);
+
+ BuildConfig? data = new()
+ {
+ SemverStyle = semver
+ };
+
+ //If the file doesnt exist or we want to overwrite it
+ if (!File.Exists(configFilePath) || overwrite)
+ {
+ //Create a new config file
+ await using FileStream fs = File.Create(configFilePath);
+ await JsonSerializer.SerializeAsync(fs, data);
+ }
+ else
+ {
+ await using FileStream fs = File.OpenRead(configFilePath);
+ data = await JsonSerializer.DeserializeAsync<BuildConfig>(fs);
+ }
+
+ data!.Index = index;
+
+ return data;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/Constants/ConsoleCancelToken.cs b/src/Constants/ConsoleCancelToken.cs
new file mode 100644
index 0000000..cc25feb
--- /dev/null
+++ b/src/Constants/ConsoleCancelToken.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Threading;
+
+namespace VNLib.Tools.Build.Executor.Constants
+{
+ internal sealed class ConsoleCancelToken : IDisposable
+ {
+ private readonly CancellationTokenSource _cts = new();
+
+ public CancellationToken Token => _cts.Token;
+
+ public ConsoleCancelToken() => Console.CancelKeyPress += OnCancel;
+
+ private void OnCancel(object? sender, ConsoleCancelEventArgs e)
+ {
+ _cts.Cancel();
+ e.Cancel = true;
+ }
+
+ public void Dispose()
+ {
+ //Unsubscribe from event
+ Console.CancelKeyPress -= OnCancel;
+ _cts.Dispose();
+
+ GC.SuppressFinalize(this);
+ }
+ }
+} \ No newline at end of file
diff --git a/src/Constants/Utils.cs b/src/Constants/Utils.cs
new file mode 100644
index 0000000..6047c35
--- /dev/null
+++ b/src/Constants/Utils.cs
@@ -0,0 +1,151 @@
+using System;
+using System.Threading;
+using System.Diagnostics;
+using System.Threading.Tasks;
+using System.Collections.Generic;
+using System.Runtime.CompilerServices;
+
+using static VNLib.Tools.Build.Executor.Constants.Config;
+
+namespace VNLib.Tools.Build.Executor.Constants
+{
+
+ internal static class Utils
+ {
+
+ /// <summary>
+ /// Runs a process by its name/exe file path, and writes its stdout/stderr to
+ /// the default build log
+ /// </summary>
+ /// <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)
+ {
+ //Init new console cancellation token
+ using ConsoleCancelToken ctToken = new();
+
+ ProcessStartInfo psi = new(process)
+ {
+ //Redirect streams
+ RedirectStandardError = true,
+ RedirectStandardOutput = true,
+ CreateNoWindow = true,
+ //Create a child process, not shell
+ UseShellExecute = false,
+ WorkingDirectory = workingDir ?? string.Empty,
+ };
+
+ if (env != null)
+ {
+ //Add all env variables to process
+ foreach (KeyValuePair<string, string> kv in env)
+ {
+ psi.Environment.Add(kv.Key, kv.Value);
+ }
+ }
+
+ //Add arguments
+ foreach (string arg in args)
+ {
+ psi.ArgumentList.Add(arg);
+ }
+
+ using Process proc = new();
+ proc.StartInfo = psi;
+
+ //Start the process
+ proc.Start();
+
+ Log.Debug("Starting process {proc}, with args {args}", proc.ProcessName, args);
+ Console.WriteLine();
+
+ //Log std out
+ Task stdout = LogStdOutAsync(proc, ctToken.Token);
+ Task stdErr = LogStdErrAsync(proc, ctToken.Token);
+
+ //Wait for the process to exit
+ Task wfe = proc.WaitForExitAsync(ctToken.Token);
+
+ //Wait for stderr/out/proc to exit
+ await Task.WhenAll(stdout, stdErr, wfe);
+
+ Console.WriteLine();
+ Log.Debug("[CHILD]:{id}:{p} exited w/ code {code}", proc.ProcessName, proc.Id, proc.ExitCode);
+
+ //Return status code
+ return proc.ExitCode;
+ }
+
+ private static async Task LogStdOutAsync(Process psi, CancellationToken cancellation)
+ {
+ try
+ {
+ string procName = psi.ProcessName;
+ int id = psi.Id;
+
+ do
+ {
+ //Read lines from the process
+ string? line = await psi.StandardOutput.ReadLineAsync(cancellation);
+
+ if (line == null)
+ {
+ break;
+ }
+
+ //Print to log file
+ Console.WriteLine(line);
+ } while (!psi.HasExited);
+ }
+ catch (Exception ex)
+ {
+ Log.Error(ex, "An exception was raised while reading the process standard output");
+ }
+ }
+
+ private static async Task LogStdErrAsync(Process psi, CancellationToken cancellation)
+ {
+ try
+ {
+ string procName = psi.ProcessName;
+ int id = psi.Id;
+
+ do
+ {
+ //Read lines from the process
+ string? line = await psi.StandardError.ReadLineAsync(cancellation);
+
+ if (line == null)
+ {
+ break;
+ }
+
+ //Print to log file
+ Console.WriteLine(line);
+ } while (!psi.HasExited);
+ }
+ catch (Exception ex)
+ {
+ Log.Error(ex, "An exception was raised while reading the process standard output");
+ }
+ }
+
+
+ /// <summary>
+ /// Throws a <see cref="BuildStepFailedException"/> if the value
+ /// of <paramref name="status"/> is false
+ /// </summary>
+ /// <param name="status">If false throws exception</param>
+ /// <param name="message">The message to display</param>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void ThrowIfStepFailed(bool status, string message, string artifactName)
+ {
+ if (!status)
+ {
+ throw new BuildStepFailedException(message, artifactName);
+ }
+ }
+
+ }
+} \ No newline at end of file