Skip to content

Commit d4cdc17

Browse files
authored
feat: Add CancellationToken support for RunBuild.Exec (#10185)
feat: add `CancellationToken` support for `RunBuild.Exec`
1 parent 02a052b commit d4cdc17

22 files changed

+186
-101
lines changed

src/Docfx.App/Helpers/DocumentBuilderWrapper.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ internal static class DocumentBuilderWrapper
1515
{
1616
private static readonly Assembly[] s_pluginAssemblies = LoadPluginAssemblies(AppContext.BaseDirectory).ToArray();
1717

18-
public static void BuildDocument(BuildJsonConfig config, BuildOptions options, TemplateManager templateManager, string baseDirectory, string outputDirectory, string templateDirectory)
18+
public static void BuildDocument(BuildJsonConfig config, BuildOptions options, TemplateManager templateManager, string baseDirectory, string outputDirectory, string templateDirectory, CancellationToken cancellationToken)
1919
{
2020
var postProcessorNames = config.PostProcessors.ToImmutableArray();
2121
var metadata = config.GlobalMetadata?.ToImmutableDictionary();
@@ -39,7 +39,7 @@ public static void BuildDocument(BuildJsonConfig config, BuildOptions options, T
3939
using var builder = new DocumentBuilder(s_pluginAssemblies.Concat(pluginAssemblies), postProcessorNames);
4040

4141
var parameters = ConfigToParameter(config, options, templateManager, baseDirectory, outputDirectory, templateDirectory);
42-
builder.Build(parameters, outputDirectory);
42+
builder.Build(parameters, outputDirectory, cancellationToken);
4343
}
4444

4545
private static IEnumerable<Assembly> LoadPluginAssemblies(string pluginDirectory)

src/Docfx.App/RunBuild.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ internal static class RunBuild
1616
/// <summary>
1717
/// Build document with specified settings.
1818
/// </summary>
19-
public static string Exec(BuildJsonConfig config, BuildOptions options, string configDirectory, string outputDirectory = null)
19+
public static string Exec(BuildJsonConfig config, BuildOptions options, string configDirectory, string outputDirectory = null, CancellationToken cancellationToken = default)
2020
{
2121
var stopwatch = Stopwatch.StartNew();
2222
if (config.Template == null || config.Template.Count == 0)
@@ -36,7 +36,7 @@ public static string Exec(BuildJsonConfig config, BuildOptions options, string c
3636
{
3737
var templateManager = new TemplateManager(config.Template, config.Theme, configDirectory);
3838

39-
DocumentBuilderWrapper.BuildDocument(config, options, templateManager, baseDirectory, outputFolder, null);
39+
DocumentBuilderWrapper.BuildDocument(config, options, templateManager, baseDirectory, outputFolder, null, cancellationToken);
4040

4141
templateManager.ProcessTheme(outputFolder, true);
4242
}

src/Docfx.Build/CompilePhaseHandler.cs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public void Handle(List<HostService> hostServices, int maxParallelism)
3939
_restructions.AddRange(hostService.TableOfContentRestructions);
4040
}
4141
}
42-
}, maxParallelism);
42+
}, maxParallelism, Context.CancellationToken);
4343

4444
DistributeTocRestructions(hostServices);
4545

@@ -49,7 +49,7 @@ public void Handle(List<HostService> hostServices, int maxParallelism)
4949
Build(hostService, maxParallelism);
5050
}
5151

52-
hostServices.RunAll(Postbuild, maxParallelism);
52+
hostServices.RunAll(Postbuild, maxParallelism, Context.CancellationToken);
5353
}
5454

5555
private void Prepare(List<HostService> hostServices, int maxParallelism)
@@ -66,7 +66,8 @@ private void Prepare(List<HostService> hostServices, int maxParallelism)
6666
{
6767
m.LocalPathFromRoot ??= StringExtension.ToDisplayPath(Path.Combine(m.BaseDir, m.File));
6868
},
69-
maxParallelism);
69+
maxParallelism,
70+
Context.CancellationToken);
7071
}
7172
}
7273

@@ -83,7 +84,7 @@ private void DistributeTocRestructions(List<HostService> hostServices)
8384
}
8485
}
8586

