feat(git-provider): Initial git registration storage in database

- update PostBuild.ps1 to not delete data directory created during debug
- move sqlite-net-pcl to ModuleCore
This commit is contained in:
Scott 2026-08-24 16:02:51 +10:00
commit 633b35f7e9
5 changed files with 95 additions and 14 deletions

View file

@ -1,4 +1,6 @@
namespace ModuleCore.Database; using SQLite;
namespace ModuleCore.Database;
public class DatabaseManager public class DatabaseManager
{ {
@ -16,8 +18,37 @@ public class DatabaseManager
_databaseLocation = new FileInfo(Path.Combine(".", "data", $"{SanitiseFilename(databaseName)}.db")); _databaseLocation = new FileInfo(Path.Combine(".", "data", $"{SanitiseFilename(databaseName)}.db"));
Directory.CreateDirectory(_databaseLocation.DirectoryName!); Directory.CreateDirectory(_databaseLocation.DirectoryName!);
var file = File.Create(_databaseLocation.FullName);
file.Close(); if (!File.Exists(_databaseLocation.FullName))
{
var file = File.Create(_databaseLocation.FullName);
file.Close();
}
}
public void InConnection(Action<SQLiteConnection> dbAction)
{
using var conn = new SQLiteConnection(_databaseLocation.FullName);
dbAction(conn);
}
public T InConnection<T>(Func<SQLiteConnection, T> dbAction)
{
using var conn = new SQLiteConnection(_databaseLocation.FullName);
return dbAction(conn);
}
/// <summary>
/// Returns a bool for the given query. Convenience method for <see cref="SQLiteConnection.ExecuteScalar"/>.
/// </summary>
/// <param name="query">A query starting with SELECT 1, optionally paramaterised with ?</param>
/// <param name="args">Parameter values</param>
/// <returns></returns>
public bool Exists(string query, params object[] args)
{
using var conn = new SQLiteConnection(_databaseLocation.FullName);
var exists = conn.ExecuteScalar<bool?>(query, args);
return exists ?? false;
} }
/// <summary> /// <summary>

View file

@ -2,6 +2,7 @@
using System.Diagnostics; using System.Diagnostics;
using ModuleCore.Database; using ModuleCore.Database;
using ModuleCore.Git.Models; using ModuleCore.Git.Models;
using SQLite;
namespace ModuleCore.Git; namespace ModuleCore.Git;
@ -18,6 +19,11 @@ public class GitManager
_registrations = new ConcurrentDictionary<string, InternalGitRegistration>(); _registrations = new ConcurrentDictionary<string, InternalGitRegistration>();
_db = new DatabaseManager("git.db"); _db = new DatabaseManager("git.db");
_db.InConnection(conn =>
{
conn.CreateTable<InternalGitRegistration>();
});
} }
public static GitManager Instance => GitManagerInstance.Value; public static GitManager Instance => GitManagerInstance.Value;
@ -40,16 +46,46 @@ public class GitManager
? new DirectoryInfo(absoluteRepositoryLocation).Name ? new DirectoryInfo(absoluteRepositoryLocation).Name
: registrationName; : registrationName;
if (_registrations.TryAdd(registrationName, new InternalGitRegistration var gitRegistration = new InternalGitRegistration
{
Name = registrationName,
Location = absoluteRepositoryLocation,
}))
{ {
return registrationName; Name = registrationName,
} Location = absoluteRepositoryLocation,
Id = Guid.CreateVersion7(),
};
throw new Exception($"Git repo already registered with the name {registrationName}"); return _db.InConnection<string>(conn =>
{
// Query if we already have a registration either by name or location.
// tbh this is a bit of a janky way to do exists when I have to pass the query in anyway, but I just didn't
// want to do null checks and a truthy check so I wrap it in a barely-valuable method.
var registrationExists = _db.Exists(
$"""
SELECT 1
FROM {InternalGitRegistration.TableName}
WHERE Name = ? OR
Location = ?
""",
gitRegistration.Name,
gitRegistration.Location
);
if (registrationExists)
{
throw new Exception($"A Git repo is already registered with the name {registrationName} or location {absoluteRepositoryLocation}");
}
// Insert the new record
conn.Insert(gitRegistration);
if (_registrations.TryAdd(registrationName, gitRegistration))
{
return registrationName;
}
// This error case should be unlikely, but if a registration was removed but the registrations wasn't updated
// correctly then we'd unable to re-add a repo with the same name
throw new Exception("An error occured during registration.");
});
} }
public List<GitRegistration> ListRepos() public List<GitRegistration> ListRepos()
@ -83,12 +119,22 @@ public class GitManager
/// <summary> /// <summary>
/// Used for internal git registration and handles getting the current branch /// Used for internal git registration and handles getting the current branch
/// </summary> /// </summary>
[Table(TableName)]
private class InternalGitRegistration private class InternalGitRegistration
{ {
private string _currentBranch = string.Empty; private string _currentBranch = string.Empty;
private long _nextCheckTime; private long _nextCheckTime;
public required string Name { get; set; } internal const string TableName = "GitRegistration";
public required string Location { get; set; }
[PrimaryKey]
public Guid Id { get; set; }
[Indexed(Unique = true)]
public string Name { get; set; } = null!;
[Indexed(Unique = true)]
public string Location { get; set; } = null!;
public string CurrentBranch => GetCurrentBranch(); public string CurrentBranch => GetCurrentBranch();
// TODO: not fully decided on if I want this feature or not, but keeping it in for now // TODO: not fully decided on if I want this feature or not, but keeping it in for now

View file

@ -13,4 +13,8 @@
</AssemblyAttribute> </AssemblyAttribute>
</ItemGroup> </ItemGroup>
<ItemGroup>
<PackageReference Include="sqlite-net-pcl" />
</ItemGroup>
</Project> </Project>

View file

@ -22,6 +22,7 @@ $allowList = @(
"ModuleCore*" "ModuleCore*"
"PowershellModule*" "PowershellModule*"
"*SQLite*" "*SQLite*"
"data"
) )
Write-Host "Removing all non-module required files from '$targetDir'" Write-Host "Removing all non-module required files from '$targetDir'"
Get-ChildItem -Path $targetDir -exclude $allowList | Remove-Item -Recurse Get-ChildItem -Path $targetDir -exclude $allowList | Remove-Item -Recurse

View file

@ -12,7 +12,6 @@
<PackageReference Include="PowerShellStandard.Library" > <PackageReference Include="PowerShellStandard.Library" >
<PrivateAssets>All</PrivateAssets> <PrivateAssets>All</PrivateAssets>
</PackageReference> </PackageReference>
<PackageReference Include="sqlite-net-pcl" />
<PackageReference Include="System.Management.Automation" /> <PackageReference Include="System.Management.Automation" />
</ItemGroup> </ItemGroup>