feat: Add RustFS artifact object store and migration tool
- Implemented RustFsArtifactObjectStore for managing artifacts in RustFS. - Added unit tests for RustFsArtifactObjectStore functionality. - Created a RustFS migrator tool to transfer objects from S3 to RustFS. - Introduced policy preview and report models for API integration. - Added fixtures and tests for policy preview and report functionality. - Included necessary metadata and scripts for cache_pkg package.
This commit is contained in:
		@@ -0,0 +1,88 @@
 | 
			
		||||
using System.Globalization;
 | 
			
		||||
 | 
			
		||||
namespace StellaOps.Bench.ScannerAnalyzers.Baseline;
 | 
			
		||||
 | 
			
		||||
internal static class BaselineLoader
 | 
			
		||||
{
 | 
			
		||||
    public static async Task<IReadOnlyDictionary<string, BaselineEntry>> LoadAsync(string path, CancellationToken cancellationToken)
 | 
			
		||||
    {
 | 
			
		||||
        if (string.IsNullOrWhiteSpace(path))
 | 
			
		||||
        {
 | 
			
		||||
            throw new ArgumentException("Baseline path must be provided.", nameof(path));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var resolved = Path.GetFullPath(path);
 | 
			
		||||
        if (!File.Exists(resolved))
 | 
			
		||||
        {
 | 
			
		||||
            throw new FileNotFoundException($"Baseline file not found at {resolved}", resolved);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var result = new Dictionary<string, BaselineEntry>(StringComparer.OrdinalIgnoreCase);
 | 
			
		||||
 | 
			
		||||
        await using var stream = new FileStream(resolved, FileMode.Open, FileAccess.Read, FileShare.Read);
 | 
			
		||||
        using var reader = new StreamReader(stream);
 | 
			
		||||
        string? line;
 | 
			
		||||
        var isFirst = true;
 | 
			
		||||
 | 
			
		||||
        while ((line = await reader.ReadLineAsync().ConfigureAwait(false)) is not null)
 | 
			
		||||
        {
 | 
			
		||||
            cancellationToken.ThrowIfCancellationRequested();
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(line))
 | 
			
		||||
            {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (isFirst)
 | 
			
		||||
            {
 | 
			
		||||
                isFirst = false;
 | 
			
		||||
                if (line.StartsWith("scenario,", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
                {
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var entry = ParseLine(line);
 | 
			
		||||
            result[entry.ScenarioId] = entry;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static BaselineEntry ParseLine(string line)
 | 
			
		||||
    {
 | 
			
		||||
        var parts = line.Split(',', StringSplitOptions.TrimEntries);
 | 
			
		||||
        if (parts.Length < 6)
 | 
			
		||||
        {
 | 
			
		||||
            throw new InvalidDataException($"Baseline CSV row malformed: '{line}'");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var scenarioId = parts[0];
 | 
			
		||||
        var iterations = ParseInt(parts[1], nameof(BaselineEntry.Iterations));
 | 
			
		||||
        var sampleCount = ParseInt(parts[2], nameof(BaselineEntry.SampleCount));
 | 
			
		||||
        var meanMs = ParseDouble(parts[3], nameof(BaselineEntry.MeanMs));
 | 
			
		||||
        var p95Ms = ParseDouble(parts[4], nameof(BaselineEntry.P95Ms));
 | 
			
		||||
        var maxMs = ParseDouble(parts[5], nameof(BaselineEntry.MaxMs));
 | 
			
		||||
 | 
			
		||||
        return new BaselineEntry(scenarioId, iterations, sampleCount, meanMs, p95Ms, maxMs);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static int ParseInt(string value, string field)
 | 
			
		||||
    {
 | 
			
		||||
        if (!int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var parsed))
 | 
			
		||||
        {
 | 
			
		||||
            throw new InvalidDataException($"Failed to parse integer {field} from '{value}'.");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return parsed;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static double ParseDouble(string value, string field)
 | 
			
		||||
    {
 | 
			
		||||
        if (!double.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out var parsed))
 | 
			
		||||
        {
 | 
			
		||||
            throw new InvalidDataException($"Failed to parse double {field} from '{value}'.");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return parsed;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user