86-
private static void Prebuild(HostService hostService)
87+
private void Prebuild(HostService hostService)
8788
{
8889
RunBuildSteps(
8990
hostService.Processor.BuildSteps,
@@ -99,7 +100,7 @@ private static void Prebuild(HostService hostService)
99100
});
100101
}
101102

102-
private static void Build(HostService hostService, int maxParallelism)
103+
private void Build(HostService hostService, int maxParallelism)
103104
{
104105
hostService.Models.RunAll(
105106
m =>
@@ -124,10 +125,11 @@ private static void Build(HostService hostService, int maxParallelism)
124125
});
125126
}
126127
},
127-
maxParallelism);
128+
maxParallelism,
129+
Context.CancellationToken);
128130
}
129131

130-
private static void Postbuild(HostService hostService)
132+
private void Postbuild(HostService hostService)
131133
{
132134
hostService.Reload(hostService.Models);
133135

@@ -140,12 +142,14 @@ private static void Postbuild(HostService hostService)
140142
});
141143
}
142144

143-
private static void RunBuildSteps(IEnumerable<IDocumentBuildStep> buildSteps, Action<IDocumentBuildStep> action)
145+
private void RunBuildSteps(IEnumerable<IDocumentBuildStep> buildSteps, Action<IDocumentBuildStep> action)
144146
{
145147
if (buildSteps != null)
146148
{
147149
foreach (var buildStep in buildSteps.OrderBy(static step => step.BuildOrder))
148150
{
151+
Context.CancellationToken.ThrowIfCancellationRequested();
152+
149153
action(buildStep);
150154
}
151155
}

src/Docfx.Build/DocumentBuildContext.cs

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,7 @@ public sealed class DocumentBuildContext : IDocumentBuildContext
1616
private readonly ConcurrentDictionary<string, TocInfo> _tableOfContents = new(FilePathComparer.OSPlatformSensitiveStringComparer);
1717
private readonly Task<IXRefContainerReader> _reader;
1818

19-
public DocumentBuildContext(string buildOutputFolder)
20-
: this(buildOutputFolder, Enumerable.Empty<FileAndType>(), ImmutableArray<string>.Empty, ImmutableArray<string>.Empty, 1, Directory.GetCurrentDirectory(), string.Empty, null, null) { }
21-
22-
public DocumentBuildContext(string buildOutputFolder, IEnumerable<FileAndType> allSourceFiles, ImmutableArray<string> externalReferencePackages, ImmutableArray<string> xrefMaps, int maxParallelism, string baseFolder, string versionName, ApplyTemplateSettings applyTemplateSetting, string rootTocPath)
23-
: this(buildOutputFolder, allSourceFiles, externalReferencePackages, xrefMaps, maxParallelism, baseFolder, versionName, applyTemplateSetting, rootTocPath, null, null) { }
24-
25-
public DocumentBuildContext(DocumentBuildParameters parameters)
19+
public DocumentBuildContext(DocumentBuildParameters parameters, CancellationToken cancellationToken)
2620
{
2721
BuildOutputFolder = Path.Combine(Path.GetFullPath(EnvironmentContext.BaseDirectory), parameters.OutputBaseDir);
2822
VersionName = parameters.VersionName;
@@ -34,9 +28,10 @@ public DocumentBuildContext(DocumentBuildParameters parameters)
3428

3529
if (parameters.XRefMaps.Length > 0)
3630
{
31+
// Note: `_reader` task is processed asyncronously and await is called later. So OperationCancellationException is not thrown by this lines.
3732
_reader = new XRefCollection(
3833
from u in parameters.XRefMaps
39-
select new Uri(u, UriKind.RelativeOrAbsolute)).GetReaderAsync(parameters.Files.DefaultBaseDir, parameters.MarkdownEngineParameters?.FallbackFolders);
34+
select new Uri(u, UriKind.RelativeOrAbsolute)).GetReaderAsync(parameters.Files.DefaultBaseDir, parameters.MarkdownEngineParameters?.FallbackFolders, cancellationToken);
4035
}
4136
RootTocPath = parameters.RootTocPath;
4237

@@ -54,9 +49,18 @@ from u in parameters.XRefMaps
5449
}
5550
}
5651
VersionFolder = versionDir;
52+
CancellationToken = cancellationToken;
5753
}
5854

