From 536aa4cc948abc19bde1558b29fc07a3264ccc58 Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Tue, 10 Dec 2024 10:42:22 +0100 Subject: [PATCH 1/3] Ship static site resources as part of the assembly --- docs/source/_ext/rejoin.py | 48 --------------- docs/source/_templates/header.html | 8 --- .../_templates/partials/globaltoc-above.html | 59 ------------------- docs/source/_templates/versioning.html | 8 --- .../DocumentationGenerator.cs | 22 +++++++ src/Elastic.Markdown/Elastic.Markdown.csproj | 5 +- src/Elastic.Markdown/IO/DocumentationSet.cs | 1 - .../_static/atom-one-light.css | 0 .../_static/clipboard.min.js | 0 .../Elastic.Markdown}/_static/copybutton.css | 0 .../Elastic.Markdown}/_static/copybutton.js | 0 .../Elastic.Markdown}/_static/custom.css | 0 .../Elastic.Markdown}/_static/design-tabs.js | 0 .../Elastic.Markdown}/_static/doctools.js | 0 .../_static/documentation_options.js | 0 .../Elastic.Markdown}/_static/logo-dark.svg | 0 .../Elastic.Markdown}/_static/logo-light.svg | 0 .../Elastic.Markdown}/_static/mystnb.css | 0 .../Elastic.Markdown}/_static/print.css | 0 .../Elastic.Markdown}/_static/pygments.css | 0 .../Elastic.Markdown}/_static/shibuya.css | 0 .../Elastic.Markdown}/_static/shibuya.js | 0 .../_static/sphinx-design.min.css | 0 .../_static/sphinx_highlight.js | 0 .../_static/togglebutton.css | 0 .../Elastic.Markdown}/_static/togglebutton.js | 0 src/docs-builder/Cli/Commands.cs | 1 - src/docs-builder/Program.cs | 2 + src/docs-builder/docs-builder.csproj | 2 + 29 files changed, 30 insertions(+), 126 deletions(-) delete mode 100644 docs/source/_ext/rejoin.py delete mode 100644 docs/source/_templates/header.html delete mode 100644 docs/source/_templates/partials/globaltoc-above.html delete mode 100644 docs/source/_templates/versioning.html rename {docs/source => src/Elastic.Markdown}/_static/atom-one-light.css (100%) rename {docs/source => src/Elastic.Markdown}/_static/clipboard.min.js (100%) rename {docs/source => src/Elastic.Markdown}/_static/copybutton.css (100%) rename {docs/source => src/Elastic.Markdown}/_static/copybutton.js (100%) rename {docs/source => src/Elastic.Markdown}/_static/custom.css (100%) rename {docs/source => src/Elastic.Markdown}/_static/design-tabs.js (100%) rename {docs/source => src/Elastic.Markdown}/_static/doctools.js (100%) rename {docs/source => src/Elastic.Markdown}/_static/documentation_options.js (100%) rename {docs/source => src/Elastic.Markdown}/_static/logo-dark.svg (100%) rename {docs/source => src/Elastic.Markdown}/_static/logo-light.svg (100%) rename {docs/source => src/Elastic.Markdown}/_static/mystnb.css (100%) rename {docs/source => src/Elastic.Markdown}/_static/print.css (100%) rename {docs/source => src/Elastic.Markdown}/_static/pygments.css (100%) rename {docs/source => src/Elastic.Markdown}/_static/shibuya.css (100%) rename {docs/source => src/Elastic.Markdown}/_static/shibuya.js (100%) rename {docs/source => src/Elastic.Markdown}/_static/sphinx-design.min.css (100%) rename {docs/source => src/Elastic.Markdown}/_static/sphinx_highlight.js (100%) rename {docs/source => src/Elastic.Markdown}/_static/togglebutton.css (100%) rename {docs/source => src/Elastic.Markdown}/_static/togglebutton.js (100%) diff --git a/docs/source/_ext/rejoin.py b/docs/source/_ext/rejoin.py deleted file mode 100644 index afa760c..0000000 --- a/docs/source/_ext/rejoin.py +++ /dev/null @@ -1,48 +0,0 @@ -from __future__ import annotations -from docutils import nodes - -from sphinx.application import Sphinx -from sphinx.util.docutils import SphinxDirective, SphinxRole, directives -from sphinx.util.typing import ExtensionMetadata - -def rejoin_text(text: str, split_by: str, join_by: str) -> str: - return join_by.join(text.lower().split(split_by)) - -class RejoinRole(SphinxRole): - """A role to split by a string and rejoin by another string !""" - - def run(self) -> tuple[list[nodes.Node], list[nodes.system_message]]: - node = nodes.inline(text=rejoin_text(self.text, ' ', '-')) - return [node], [] - -class RejoinDirective(SphinxDirective): - """A directive to split by a string and rejoin by another string !""" - - required_arguments = 1 - has_content = True - FROM_OPTION = 'from' - TO_OPTION = 'to' - optional_arguments = 2 - option_spec = { - FROM_OPTION: directives.unchanged, - TO_OPTION: directives.unchanged - } - - def run(self) -> list[nodes.Node]: - label = self.arguments[0] - text = ''.join(self.content) - fr = self.options[self.FROM_OPTION] - to = self.options[self.TO_OPTION] - rejoined_text = rejoin_text(text, fr, to) - converted_text = f"{label} : {rejoined_text}" - paragraph_node = nodes.inline(text=converted_text) - return [paragraph_node] - -def setup(app: Sphinx) -> ExtensionMetadata: - app.add_role('rejoin', RejoinRole()) - app.add_directive('rejoin', RejoinDirective) - return { - 'version': '0.1', - 'parallel_read_safe': True, - 'parallel_write_safe': True, - } \ No newline at end of file diff --git a/docs/source/_templates/header.html b/docs/source/_templates/header.html deleted file mode 100644 index 3d64487..0000000 --- a/docs/source/_templates/header.html +++ /dev/null @@ -1,8 +0,0 @@ -{% extends "!header.html" %} - -{{ super() }} - -{% block extrahead %} -{# Included before the closing tag #} - -{% endblock %} diff --git a/docs/source/_templates/partials/globaltoc-above.html b/docs/source/_templates/partials/globaltoc-above.html deleted file mode 100644 index f7da18f..0000000 --- a/docs/source/_templates/partials/globaltoc-above.html +++ /dev/null @@ -1,59 +0,0 @@ -{% if versions %} - - -{% endif %} diff --git a/docs/source/_templates/versioning.html b/docs/source/_templates/versioning.html deleted file mode 100644 index 5347ebb..0000000 --- a/docs/source/_templates/versioning.html +++ /dev/null @@ -1,8 +0,0 @@ -{% if versions %} -

{{ _('Versions') }}

- -{% endif %} \ No newline at end of file diff --git a/src/Elastic.Markdown/DocumentationGenerator.cs b/src/Elastic.Markdown/DocumentationGenerator.cs index a8b2ce3..df0955b 100644 --- a/src/Elastic.Markdown/DocumentationGenerator.cs +++ b/src/Elastic.Markdown/DocumentationGenerator.cs @@ -2,6 +2,7 @@ // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. // See the LICENSE file in the project root for more information using System.IO.Abstractions; +using System.Reflection; using System.Text.Json; using System.Text.Json.Serialization; using Elastic.Markdown.IO; @@ -110,6 +111,27 @@ await Parallel.ForEachAsync(DocumentationSet.Files, ctx, async (file, token) => if (item % 1_000 == 0) _logger.LogInformation($"Handled {handledItems} files"); }); + + var embeddedStaticFiles = Assembly.GetExecutingAssembly() + .GetManifestResourceNames() + .ToList(); + foreach (var a in embeddedStaticFiles) + { + await using var resourceStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(a); + if (resourceStream == null) + continue; + + var path = a.Replace("Elastic.Markdown.", "").Replace("_static.", "_static/"); + + var outputFile = OutputFile(path); + if (outputFile.Directory is { Exists: false }) + outputFile.Directory.Create(); + await using var stream = outputFile.OpenWrite(); + await resourceStream.CopyToAsync(stream, ctx); + _logger.LogInformation($"Copied static embedded resource {path}"); + } + + Context.Collector.Channel.TryComplete(); await GenerateDocumentationState(ctx); diff --git a/src/Elastic.Markdown/Elastic.Markdown.csproj b/src/Elastic.Markdown/Elastic.Markdown.csproj index c9721f6..f616d87 100644 --- a/src/Elastic.Markdown/Elastic.Markdown.csproj +++ b/src/Elastic.Markdown/Elastic.Markdown.csproj @@ -26,5 +26,8 @@ - + + + + diff --git a/src/Elastic.Markdown/IO/DocumentationSet.cs b/src/Elastic.Markdown/IO/DocumentationSet.cs index ecee2e3..69e1053 100644 --- a/src/Elastic.Markdown/IO/DocumentationSet.cs +++ b/src/Elastic.Markdown/IO/DocumentationSet.cs @@ -47,7 +47,6 @@ public DocumentationSet(BuildContext context) ".md" => CreateMarkDownFile(file, context), _ => new StaticFile(file, SourcePath) }) - .ToList(); LastWrite = Files.Max(f => f.SourceFile.LastWriteTimeUtc); diff --git a/docs/source/_static/atom-one-light.css b/src/Elastic.Markdown/_static/atom-one-light.css similarity index 100% rename from docs/source/_static/atom-one-light.css rename to src/Elastic.Markdown/_static/atom-one-light.css diff --git a/docs/source/_static/clipboard.min.js b/src/Elastic.Markdown/_static/clipboard.min.js similarity index 100% rename from docs/source/_static/clipboard.min.js rename to src/Elastic.Markdown/_static/clipboard.min.js diff --git a/docs/source/_static/copybutton.css b/src/Elastic.Markdown/_static/copybutton.css similarity index 100% rename from docs/source/_static/copybutton.css rename to src/Elastic.Markdown/_static/copybutton.css diff --git a/docs/source/_static/copybutton.js b/src/Elastic.Markdown/_static/copybutton.js similarity index 100% rename from docs/source/_static/copybutton.js rename to src/Elastic.Markdown/_static/copybutton.js diff --git a/docs/source/_static/custom.css b/src/Elastic.Markdown/_static/custom.css similarity index 100% rename from docs/source/_static/custom.css rename to src/Elastic.Markdown/_static/custom.css diff --git a/docs/source/_static/design-tabs.js b/src/Elastic.Markdown/_static/design-tabs.js similarity index 100% rename from docs/source/_static/design-tabs.js rename to src/Elastic.Markdown/_static/design-tabs.js diff --git a/docs/source/_static/doctools.js b/src/Elastic.Markdown/_static/doctools.js similarity index 100% rename from docs/source/_static/doctools.js rename to src/Elastic.Markdown/_static/doctools.js diff --git a/docs/source/_static/documentation_options.js b/src/Elastic.Markdown/_static/documentation_options.js similarity index 100% rename from docs/source/_static/documentation_options.js rename to src/Elastic.Markdown/_static/documentation_options.js diff --git a/docs/source/_static/logo-dark.svg b/src/Elastic.Markdown/_static/logo-dark.svg similarity index 100% rename from docs/source/_static/logo-dark.svg rename to src/Elastic.Markdown/_static/logo-dark.svg diff --git a/docs/source/_static/logo-light.svg b/src/Elastic.Markdown/_static/logo-light.svg similarity index 100% rename from docs/source/_static/logo-light.svg rename to src/Elastic.Markdown/_static/logo-light.svg diff --git a/docs/source/_static/mystnb.css b/src/Elastic.Markdown/_static/mystnb.css similarity index 100% rename from docs/source/_static/mystnb.css rename to src/Elastic.Markdown/_static/mystnb.css diff --git a/docs/source/_static/print.css b/src/Elastic.Markdown/_static/print.css similarity index 100% rename from docs/source/_static/print.css rename to src/Elastic.Markdown/_static/print.css diff --git a/docs/source/_static/pygments.css b/src/Elastic.Markdown/_static/pygments.css similarity index 100% rename from docs/source/_static/pygments.css rename to src/Elastic.Markdown/_static/pygments.css diff --git a/docs/source/_static/shibuya.css b/src/Elastic.Markdown/_static/shibuya.css similarity index 100% rename from docs/source/_static/shibuya.css rename to src/Elastic.Markdown/_static/shibuya.css diff --git a/docs/source/_static/shibuya.js b/src/Elastic.Markdown/_static/shibuya.js similarity index 100% rename from docs/source/_static/shibuya.js rename to src/Elastic.Markdown/_static/shibuya.js diff --git a/docs/source/_static/sphinx-design.min.css b/src/Elastic.Markdown/_static/sphinx-design.min.css similarity index 100% rename from docs/source/_static/sphinx-design.min.css rename to src/Elastic.Markdown/_static/sphinx-design.min.css diff --git a/docs/source/_static/sphinx_highlight.js b/src/Elastic.Markdown/_static/sphinx_highlight.js similarity index 100% rename from docs/source/_static/sphinx_highlight.js rename to src/Elastic.Markdown/_static/sphinx_highlight.js diff --git a/docs/source/_static/togglebutton.css b/src/Elastic.Markdown/_static/togglebutton.css similarity index 100% rename from docs/source/_static/togglebutton.css rename to src/Elastic.Markdown/_static/togglebutton.css diff --git a/docs/source/_static/togglebutton.js b/src/Elastic.Markdown/_static/togglebutton.js similarity index 100% rename from docs/source/_static/togglebutton.js rename to src/Elastic.Markdown/_static/togglebutton.js diff --git a/src/docs-builder/Cli/Commands.cs b/src/docs-builder/Cli/Commands.cs index 35eef9f..88dd4b2 100644 --- a/src/docs-builder/Cli/Commands.cs +++ b/src/docs-builder/Cli/Commands.cs @@ -7,7 +7,6 @@ using Documentation.Builder.Diagnostics; using Documentation.Builder.Http; using Elastic.Markdown; -using Elastic.Markdown.Diagnostics; using Elastic.Markdown.IO; using Microsoft.Extensions.Logging; diff --git a/src/docs-builder/Program.cs b/src/docs-builder/Program.cs index e10c1d9..25d9d38 100644 --- a/src/docs-builder/Program.cs +++ b/src/docs-builder/Program.cs @@ -4,6 +4,7 @@ using Actions.Core.Extensions; using ConsoleAppFramework; +using Documentation.Builder; using Documentation.Builder.Cli; using Elastic.Markdown.Diagnostics; using Microsoft.Extensions.DependencyInjection; @@ -28,6 +29,7 @@ services.AddSingleton(); services.AddSingleton(); + await using var serviceProvider = services.BuildServiceProvider(); var logger = serviceProvider.GetRequiredService>(); ConsoleApp.ServiceProvider = serviceProvider; diff --git a/src/docs-builder/docs-builder.csproj b/src/docs-builder/docs-builder.csproj index d1788fb..945726a 100644 --- a/src/docs-builder/docs-builder.csproj +++ b/src/docs-builder/docs-builder.csproj @@ -28,9 +28,11 @@ + + \ No newline at end of file From 1ce03dc3a0942df16c248d181c34b430aaf9fceb Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Tue, 10 Dec 2024 13:42:40 +0100 Subject: [PATCH 2/3] Ensure we can serve static files either form disk or embedded into the assembly --- src/Elastic.Markdown/IO/Paths.cs | 9 ++++ .../DiagnosticLinkInlineParser.cs | 2 +- src/docs-builder/Http/DocumentationWebHost.cs | 54 +++++++++++++++++-- src/docs-builder/docs-builder.csproj | 1 - src/docs-generator/Cli/Commands.cs | 2 +- src/docs-generator/Domain/Generators.cs | 2 - 6 files changed, 62 insertions(+), 8 deletions(-) diff --git a/src/Elastic.Markdown/IO/Paths.cs b/src/Elastic.Markdown/IO/Paths.cs index 8b63080..3075ef0 100644 --- a/src/Elastic.Markdown/IO/Paths.cs +++ b/src/Elastic.Markdown/IO/Paths.cs @@ -15,4 +15,13 @@ private static DirectoryInfo RootDirectoryInfo() } public static readonly DirectoryInfo Root = RootDirectoryInfo(); + + /// Used in debug to locate static folder so we can change js/css files while the server is running + public static DirectoryInfo? GetSolutionDirectory() + { + var directory = new DirectoryInfo(Directory.GetCurrentDirectory()); + while (directory != null && directory.GetFiles("*.sln").Length == 0) + directory = directory.Parent; + return directory; + } } diff --git a/src/Elastic.Markdown/Myst/InlineParsers/DiagnosticLinkInlineParser.cs b/src/Elastic.Markdown/Myst/InlineParsers/DiagnosticLinkInlineParser.cs index 524cfa8..98d6a83 100644 --- a/src/Elastic.Markdown/Myst/InlineParsers/DiagnosticLinkInlineParser.cs +++ b/src/Elastic.Markdown/Myst/InlineParsers/DiagnosticLinkInlineParser.cs @@ -107,7 +107,7 @@ public override bool Match(InlineProcessor processor, ref StringSlice slice) } if (url.EndsWith(".md")) - link.Url = Path.ChangeExtension(url, ".html"); + link.Url = $"{processor.GetBuildContext().UrlPathPrefix}/{Path.ChangeExtension(url, ".html")}"; if (!string.IsNullOrEmpty(anchor)) link.Url += $"#{anchor}"; diff --git a/src/docs-builder/Http/DocumentationWebHost.cs b/src/docs-builder/Http/DocumentationWebHost.cs index c9537ea..656e9bb 100644 --- a/src/docs-builder/Http/DocumentationWebHost.cs +++ b/src/docs-builder/Http/DocumentationWebHost.cs @@ -10,9 +10,12 @@ using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.FileProviders; +using Microsoft.Extensions.FileProviders.Physical; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Primitives; using Westwind.AspNetCore.LiveReload; +using IFileInfo = Microsoft.Extensions.FileProviders.IFileInfo; namespace Documentation.Builder.Http; @@ -20,8 +23,7 @@ public class DocumentationWebHost { private readonly WebApplication _webApplication; - private readonly string _staticFilesDirectory = - Path.Combine(Paths.Root.FullName, "docs", "source", "_static"); + private readonly string _staticFilesDirectory; public DocumentationWebHost(string? path, ILoggerFactory logger, IFileSystem fileSystem) { @@ -40,6 +42,15 @@ public DocumentationWebHost(string? path, ILoggerFactory logger, IFileSystem fil builder.Services.AddSingleton(logger); builder.Logging.SetMinimumLevel(LogLevel.Warning); + _staticFilesDirectory = Path.Combine(context.SourcePath.FullName, "_static"); + #if DEBUG + // this attempts to serve files directly from their source rather than the embedded resourses during development. + // this allows us to change js/css files without restarting the webserver + var solutionRoot = Paths.GetSolutionDirectory(); + if (solutionRoot != null) + _staticFilesDirectory = Path.Combine(solutionRoot.FullName, "src", "Elastic.Markdown", "_static"); + #endif + _webApplication = builder.Build(); SetUpRoutes(); } @@ -52,7 +63,7 @@ private void SetUpRoutes() _webApplication.UseLiveReload(); _webApplication.UseStaticFiles(new StaticFileOptions { - FileProvider = new PhysicalFileProvider(_staticFilesDirectory), + FileProvider = new EmbeddedOrPhysicalFileProvider(_staticFilesDirectory), RequestPath = "/_static" }); _webApplication.UseRouting(); @@ -86,3 +97,40 @@ private static async Task ServeDocumentationFile(ReloadableGeneratorSta } } } + + +public class EmbeddedOrPhysicalFileProvider : IFileProvider +{ + private readonly EmbeddedFileProvider _embeddedProvider; + private readonly PhysicalFileProvider _fileProvider; + + public EmbeddedOrPhysicalFileProvider(string root) + { + _embeddedProvider = new EmbeddedFileProvider(typeof(BuildContext).Assembly, "Elastic.Markdown._static"); + _fileProvider = new PhysicalFileProvider(root); + } + + public IDirectoryContents GetDirectoryContents(string subpath) + { + var contents = _fileProvider.GetDirectoryContents(subpath); + if (!contents.Exists) + contents = _embeddedProvider.GetDirectoryContents(subpath); + return contents; + } + + public IFileInfo GetFileInfo(string subpath) + { + var fileInfo = _fileProvider.GetFileInfo(subpath.Replace("/_static", "")); + if (!fileInfo.Exists) + fileInfo = _embeddedProvider.GetFileInfo(subpath); + return fileInfo; + } + + public IChangeToken Watch(string filter) + { + var changeToken = _fileProvider.Watch(filter); + if (changeToken is NullChangeToken) + changeToken = _embeddedProvider.Watch(filter); + return changeToken; + } +} diff --git a/src/docs-builder/docs-builder.csproj b/src/docs-builder/docs-builder.csproj index 945726a..6c455cc 100644 --- a/src/docs-builder/docs-builder.csproj +++ b/src/docs-builder/docs-builder.csproj @@ -28,7 +28,6 @@ - diff --git a/src/docs-generator/Cli/Commands.cs b/src/docs-generator/Cli/Commands.cs index 924d1a4..3f435da 100644 --- a/src/docs-generator/Cli/Commands.cs +++ b/src/docs-generator/Cli/Commands.cs @@ -95,7 +95,7 @@ public async Task Generate( WriteMarkdownFile(outputFolder, file); } - var name = $"random-docset-{seedContent}-{seedFileSystem}"; + var name = $"random-docset-{Determinism.Random.SeedFileSystem}-{Determinism.Random.SeedFileSystem}"; WriteIndexMarkdownFile(name, outputFolder); var docset = Path.Combine(outputFolder.FullName, "docset.yml"); diff --git a/src/docs-generator/Domain/Generators.cs b/src/docs-generator/Domain/Generators.cs index feef603..dad7b90 100644 --- a/src/docs-generator/Domain/Generators.cs +++ b/src/docs-generator/Domain/Generators.cs @@ -2,7 +2,6 @@ // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. // See the LICENSE file in the project root for more information -using Slugify; using Soenneker.Utils.AutoBogus; namespace Documentation.Generator.Domain; @@ -12,7 +11,6 @@ public static class Generators public static AutoFaker FolderName { get; } = new(); public static AutoFaker
Section { get; } = new(); public static AutoFaker File { get; } = new(); - public static SlugHelper Slug { get; } = new(); static Generators() { From 3f6b3bbadcbfd50971085f3ffcfb115198cc4827 Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Tue, 10 Dec 2024 13:52:25 +0100 Subject: [PATCH 3/3] fix conditionally appending url path prefix --- .../Myst/InlineParsers/DiagnosticLinkInlineParser.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Elastic.Markdown/Myst/InlineParsers/DiagnosticLinkInlineParser.cs b/src/Elastic.Markdown/Myst/InlineParsers/DiagnosticLinkInlineParser.cs index 98d6a83..d4ce66d 100644 --- a/src/Elastic.Markdown/Myst/InlineParsers/DiagnosticLinkInlineParser.cs +++ b/src/Elastic.Markdown/Myst/InlineParsers/DiagnosticLinkInlineParser.cs @@ -107,7 +107,11 @@ public override bool Match(InlineProcessor processor, ref StringSlice slice) } if (url.EndsWith(".md")) - link.Url = $"{processor.GetBuildContext().UrlPathPrefix}/{Path.ChangeExtension(url, ".html")}"; + link.Url = Path.ChangeExtension(url, ".html"); + // rooted links might need the configured path prefix to properly link + var prefix = processor.GetBuildContext().UrlPathPrefix; + if (url.StartsWith("/") && !string.IsNullOrWhiteSpace(prefix)) + link.Url = $"{prefix}/{link.Url}"; if (!string.IsNullOrEmpty(anchor)) link.Url += $"#{anchor}";