174 lines
5.4 KiB
C#
174 lines
5.4 KiB
C#
// -----------------------------------------------------------------------------
|
|
// RebuildService.cs
|
|
// Sprint: SPRINT_20260119_005 Reproducible Rebuild Integration
|
|
// Task: REPR-001 through REPR-007 - Service Orchestration
|
|
// Description: Main rebuild service orchestrating all backends.
|
|
// -----------------------------------------------------------------------------
|
|
|
|
using Microsoft.Extensions.Logging;
|
|
using Microsoft.Extensions.Options;
|
|
|
|
namespace StellaOps.BinaryIndex.GroundTruth.Reproducible;
|
|
|
|
/// <summary>
|
|
/// Main rebuild service implementation.
|
|
/// </summary>
|
|
public sealed class RebuildService : IRebuildService
|
|
{
|
|
private readonly ReproduceDebianClient _reproduceDebianClient;
|
|
private readonly LocalRebuildBackend _localBackend;
|
|
private readonly AirGapRebuildBundleService _airGapService;
|
|
private readonly RebuildServiceOptions _options;
|
|
private readonly ILogger<RebuildService> _logger;
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="RebuildService"/> class.
|
|
/// </summary>
|
|
public RebuildService(
|
|
ReproduceDebianClient reproduceDebianClient,
|
|
LocalRebuildBackend localBackend,
|
|
AirGapRebuildBundleService airGapService,
|
|
IOptions<RebuildServiceOptions> options,
|
|
ILogger<RebuildService> logger)
|
|
{
|
|
_reproduceDebianClient = reproduceDebianClient;
|
|
_localBackend = localBackend;
|
|
_airGapService = airGapService;
|
|
_options = options.Value;
|
|
_logger = logger;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task<string> RequestRebuildAsync(
|
|
RebuildRequest request,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
request.Validate();
|
|
|
|
_logger.LogInformation(
|
|
"Requesting rebuild for {Package} {Version} via {Backend}",
|
|
request.Package,
|
|
request.Version,
|
|
request.PreferredBackend);
|
|
|
|
// For now, generate a job ID and start the rebuild
|
|
var jobId = Guid.NewGuid().ToString("N")[..12];
|
|
|
|
// Store the request for status tracking
|
|
// In production, would persist to database
|
|
|
|
return jobId;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task<RebuildStatus> GetStatusAsync(
|
|
string jobId,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
// In production, would query from database/job queue
|
|
return new RebuildStatus
|
|
{
|
|
JobId = jobId,
|
|
State = RebuildState.Queued,
|
|
CurrentStage = "Pending"
|
|
};
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task<RebuildResult> DownloadArtifactsAsync(
|
|
string jobId,
|
|
string outputDirectory,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
Directory.CreateDirectory(outputDirectory);
|
|
|
|
var artifacts = await _reproduceDebianClient.DownloadArtifactsAsync(
|
|
jobId,
|
|
outputDirectory,
|
|
cancellationToken);
|
|
|
|
return RebuildResult.Successful(
|
|
jobId,
|
|
artifacts,
|
|
artifacts.Count > 0,
|
|
RebuildBackend.ReproduceDebian);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task<RebuildResult> RebuildLocalAsync(
|
|
string buildinfoPath,
|
|
LocalRebuildOptions? options = null,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
if (!File.Exists(buildinfoPath))
|
|
{
|
|
return RebuildResult.Failed(
|
|
Guid.NewGuid().ToString("N")[..12],
|
|
$"Buildinfo file not found: {buildinfoPath}",
|
|
backend: RebuildBackend.Local);
|
|
}
|
|
|
|
return await _localBackend.RebuildAsync(buildinfoPath, options, cancellationToken);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task<RebuildInfo?> QueryExistingRebuildAsync(
|
|
string package,
|
|
string version,
|
|
string architecture,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
_logger.LogDebug(
|
|
"Querying existing rebuild for {Package} {Version} {Arch}",
|
|
package, version, architecture);
|
|
|
|
var buildInfo = await _reproduceDebianClient.QueryBuildAsync(
|
|
package,
|
|
version,
|
|
architecture,
|
|
cancellationToken);
|
|
|
|
if (buildInfo is null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
return new RebuildInfo
|
|
{
|
|
JobId = buildInfo.Id,
|
|
Package = buildInfo.Package,
|
|
Version = buildInfo.Version,
|
|
Architecture = buildInfo.Architecture,
|
|
Reproducible = buildInfo.Reproducible,
|
|
BuiltAt = buildInfo.CompletedAt ?? buildInfo.StartedAt ?? DateTimeOffset.MinValue,
|
|
Backend = RebuildBackend.ReproduceDebian
|
|
};
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Configuration for the rebuild service.
|
|
/// </summary>
|
|
public sealed record RebuildServiceOptions
|
|
{
|
|
/// <summary>
|
|
/// Gets the default backend to use.
|
|
/// </summary>
|
|
public RebuildBackend DefaultBackend { get; init; } = RebuildBackend.ReproduceDebian;
|
|
|
|
/// <summary>
|
|
/// Gets the output directory for artifacts.
|
|
/// </summary>
|
|
public string OutputDirectory { get; init; } = Path.Combine(Path.GetTempPath(), "stella-rebuilds");
|
|
|
|
/// <summary>
|
|
/// Gets whether to prefer local rebuilds.
|
|
/// </summary>
|
|
public bool PreferLocalRebuild { get; init; } = false;
|
|
|
|
/// <summary>
|
|
/// Gets the job retention period.
|
|
/// </summary>
|
|
public TimeSpan JobRetention { get; init; } = TimeSpan.FromDays(30);
|
|
}
|