59-
public DocumentBuildContext(
55+
#region Constructors that used by test code.
56+
57+
internal DocumentBuildContext(string buildOutputFolder)
58+
: this(buildOutputFolder, Enumerable.Empty<FileAndType>(), ImmutableArray<string>.Empty, ImmutableArray<string>.Empty, 1, Directory.GetCurrentDirectory(), string.Empty, null, null) { }
59+
60+
private DocumentBuildContext(string buildOutputFolder, IEnumerable<FileAndType> allSourceFiles, ImmutableArray<string> externalReferencePackages, ImmutableArray<string> xrefMaps, int maxParallelism, string baseFolder, string versionName, ApplyTemplateSettings applyTemplateSetting, string rootTocPath)
61+
: this(buildOutputFolder, allSourceFiles, externalReferencePackages, xrefMaps, maxParallelism, baseFolder, versionName, applyTemplateSetting, rootTocPath, null, null) { }
62+
63+
private DocumentBuildContext(
6064
string buildOutputFolder,
6165
IEnumerable<FileAndType> allSourceFiles,
6266
ImmutableArray<string> externalReferencePackages,
@@ -98,6 +102,7 @@ from u in xrefMaps
98102
}
99103
VersionFolder = versionFolder;
100104
}
105+
#endregion
101106

102107
public string BuildOutputFolder { get; }
103108

@@ -129,6 +134,8 @@ from u in xrefMaps
129134

130135
public ICustomHrefGenerator HrefGenerator { get; }
131136

137+
public CancellationToken CancellationToken { get; } = CancellationToken.None;
138+
132139
internal ConcurrentBag<ManifestItem> ManifestItems { get; } = new();
133140

134141
private ConcurrentDictionary<string, XRefSpec> ExternalXRefSpec { get; } = new();
@@ -150,9 +157,10 @@ public void ReportExternalXRefSpec(XRefSpec spec)
150157

151158
public void ResolveExternalXRefSpec()
152159
{
153-
Task.WaitAll(
160+
Task.WaitAll([
154161
Task.Run(ResolveExternalXRefSpecForSpecs),
155-
Task.Run(ResolveExternalXRefSpecForNoneSpecsAsync));
162+
Task.Run(ResolveExternalXRefSpecForNoneSpecsAsync)
163+
], CancellationToken);
156164
}
157165

158166
private void ResolveExternalXRefSpecForSpecs()
@@ -205,7 +213,7 @@ private List<string> ResolveByExternalReferencePackages(List<string> uidList, Co
205213

206214
var oldSpecCount = externalXRefSpec.Count;
207215
var list = new List<string>();
208-
using (var externalReferences = new ExternalReferencePackageCollection(ExternalReferencePackages, MaxParallelism))
216+
using (var externalReferences = new ExternalReferencePackageCollection(ExternalReferencePackages, MaxParallelism, CancellationToken))
209217
{
210218
foreach (var uid in uidList)
211219
{
@@ -401,7 +409,7 @@ public XRefSpec GetXrefSpec(string uid)
401409

402410
if (ExternalReferencePackages.Length > 0)
403411
{
404-
using (var externalReferences = new ExternalReferencePackageCollection(ExternalReferencePackages, MaxParallelism))
412+
using (var externalReferences = new ExternalReferencePackageCollection(ExternalReferencePackages, MaxParallelism, CancellationToken))
405413
{
406414
xref = GetExternalReference(externalReferences, uid);
407415
}

src/Docfx.Build/DocumentBuilder.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,12 @@ public void Build(DocumentBuildParameters parameter)
3939
Build(new DocumentBuildParameters[] { parameter }, parameter.OutputBaseDir);
4040
}
4141

42-
public void Build(IList<DocumentBuildParameters> parameters, string outputDirectory)
42+
public void Build(IList<DocumentBuildParameters> parameters, string outputDirectory, CancellationToken cancellationToken = default)
4343
{
4444
ArgumentNullException.ThrowIfNull(parameters);
4545

46+
cancellationToken.ThrowIfCancellationRequested();
47+
4648
if (parameters.Count == 0)
4749
{
4850
throw new ArgumentException("Parameters are empty.", nameof(parameters));
@@ -119,7 +121,7 @@ public void Build(IList<DocumentBuildParameters> parameters, string outputDirect
119121
MetadataValidators = MetadataValidators.ToList(),
120122
Processors = Processors,
121123
};
122-
manifests.Add(builder.Build(parameter, markdownService));
124+
manifests.Add(builder.Build(parameter, markdownService, cancellationToken));
123125
}
124126
}
125127
if (noContentFound)

src/Docfx.Build/HostServiceCreator.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,9 @@ bool NeedApplyMetadata()
9797
{
9898
invalidFiles.Add(file.File);
9999
}
100-
}, _context.MaxParallelism);
100+
},
101+
_context.MaxParallelism,
102+
_context.CancellationToken);
101103

