Skip to content

Added Source Schema Settings to FAR Format #8501

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Aug 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/All.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -330,4 +330,4 @@
<Folder Name="/StrawberryShake/Tooling/test/">
<Project Path="StrawberryShake/Tooling/test/Configuration.Tests/StrawberryShake.Tools.Configuration.Tests.csproj" />
</Folder>
</Solution>
</Solution>
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,11 @@ public ImmutableArray<VariableValues> CreateVariableValueSets(

(next, current) = (current, next);
next.Clear();

if (current.Count == 0)
{
return [];
}
}

PooledArrayWriter? buffer = null;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Buffers;
using System.IO.Compression;

namespace HotChocolate.Fusion.Packaging;
Expand All @@ -6,15 +7,17 @@ internal sealed class ArchiveSession : IDisposable
{
private readonly Dictionary<string, FileEntry> _files = [];
private readonly ZipArchive _archive;
private readonly FusionArchiveReadOptions _readOptions;
private FusionArchiveMode _mode;
private bool _disposed;

public ArchiveSession(ZipArchive archive, FusionArchiveMode mode)
public ArchiveSession(ZipArchive archive, FusionArchiveMode mode, FusionArchiveReadOptions readOptions)
{
ArgumentNullException.ThrowIfNull(archive);

_archive = archive;
_mode = mode;
_readOptions = readOptions;
}

public bool HasUncommittedChanges
Expand All @@ -39,7 +42,7 @@ public IEnumerable<string> GetFiles()
return files;
}

public async Task<bool> ExistsAsync(string path, CancellationToken cancellationToken)
public async Task<bool> ExistsAsync(string path, FileKind kind, CancellationToken cancellationToken)
{
if (_files.TryGetValue(path, out var file))
{
Expand All @@ -49,12 +52,7 @@ public async Task<bool> ExistsAsync(string path, CancellationToken cancellationT
if (_mode is not FusionArchiveMode.Create && _archive.GetEntry(path) is { } entry)
{
file = FileEntry.Read(path);
#if NET10_0_OR_GREATER
await entry.ExtractToFileAsync(file.TempPath, cancellationToken);
#else
entry.ExtractToFile(file.TempPath);
await Task.CompletedTask;
#endif
await ExtractFileAsync(entry, file, GetAllowedSize(kind), cancellationToken);
_files.Add(path, file);
return true;
}
Expand All @@ -72,7 +70,7 @@ public bool Exists(string path)
return _mode is not FusionArchiveMode.Create && _archive.GetEntry(path) is not null;
}

public async Task<Stream> OpenReadAsync(string path, CancellationToken cancellationToken)
public async Task<Stream> OpenReadAsync(string path, FileKind kind, CancellationToken cancellationToken)
{
if (_files.TryGetValue(path, out var file))
{
Expand All @@ -87,12 +85,7 @@ public async Task<Stream> OpenReadAsync(string path, CancellationToken cancellat
if (_mode is not FusionArchiveMode.Create && _archive.GetEntry(path) is { } entry)
{
file = FileEntry.Read(path);
#if NET10_0_OR_GREATER
await entry.ExtractToFileAsync(file.TempPath, cancellationToken);
#else
entry.ExtractToFile(file.TempPath);
await Task.CompletedTask;
#endif
await ExtractFileAsync(entry, file, GetAllowedSize(kind), cancellationToken);
var stream = File.OpenRead(file.TempPath);
_files.Add(path, file);
return stream;
Expand Down Expand Up @@ -181,21 +174,66 @@ await _archive.CreateEntryFromFileAsync(
}
}

private static async Task ExtractFileAsync(
ZipArchiveEntry zipEntry,
FileEntry fileEntry,
int maxAllowedSize,
CancellationToken cancellationToken)
{
var buffer = ArrayPool<byte>.Shared.Rent(4096);
var consumed = 0;

await using var readStream = zipEntry.Open();
await using var writeStream = File.Open(fileEntry.TempPath, FileMode.Create, FileAccess.Write);

int read;
while ((read = await readStream.ReadAsync(buffer, cancellationToken)) > 0)
{
consumed += read;

if (consumed > maxAllowedSize)
{
throw new InvalidOperationException(
$"File is too large and exceeds the allowed size of {maxAllowedSize}.");
}

await writeStream.WriteAsync(buffer.AsMemory(0, read), cancellationToken);
}
}

private int GetAllowedSize(FileKind kind)
=> kind switch
{
FileKind.Schema
=> _readOptions.MaxAllowedSchemaSize,
FileKind.Manifest or FileKind.Settings or FileKind.Metadata or FileKind.Signature
=> _readOptions.MaxAllowedSettingsSize,
_ => throw new ArgumentOutOfRangeException(nameof(kind), kind, null)
};

public void Dispose()
{
if (_disposed)
{
return;
}

_disposed = true;
foreach (var file in _files.Values)
{
if (file.State is not FileState.Deleted)
if (file.State is not FileState.Deleted && File.Exists(file.TempPath))
{
File.Delete(file.TempPath);
try
{
File.Delete(file.TempPath);
}
catch
{
// ignore
}
}
}

_disposed = true;
}

private class FileEntry
Expand Down
10 changes: 10 additions & 0 deletions src/HotChocolate/Fusion-vnext/src/Fusion.Packaging/FileKind.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace HotChocolate.Fusion.Packaging;

internal enum FileKind
{
Schema,
Settings,
Manifest,
Metadata,
Signature
}
31 changes: 31 additions & 0 deletions src/HotChocolate/Fusion-vnext/src/Fusion.Packaging/FileNames.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ internal static class FileNames
private const string GatewaySchemaFormat = "gateway/{0}/gateway.graphqls";
private const string GatewaySettingsFormat = "gateway/{0}/gateway-settings.json";
private const string SourceSchemaFormat = "source-schemas/{0}/schema.graphqls";
private const string SourceSchemaSettingsFormat = "source-schemas/{0}/schema-settings.json";

public const string ArchiveMetadata = "archive-metadata.json";
public const string CompositionSettings = "composition-settings.json";
Expand All @@ -19,4 +20,34 @@ public static string GetGatewaySettingsPath(Version version)

public static string GetSourceSchemaPath(string schemaName)
=> string.Format(SourceSchemaFormat, schemaName);

public static string GetSourceSchemaSettingsPath(string schemaName)
=> string.Format(SourceSchemaSettingsFormat, schemaName);

public static FileKind GetFileKind(string fileName)
{
switch (Path.GetFileName(fileName))
{
case "gateway.graphqls":
case "schema.graphqls":
return FileKind.Schema;

case "schema-settings.json":
case "gateway-settings.json":
case "composition-settings.json":
return FileKind.Settings;

case "archive-metadata.json":
return FileKind.Metadata;

case "manifest.json":
return FileKind.Manifest;

case "signature.json":
return FileKind.Signature;

default:
return FileKind.Settings;
}
}
}
Loading
Loading