diff --git a/docs/source/_ext/rejoin.py b/docs/source/_ext/rejoin.py deleted file mode 100644 index afa760c43..000000000 --- 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 3d6448719..000000000 --- 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 f7da18f8b..000000000 --- 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 5347ebbda..000000000 --- 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 a8b2ce377..df0955b1c 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 c9721f6bf..f616d8770 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 ecee2e385..69e1053d1 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/src/Elastic.Markdown/IO/Paths.cs b/src/Elastic.Markdown/IO/Paths.cs index 8b630801c..3075ef061 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 524cfa826..d4ce66dfd 100644 --- a/src/Elastic.Markdown/Myst/InlineParsers/DiagnosticLinkInlineParser.cs +++ b/src/Elastic.Markdown/Myst/InlineParsers/DiagnosticLinkInlineParser.cs @@ -108,6 +108,10 @@ public override bool Match(InlineProcessor processor, ref StringSlice slice) if (url.EndsWith(".md")) 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}"; 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 35eef9f7d..88dd4b2a5 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/Http/DocumentationWebHost.cs b/src/docs-builder/Http/DocumentationWebHost.cs index c9537eacf..656e9bbc3 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/Program.cs b/src/docs-builder/Program.cs index e10c1d960..25d9d388c 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 d1788fbfc..6c455cc2e 100644 --- a/src/docs-builder/docs-builder.csproj +++ b/src/docs-builder/docs-builder.csproj @@ -33,4 +33,5 @@ + \ No newline at end of file diff --git a/src/docs-generator/Cli/Commands.cs b/src/docs-generator/Cli/Commands.cs index 924d1a41a..3f435da9e 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 feef603f5..dad7b9049 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() {