102104
return (models.OrderBy(m => m.File, StringComparer.Ordinal).ToArray(), invalidFiles);
103105
}

src/Docfx.Build/LinkPhaseHandler.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ private IEnumerable<ManifestItemWithContext> ExportManifest(HostService hostServ
7777
}
7878
}
7979
}
80-
});
80+
}, Context.CancellationToken);
8181
return manifestItems;
8282
}
8383

@@ -136,7 +136,7 @@ private void CheckFileLink(FileModel model, HostService hostService, SaveResult
136136
Logger.LogWarning($"Invalid file link:({fileLink}).", code: WarningCodes.Build.InvalidFileLink);
137137
}
138138
}
139-
});
139+
}, Context.CancellationToken);
140140
}
141141

142142
private void HandleUids(SaveResult result)

src/Docfx.Build/ManifestProcessor.cs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,8 @@ private void NormalizeToObject()
8787
}
8888
}
8989
},
90-
_context.MaxParallelism);
90+
_context.MaxParallelism,
91+
_context.CancellationToken);
9192
}
9293

9394
private void FeedOptions()
@@ -113,7 +114,8 @@ private void FeedOptions()
113114
}
114115
}
115116
},
116-
_context.MaxParallelism);
117+
_context.MaxParallelism,
118+
_context.CancellationToken);
117119
}
118120

119121
private void UpdateHref()
@@ -130,7 +132,8 @@ private void UpdateHref()
130132
m.Item.Content = m.FileModel.Content;
131133
}
132134
},
133-
_context.MaxParallelism);
135+
_context.MaxParallelism,
136+
_context.CancellationToken);
134137
}
135138

136139
private void ApplySystemMetadata()
@@ -171,7 +174,8 @@ private void ApplySystemMetadata()
171174
}
172175
}
173176
},
174-
_context.MaxParallelism);
177+
_context.MaxParallelism,
178+
_context.CancellationToken);
175179

176180
_globalMetadata["_shared"] = sharedObjects;
177181
}

src/Docfx.Build/PostProcessors/ExtractSearchIndex.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public ImmutableDictionary<string, object> PrepareMetadata(ImmutableDictionary<s
3737
return metadata;
3838
}
3939

40-
public Manifest Process(Manifest manifest, string outputFolder)
40+
public Manifest Process(Manifest manifest, string outputFolder, CancellationToken cancellationToken = default)
4141
{
4242
if (outputFolder == null)
4343
{
@@ -57,6 +57,8 @@ from output in item.Output
5757
Logger.LogInfo($"Extracting index data from {htmlFiles.Count} html files");
5858
foreach (var relativePath in htmlFiles)
5959
{
60+
cancellationToken.ThrowIfCancellationRequested();
61+
6062
var filePath = Path.Combine(outputFolder, relativePath);
6163
var html = new HtmlDocument();
6264
Logger.LogDiagnostic($"Extracting index data from {filePath}");

src/Docfx.Build/PostProcessors/HtmlPostProcessor.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public ImmutableDictionary<string, object> PrepareMetadata(ImmutableDictionary<s
3939
return metadata;
4040
}
4141

42-
public Manifest Process(Manifest manifest, string outputFolder)
42+
public Manifest Process(Manifest manifest, string outputFolder, CancellationToken cancellationToken = default)
4343
{
4444
ArgumentNullException.ThrowIfNull(manifest);
4545
ArgumentNullException.ThrowIfNull(outputFolder);
@@ -58,6 +58,8 @@ where output.Key.Equals(".html", StringComparison.OrdinalIgnoreCase)
5858
OutputFile = output.Value.RelativePath,
5959
})
6060
{
61+
cancellationToken.ThrowIfCancellationRequested();
62+
6163
if (!EnvironmentContext.FileAbstractLayer.Exists(tuple.OutputFile))
6264
{
6365
continue;

0 commit comments

Comments
 (0)