OPC # 0001: Extract OPC into standalone repo
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
using System.Formats.Tar;
|
||||
using System.IO.Compression;
|
||||
|
||||
namespace ControlPlane.Api.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a gzipped tar stream from a directory, respecting .dockerignore rules.
|
||||
/// Used to supply the Docker build context to the Docker SDK.
|
||||
/// </summary>
|
||||
internal static class TarHelper
|
||||
{
|
||||
private static readonly string[] DefaultIgnore =
|
||||
[
|
||||
".git", ".vs", ".vscode", "node_modules", "bin", "obj",
|
||||
"VaultData", "*.user", "*.suo",
|
||||
];
|
||||
|
||||
public static void Pack(string root, Stream destination)
|
||||
{
|
||||
var ignorePatterns = LoadDockerIgnore(root);
|
||||
|
||||
using var gz = new GZipStream(destination, CompressionLevel.Fastest, leaveOpen: true);
|
||||
using var tar = new TarWriter(gz, TarEntryFormat.Gnu, leaveOpen: false);
|
||||
|
||||
foreach (var file in Directory.EnumerateFiles(root, "*", SearchOption.AllDirectories))
|
||||
{
|
||||
var relative = Path.GetRelativePath(root, file).Replace('\\', '/');
|
||||
|
||||
if (ShouldIgnore(relative, ignorePatterns))
|
||||
continue;
|
||||
|
||||
var entry = new GnuTarEntry(TarEntryType.RegularFile, relative)
|
||||
{
|
||||
DataStream = File.OpenRead(file),
|
||||
};
|
||||
tar.WriteEntry(entry);
|
||||
}
|
||||
}
|
||||
|
||||
private static List<string> LoadDockerIgnore(string root)
|
||||
{
|
||||
var path = Path.Combine(root, ".dockerignore");
|
||||
var patterns = new List<string>(DefaultIgnore);
|
||||
if (!File.Exists(path)) return patterns;
|
||||
|
||||
foreach (var line in File.ReadAllLines(path))
|
||||
{
|
||||
var trimmed = line.Trim();
|
||||
if (!string.IsNullOrEmpty(trimmed) && !trimmed.StartsWith('#'))
|
||||
patterns.Add(trimmed);
|
||||
}
|
||||
return patterns;
|
||||
}
|
||||
|
||||
private static bool ShouldIgnore(string relativePath, List<string> patterns)
|
||||
{
|
||||
var segments = relativePath.Split('/');
|
||||
|
||||
foreach (var pattern in patterns)
|
||||
{
|
||||
var p = pattern.TrimStart('/').TrimEnd('/');
|
||||
|
||||
// Glob suffix match (e.g. *.user)
|
||||
if (p.StartsWith('*'))
|
||||
{
|
||||
if (relativePath.EndsWith(p[1..], StringComparison.OrdinalIgnoreCase))
|
||||
return true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Exact full-path match or root-anchored prefix (e.g. .git, .vs)
|
||||
if (relativePath.Equals(p, StringComparison.OrdinalIgnoreCase))
|
||||
return true;
|
||||
if (relativePath.StartsWith(p + "/", StringComparison.OrdinalIgnoreCase))
|
||||
return true;
|
||||
|
||||
// Match any path segment so that nested bin/, obj/, node_modules/ etc. are caught
|
||||
// regardless of which project subdirectory they live in.
|
||||
if (segments.Any(seg => seg.Equals(p, StringComparison.OrdinalIgnoreCase)))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user