diff --git a/.env b/.env
index 76bcc5ba9..b3af88f32 100644
--- a/.env
+++ b/.env
@@ -1,3 +1,7 @@
+ARCHIVAL_GIT_REPOSITORY_DIRECTORY=archives
+ARCHIVAL_GIT_USER_NAME=FilterLists Archival
+ARCHIVAL_GIT_USER_EMAIL=noreply@filterlists.com
+
DIRECTORY_CONNECTION_STRING=Server=directory-db;Database=filterlists;User Id=filterlists;Password=filterlists;
DIRECTORY_DB_USER=filterlists
DIRECTORY_DB_PASSWORD=filterlists
diff --git a/services/archival/src/FilterLists.Archival.Api/Startup.cs b/services/archival/src/FilterLists.Archival.Api/Startup.cs
index 271dbb4f7..745257d05 100644
--- a/services/archival/src/FilterLists.Archival.Api/Startup.cs
+++ b/services/archival/src/FilterLists.Archival.Api/Startup.cs
@@ -1,16 +1,24 @@
using FilterLists.Archival.Application;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace FilterLists.Archival.Api
{
- public class Startup
+ internal class Startup
{
- public static void ConfigureServices(IServiceCollection services)
+ public Startup(IConfiguration configuration)
{
- services.AddApplicationServices();
+ Configuration = configuration;
+ }
+
+ public IConfiguration Configuration { get; }
+
+ public void ConfigureServices(IServiceCollection services)
+ {
+ services.AddApplicationServices(Configuration);
}
public static void Configure(IApplicationBuilder app, IWebHostEnvironment env)
diff --git a/services/archival/src/FilterLists.Archival.Application/ServiceCollectionExtension.cs b/services/archival/src/FilterLists.Archival.Application/ServiceCollectionExtension.cs
index 360942232..6cc9a52cb 100644
--- a/services/archival/src/FilterLists.Archival.Application/ServiceCollectionExtension.cs
+++ b/services/archival/src/FilterLists.Archival.Application/ServiceCollectionExtension.cs
@@ -1,15 +1,16 @@
using FilterLists.Archival.Infrastructure;
using MediatR;
+using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace FilterLists.Archival.Application
{
public static class ServiceCollectionExtension
{
- public static void AddApplicationServices(this IServiceCollection services)
+ public static void AddApplicationServices(this IServiceCollection services, IConfiguration configuration)
{
services.AddMediatR(typeof(ServiceCollectionExtension).Assembly);
- services.AddInfrastructureServices();
+ services.AddInfrastructureServices(configuration);
}
}
}
\ No newline at end of file
diff --git a/services/archival/src/FilterLists.Archival.Infrastructure/FilterLists.Archival.Infrastructure.csproj b/services/archival/src/FilterLists.Archival.Infrastructure/FilterLists.Archival.Infrastructure.csproj
index 747a00669..234e53157 100644
--- a/services/archival/src/FilterLists.Archival.Infrastructure/FilterLists.Archival.Infrastructure.csproj
+++ b/services/archival/src/FilterLists.Archival.Infrastructure/FilterLists.Archival.Infrastructure.csproj
@@ -25,11 +25,14 @@
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
diff --git a/services/archival/src/FilterLists.Archival.Infrastructure/Options/GitOptions.cs b/services/archival/src/FilterLists.Archival.Infrastructure/Options/GitOptions.cs
new file mode 100644
index 000000000..c1015ab9a
--- /dev/null
+++ b/services/archival/src/FilterLists.Archival.Infrastructure/Options/GitOptions.cs
@@ -0,0 +1,11 @@
+namespace FilterLists.Archival.Infrastructure.Options
+{
+ public class GitOptions
+ {
+ public const string Key = nameof(Key);
+
+ public string RepositoryDirectory { get; set; }
+ public string UserName { get; set; }
+ public string UserEmail { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/services/archival/src/FilterLists.Archival.Infrastructure/Persistence/GitFileArchiver.cs b/services/archival/src/FilterLists.Archival.Infrastructure/Persistence/GitFileArchiver.cs
new file mode 100644
index 000000000..59ed546cb
--- /dev/null
+++ b/services/archival/src/FilterLists.Archival.Infrastructure/Persistence/GitFileArchiver.cs
@@ -0,0 +1,42 @@
+using System;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using FilterLists.Archival.Infrastructure.Options;
+using LibGit2Sharp;
+using Microsoft.Extensions.Options;
+
+namespace FilterLists.Archival.Infrastructure.Persistence
+{
+ internal class GitFileArchiver : IArchiveFile
+ {
+ private readonly GitOptions _options;
+ private readonly IRepository _repository;
+
+ public GitFileArchiver(IOptions gitOptions, IRepository gitRepository)
+ {
+ _options = gitOptions.Value;
+ _repository = gitRepository;
+ }
+
+ public async Task ArchiveFileAsync(
+ Stream fileContents,
+ string fileName,
+ CancellationToken cancellationToken = default)
+ {
+ await using var output = File.OpenWrite(fileName);
+ await fileContents.CopyToAsync(output, cancellationToken);
+ if (!cancellationToken.IsCancellationRequested)
+ Commit(fileName);
+ }
+
+ private void Commit(string fileName)
+ {
+ Commands.Stage(_repository, fileName);
+ var utcNow = DateTime.UtcNow;
+ var signature = new Signature(_options.UserName, _options.UserEmail, utcNow);
+ var message = $"archive {fileName}";
+ _repository.Commit(message, signature, signature);
+ }
+ }
+}
\ No newline at end of file
diff --git a/services/archival/src/FilterLists.Archival.Infrastructure/Persistence/IArchiveFile.cs b/services/archival/src/FilterLists.Archival.Infrastructure/Persistence/IArchiveFile.cs
new file mode 100644
index 000000000..24642d736
--- /dev/null
+++ b/services/archival/src/FilterLists.Archival.Infrastructure/Persistence/IArchiveFile.cs
@@ -0,0 +1,11 @@
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace FilterLists.Archival.Infrastructure.Persistence
+{
+ public interface IArchiveFile
+ {
+ Task ArchiveFileAsync(Stream fileContents, string fileName, CancellationToken cancellationToken = default);
+ }
+}
\ No newline at end of file
diff --git a/services/archival/src/FilterLists.Archival.Infrastructure/Persistence/ServiceCollectionExtension.cs b/services/archival/src/FilterLists.Archival.Infrastructure/Persistence/ServiceCollectionExtension.cs
new file mode 100644
index 000000000..475d4dce4
--- /dev/null
+++ b/services/archival/src/FilterLists.Archival.Infrastructure/Persistence/ServiceCollectionExtension.cs
@@ -0,0 +1,25 @@
+using FilterLists.Archival.Infrastructure.Options;
+using LibGit2Sharp;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace FilterLists.Archival.Infrastructure.Persistence
+{
+ public static class ServiceCollectionExtension
+ {
+ internal static void AddGitServices(this IServiceCollection services, IConfiguration configuration)
+ {
+ services.Configure(configuration.GetSection(GitOptions.Key));
+ services.AddTransient(_ =>
+ {
+ var gitOptions = new GitOptions();
+ configuration.GetSection(GitOptions.Key).Bind(gitOptions);
+
+ if (!Repository.IsValid(gitOptions.RepositoryDirectory))
+ Repository.Init(gitOptions.RepositoryDirectory);
+
+ return new Repository(gitOptions.RepositoryDirectory);
+ });
+ }
+ }
+}
\ No newline at end of file
diff --git a/services/archival/src/FilterLists.Archival.Infrastructure/ServiceCollectionExtension.cs b/services/archival/src/FilterLists.Archival.Infrastructure/ServiceCollectionExtension.cs
index 4f7ffec47..a0a3ff86c 100644
--- a/services/archival/src/FilterLists.Archival.Infrastructure/ServiceCollectionExtension.cs
+++ b/services/archival/src/FilterLists.Archival.Infrastructure/ServiceCollectionExtension.cs
@@ -1,11 +1,18 @@
-using Microsoft.Extensions.DependencyInjection;
+using System;
+using FilterLists.Archival.Infrastructure.Persistence;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
namespace FilterLists.Archival.Infrastructure
{
public static class ServiceCollectionExtension
{
- public static void AddInfrastructureServices(this IServiceCollection services)
+ public static void AddInfrastructureServices(this IServiceCollection services, IConfiguration configuration)
{
+ _ = configuration ?? throw new ArgumentNullException(nameof(configuration));
+
+ services.AddGitServices(configuration);
+ services.AddTransient();
}
}
}
\ No newline at end of file