Skip to content

Commit

Permalink
Merge pull request #10 from smithy-lang/sphinx-config
Browse files Browse the repository at this point in the history
Support sphinx integration configuration
  • Loading branch information
JordonPhillips authored Nov 6, 2023
2 parents a1ee495 + 1261271 commit 7936c60
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public record DocSettings(ShapeId service, String format) {
* @param pluginSettings the {@code ObjectNode} to load settings from.
* @return loaded settings based on the given node.
*/
public static DocSettings from(ObjectNode pluginSettings) {
public static DocSettings fromNode(ObjectNode pluginSettings) {
return new DocSettings(
pluginSettings.expectStringMember("service").expectShapeId(),
pluginSettings.getStringMemberOrDefault("format", "sphinx-markdown")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,14 @@ public String getName() {
@Override
public void execute(PluginContext pluginContext) {
LOGGER.fine("Beginning documentation generation.");
DocSettings settings = DocSettings.from(pluginContext.getSettings());

CodegenDirector<DocWriter, DocIntegration, DocGenerationContext, DocSettings> runner
= new CodegenDirector<>();

runner.directedCodegen(new DirectedDocGen());
runner.integrationClass(DocIntegration.class);
runner.fileManifest(pluginContext.getFileManifest());
runner.model(getValidatedModel(pluginContext.getModel()).unwrap());
runner.settings(settings);
DocSettings settings = runner.settings(DocSettings.class, pluginContext.getSettings());
runner.service(settings.service());
runner.performDefaultCodegenTransforms();
runner.run();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import static software.amazon.smithy.docgen.core.DocgenUtils.normalizeNewlines;
import static software.amazon.smithy.docgen.core.DocgenUtils.runCommand;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.logging.Logger;
Expand All @@ -22,6 +23,9 @@
import software.amazon.smithy.docgen.core.sections.sphinx.RequirementsSection;
import software.amazon.smithy.docgen.core.sections.sphinx.WindowsMakeSection;
import software.amazon.smithy.docgen.core.writers.SphinxMarkdownWriter;
import software.amazon.smithy.model.node.Node;
import software.amazon.smithy.model.node.ObjectNode;
import software.amazon.smithy.model.node.StringNode;
import software.amazon.smithy.model.shapes.ServiceShape;
import software.amazon.smithy.utils.SmithyInternalApi;

Expand All @@ -47,6 +51,32 @@
* build the docs. Any dependencies here will be installed into the environment
* used to run {@code sphinx-build}.
* </ul>
*
* This integration supports several customization options. To see all those options,
* see {@link SphinxSettings}. These settings are configured similarly to the doc
* generation plugin settings. Below is an example {@code smithy-build.json} with
* sphinx project auto build disabled.
*
* <pre>{@code
* {
* "version": "1.0",
* "projections": {
* "sphinx-markdown": {
* "plugins": {
* "docgen": {
* "service": "com.example#DocumentedService",
* "format": "sphinx-markdown",
* "integrations": {
* "sphinx": {
* "autoBuild": false
* }
* }
* }
* }
* }
* }
* }
* }</pre>
*/
@SmithyInternalApi
public final class SphinxIntegration implements DocIntegration {
Expand All @@ -55,12 +85,19 @@ public final class SphinxIntegration implements DocIntegration {
private static final Logger LOGGER = Logger.getLogger(SphinxIntegration.class.getName());

// The default requirements needed to build the docs.
private static final List<String> REQUIREMENTS = List.of(
private static final List<String> BASE_REQUIREMENTS = List.of(
"Sphinx==7.2.6",
"myst-parser==2.0.0",
"linkify-it-py==2.0.2"
);

private SphinxSettings settings = SphinxSettings.fromNode(Node.objectNode());

@Override
public String name() {
return "sphinx";
}

@Override
public byte priority() {
// Run at the end so that any integration-generated changes can happen.
Expand All @@ -83,7 +120,6 @@ public void customize(DocGenerationContext context) {
));
return;
}
// TODO: add some way to disable project file generation
LOGGER.info("Generating Sphinx project files.");
writeRequirements(context);
writeConf(context);
Expand All @@ -93,8 +129,13 @@ public void customize(DocGenerationContext context) {

private void writeRequirements(DocGenerationContext context) {
context.writerDelegator().useFileWriter("requirements.txt", writer -> {
writer.pushState(new RequirementsSection(context, REQUIREMENTS));
REQUIREMENTS.forEach(writer::write);
// Merge base and configured requirements into a single immutable list
List<String> requirements = new ArrayList<>(BASE_REQUIREMENTS);
requirements.addAll(settings.extraDependencies());
requirements = List.copyOf(requirements);

writer.pushState(new RequirementsSection(context, requirements));
requirements.forEach(writer::write);
writer.popState();
});
}
Expand All @@ -114,10 +155,11 @@ private void writeConf(DocGenerationContext context) {
release = $2S
templates_path = ["_templates"]
html_static_path = ["_static"]
html_theme = "alabaster"
html_theme = $3S
""",
serviceSymbol.getName(),
service.getVersion());
service.getVersion(),
settings.theme());

if (context.docFormat().name().equals(MARKDOWN_FORMAT)) {
writer.write("""
Expand Down Expand Up @@ -209,6 +251,12 @@ private void writeMakefile(DocGenerationContext context) {
}

private void runSphinx(DocGenerationContext context) {
if (!settings.autoBuild()) {
LOGGER.info("Auto-build has been disabled. Skipping sphinx-build.");
logManualBuildInstructions(context);
return;
}

var baseDir = context.fileManifest().getBaseDir();

LOGGER.info("Flushing writers in preparation for sphinx-build.");
Expand Down Expand Up @@ -236,7 +284,7 @@ private void runSphinx(DocGenerationContext context) {
runCommand("./venv/bin/pip install -r requirements.txt", baseDir);

// Finally, run sphinx itself.
runCommand("./venv/bin/sphinx-build -M html content build", baseDir);
runCommand("./venv/bin/sphinx-build -M " + settings.format() + " content build", baseDir);

System.out.printf(normalizeNewlines("""
Successfully built HTML docs. They can be found in "%1$s".
Expand All @@ -247,21 +295,22 @@ private void runSphinx(DocGenerationContext context) {
environment docs for information on how to activate it: \
https://docs.python.org/3/library/venv.html#how-venvs-work
Once the environment is activated, run `make html` from "%3$s" to \
to build the docs, substituting html for whatever format you wish \
Once the environment is activated, run `make %4$s` from "%3$s" to \
to build the docs, substituting %4$s for whatever format you wish \
to build.
To build the docs without activating the virtual environment, simply \
run `./venv/bin/sphinx-build -M html content build` from "%3$s", \
similarly substituting html for your desired format.
run `./venv/bin/sphinx-build -M %4$s content build` from "%3$s", \
similarly substituting %4$s for your desired format.
See sphinx docs for other output formats you can choose: \
https://www.sphinx-doc.org/en/master/usage/builders/index.html
"""),
baseDir.resolve("build/html"),
baseDir.resolve("build/" + settings.format()),
baseDir.resolve("venv"),
baseDir
baseDir,
settings.format()
);
} catch (CodegenException e) {
LOGGER.warning("Unable to automatically build HTML docs: " + e);
Expand All @@ -279,13 +328,86 @@ private void logManualBuildInstructions(DocGenerationContext context) {
instead install them from your system package manager, or another \
source.
Once the dependencies are installed, run `make html` from \
Once the dependencies are installed, run `make %2$s` from \
"%1$s". Other output formats can also be built. See sphinx docs for \
other output formats: \
https://www.sphinx-doc.org/en/master/usage/builders/index.html
"""),
context.fileManifest().getBaseDir()
context.fileManifest().getBaseDir(),
settings.format()
);
}

/**
* Settings for sphinx projects, regardless of their intermediate format.
*
* <p>These settings can be set in the {@code smithy-build.json} file under the
* {@code sphinx} key of the doc generation plugin's {@code integrations} config.
* The following example shows a {@code smithy-build.json} configuration that sets
* the default sphinx output format to be dirhtml instead of html.
*
* <pre>{@code
* {
* "version": "1.0",
* "projections": {
* "sphinx-markdown": {
* "plugins": {
* "docgen": {
* "service": "com.example#DocumentedService",
* "format": "sphinx-markdown",
* "integrations": {
* "sphinx": {
* "format": "dirhtml"
* }
* }
* }
* }
* }
* }
* }
* }</pre>
*
* @param format The sphinx output format that will be built automatically during
* generation. The default is html. See
* <a href="https://www.sphinx-doc.org/en/master/usage/builders/index.html">
* sphinx docs</a> for other output format options.
* @param theme The sphinx html theme to use. The default is alabaster. If your
* chosen theme requires a python dependency to be added, use the
* {@link #extraDependencies} setting.
* @param extraDependencies Any extra python dependencies that should be added to
* the {@code requirements.txt} file for the sphinx project.
* These can be particularly useful for custom {@link #theme}s.
* @param autoBuild Whether to automatically attempt to build the generated sphinx
* project. The default is true. This will attempt to discover Python
* 3 on the path, create a virtual environment inside the output
* directory, install all the dependencies into that virtual environment,
* and finally run sphinx-build.
*/
public record SphinxSettings(
String format,
String theme,
List<String> extraDependencies,
boolean autoBuild
) {
/**
* Load the settings from an {@code ObjectNode}.
*
* @param node the {@code ObjectNode} to load settings from.
* @return loaded settings based on the given node.
*/
public static SphinxSettings fromNode(ObjectNode node) {
List<String> extraDependencies = List.of();
if (node.containsMember("extraDependencies")) {
var array = node.expectArrayMember("extraDependencies");
extraDependencies = array.getElementsAs(StringNode::getValue);
}
return new SphinxSettings(
node.getStringMemberOrDefault("format", "html"),
node.getStringMemberOrDefault("theme", "alabaster"),
extraDependencies,
node.getBooleanMemberOrDefault("autoBuild", true)
);
}
}
}

0 comments on commit 7936c60

Please sign in to comment.