Skip to content

Commit 6563c0e

Browse files
committed
WebsiteGenerator parallel file & directory delete
1 parent 74d810b commit 6563c0e

1 file changed

Lines changed: 47 additions & 27 deletions

File tree

src/Ditto/src/Website.cs

Lines changed: 47 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,7 @@ public async Task<Result<Unit, ResultErrors>> Generate(string sourcePath, string
2929
return Result.Error("Output path cannot be a system directory.");
3030
}
3131

32-
if (!Directory.Exists(outputPath)) {
33-
Directory.CreateDirectory(outputPath);
34-
}
32+
Directory.CreateDirectory(outputPath);
3533

3634
// load page files
3735
var pageFiles = pageFileLoader.LoadFiles();
@@ -40,19 +38,61 @@ public async Task<Result<Unit, ResultErrors>> Generate(string sourcePath, string
4038
return Result.Error($"No page files found in the source directory '{sourcePath}'.");
4139
}
4240

41+
var continuationErrors = new ResultErrors();
42+
43+
// delete any index.html files that aren't in the source
44+
var pageOutputPathIndex =
45+
new HashSet<string>(
46+
pageFiles.Select(x => x.OutputPath),
47+
StringComparer.OrdinalIgnoreCase);
48+
49+
var filesToDelete = new List<string>();
50+
51+
foreach (var file in Directory.EnumerateFiles(outputPath, "index.html", SearchOption.AllDirectories)) {
52+
var fullPath = Path.GetFullPath(file);
53+
if (!pageOutputPathIndex.Contains(fullPath)) {
54+
filesToDelete.Add(fullPath);
55+
}
56+
}
57+
58+
Parallel.ForEach(filesToDelete, file => {
59+
try {
60+
File.Delete(file);
61+
}
62+
catch (Exception ex) {
63+
continuationErrors.Add(Path.GetRelativePath(sourcePath, file), $"Failed to delete file '{file}': {ex.Message}");
64+
}
65+
});
66+
67+
// delete any empty directories
68+
var directoriesToDelete = new List<string>();
69+
foreach (var dir in Directory.GetDirectories(outputPath, "*", SearchOption.AllDirectories).OrderByDescending(x => x.Length)) {
70+
if (!Directory.EnumerateFileSystemEntries(dir).Any()) {
71+
directoriesToDelete.Add(dir);
72+
}
73+
}
74+
75+
Parallel.ForEach(directoriesToDelete, x => {
76+
try {
77+
Directory.Delete(x);
78+
}
79+
catch (Exception ex) {
80+
continuationErrors.Add(Path.GetRelativePath(sourcePath, x), $"Failed to delete directory '{x}': {ex.Message}");
81+
}
82+
});
83+
4384
// parse pages
4485
var pageTasks = pageFiles.Select(async pageFile => {
4586
using var input = new StreamReader(pageFile.InputPath);
4687
// using var stream = new FileStream(pageFile.InputPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite & FileShare.Delete);
4788
// using var input = new StreamReader(stream);
48-
var page = await pageParser.Parse(input, pageFile);
89+
var page = await pageParser.Parse(input, pageFile).ConfigureAwait(false);
4990
return (page, pageFile.InputPath, pageFile.OutputPath);
5091
});
5192

5293
var pageResults = await Task.WhenAll(pageTasks);
5394

5495
var pages = new List<(Page page, string outputPath)>();
55-
var continuationErrors = new ResultErrors();
5696

5797
foreach (var (page, inputPath, pageOutputPath) in pageResults) {
5898
if (page.TryGet(out var p)) {
@@ -65,39 +105,19 @@ public async Task<Result<Unit, ResultErrors>> Generate(string sourcePath, string
65105

66106
var pageCollections = PageCollectionFactory.Create(pages.Select(x => x.page));
67107

68-
// delete any index.html files that aren't in the source
69-
var pageOutputPathIndex =
70-
new HashSet<string>(
71-
pageFiles.Select(x => x.OutputPath),
72-
StringComparer.OrdinalIgnoreCase);
73-
74-
foreach (var file in Directory.EnumerateFiles(outputPath, "index.html", SearchOption.AllDirectories)) {
75-
var fullPath = Path.GetFullPath(file);
76-
if (!pageOutputPathIndex.Contains(fullPath)) {
77-
File.Delete(fullPath);
78-
}
79-
}
80-
81-
// delete any empty directories
82-
foreach (var dir in Directory.GetDirectories(outputPath, "*", SearchOption.AllDirectories).OrderByDescending(x => x.Length)) {
83-
if (!Directory.EnumerateFileSystemEntries(dir).Any()) {
84-
Directory.Delete(dir, false);
85-
}
86-
}
87-
88108
// render pages
89109
var pageRenderTasks = pages.Select(async pageTuple => {
90110
var (page, outputPath) = pageTuple;
91111
var outputDir = Path.GetDirectoryName(outputPath);
92112

93-
if (outputDir is not null && !Directory.Exists(outputDir)) {
113+
if (outputDir is not null) {
94114
Directory.CreateDirectory(outputDir);
95115
}
96116

97117
var renderedContent = await viewEngine.Render(
98118
page: page,
99119
siteConfig: siteConfig,
100-
collections: pageCollections);
120+
collections: pageCollections).ConfigureAwait(false);
101121

102122
using var writer = new StreamWriter(outputPath);
103123
await writer.WriteAsync(renderedContent);

0 commit comments

Comments
 (0)