Skip to content

Commit 5769eb4

Browse files
authored
Fix LLM export on in-memory filesystems (#3656)
1 parent 5dbce0a commit 5769eb4

2 files changed

Lines changed: 54 additions & 11 deletions

File tree

src/Elastic.Markdown/Exporters/LlmMarkdownExporter.cs

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -54,27 +54,37 @@ public class LlmMarkdownExporter(bool branded = false) : IMarkdownExporter
5454

5555
public async ValueTask<bool> FinishExportAsync(IDirectoryInfo outputFolder, Cancel ctx)
5656
{
57+
var fs = outputFolder.FileSystem;
58+
if (!outputFolder.Exists)
59+
outputFolder.Create();
60+
5761
var outputDirectory = outputFolder.FullName;
58-
var zipPath = Path.Join(outputDirectory, "llm.zip");
62+
var zipPath = fs.Path.Join(outputDirectory, "llm.zip");
5963

6064
// Create the llms.txt file; omit Elastic boilerplate for branded builds
61-
var llmsTxt = Path.Join(outputDirectory, "llms.txt");
62-
await outputFolder.FileSystem.File.WriteAllTextAsync(llmsTxt, branded ? string.Empty : LlmsTxtTemplate, ctx);
63-
64-
using var zip = ZipFile.Open(zipPath, ZipArchiveMode.Create);
65-
var llmsTxtRelativePath = Path.GetRelativePath(outputDirectory, llmsTxt);
66-
_ = zip.CreateEntryFromFile(llmsTxt, llmsTxtRelativePath);
65+
var llmsTxt = fs.FileInfo.New(fs.Path.Join(outputDirectory, "llms.txt"));
66+
await fs.File.WriteAllTextAsync(llmsTxt.FullName, branded ? string.Empty : LlmsTxtTemplate, ctx);
6767

68-
var markdownFiles = Directory.GetFiles(outputDirectory, "*.md", SearchOption.AllDirectories);
68+
await using var zipStream = fs.File.Create(zipPath);
69+
using var zip = new ZipArchive(zipStream, ZipArchiveMode.Create);
70+
await AddFileAsync(zip, llmsTxt, llmsTxt.Name, ctx);
6971

70-
foreach (var file in markdownFiles)
72+
foreach (var file in outputFolder.EnumerateFiles("*.md", SearchOption.AllDirectories))
7173
{
72-
var relativePath = Path.GetRelativePath(outputDirectory, file);
73-
_ = zip.CreateEntryFromFile(file, relativePath);
74+
var relativePath = fs.Path.GetRelativePath(outputDirectory, file.FullName).Replace('\\', '/');
75+
await AddFileAsync(zip, file, relativePath, ctx);
7476
}
7577
return true;
7678
}
7779

80+
private static async Task AddFileAsync(ZipArchive archive, IFileInfo file, string entryName, Cancel ctx)
81+
{
82+
var entry = archive.CreateEntry(entryName, CompressionLevel.Optimal);
83+
await using var entryStream = entry.Open();
84+
await using var sourceStream = file.FileSystem.File.OpenRead(file.FullName);
85+
await sourceStream.CopyToAsync(entryStream, ctx);
86+
}
87+
7888
public async ValueTask<bool> ExportAsync(MarkdownExportFileContext fileContext, Cancel ctx)
7989
{
8090
var fs = fileContext.BuildContext.WriteFileSystem;
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Licensed to Elasticsearch B.V under one or more agreements.
2+
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
3+
// See the LICENSE file in the project root for more information
4+
5+
using System.IO.Abstractions.TestingHelpers;
6+
using System.IO.Compression;
7+
using AwesomeAssertions;
8+
using Elastic.Markdown.Exporters;
9+
10+
namespace Elastic.Markdown.Tests.Exporters;
11+
12+
public class LlmMarkdownExporterTests
13+
{
14+
[Fact]
15+
public async Task FinishExportAsync_InMemoryFileSystem_CreatesArchiveFromInMemoryFiles()
16+
{
17+
const string outputPath = "/repo/.artifacts/docs/html";
18+
var fileSystem = new MockFileSystem(new Dictionary<string, MockFileData>
19+
{
20+
[$"{outputPath}/guide/page.md"] = new("# Page")
21+
});
22+
var outputFolder = fileSystem.DirectoryInfo.New(outputPath);
23+
var exporter = new LlmMarkdownExporter();
24+
25+
var result = await exporter.FinishExportAsync(outputFolder, TestContext.Current.CancellationToken);
26+
27+
result.Should().BeTrue();
28+
fileSystem.File.Exists($"{outputPath}/llm.zip").Should().BeTrue();
29+
await using var zipStream = fileSystem.File.OpenRead($"{outputPath}/llm.zip");
30+
using var archive = new ZipArchive(zipStream, ZipArchiveMode.Read);
31+
archive.Entries.Select(entry => entry.FullName).Should().BeEquivalentTo("llms.txt", "guide/page.md");
32+
}
33+
}

0 commit comments

Comments
 (0)