From ad88794506a0ccf0671dd9b909890e0a80b346cc Mon Sep 17 00:00:00 2001 From: Stanislaw Klekot Date: Mon, 30 Oct 2017 20:39:07 +0100 Subject: Add support for Sphinx documentation builder --- build.config | 1 + doc/src/guide/book.asciidoc | 2 + doc/src/guide/sphinx.asciidoc | 134 +++++++++++++++++++++++++++++++ plugins/sphinx.mk | 62 +++++++++++++++ test/plugin_sphinx.mk | 180 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 379 insertions(+) create mode 100644 doc/src/guide/sphinx.asciidoc create mode 100644 plugins/sphinx.mk create mode 100644 test/plugin_sphinx.mk diff --git a/build.config b/build.config index ae146ac..154a7ea 100644 --- a/build.config +++ b/build.config @@ -34,6 +34,7 @@ plugins/eunit plugins/proper plugins/relx plugins/shell +plugins/sphinx plugins/syntastic plugins/triq plugins/xref diff --git a/doc/src/guide/book.asciidoc b/doc/src/guide/book.asciidoc index 571d06d..085c147 100644 --- a/doc/src/guide/book.asciidoc +++ b/doc/src/guide/book.asciidoc @@ -41,6 +41,8 @@ include::asciidoc.asciidoc[Asciidoc documentation] include::edoc.asciidoc[EDoc comments] +include::sphinx.asciidoc[Sphinx documentation] + [[tests]] = Tests diff --git a/doc/src/guide/sphinx.asciidoc b/doc/src/guide/sphinx.asciidoc new file mode 100644 index 0000000..a20dee5 --- /dev/null +++ b/doc/src/guide/sphinx.asciidoc @@ -0,0 +1,134 @@ +[[sphinx]] +== Sphinx documentation + +Erlang.mk includes targets for running +http://www.sphinx-doc.org/[Sphinx documentation generator], which can produce +documentation in various formats, like HTML, man pages, Texinfo, LaTeX, and +others. + +=== Writing Sphinx documentation + +Sphinx generates documentation form a set of +http://www.sphinx-doc.org/en/stable/rest.html[reST] documents. There is +a http://www.sphinx-doc.org/en/stable/tutorial.html[quick start guide] on +Sphinx' website. For Erlang.mk, we'll set up a minimal environment instead. + +=== Basic setup + +By default, Erlang.mk expects Sphinx documentation to be placed in 'doc' +directory, with 'doc/conf.py' config file in particular. The file contains +information about the project, among the other things. + +A minimal 'doc/conf.py' will look similar to this: + +[source,python] +---- +project = 'My Project' +version = '0.0' +release = '0.0.1' +master_doc = 'index' +source_suffix = '.rst' +---- + +It points to a 'doc/index.rst' document. A simple skeleton includes a table of +contents for all documentation, and links to generated index of terms and +a search page: + +[literal] +---- +My Project +========== + +Contents: + +.. toctree:: + :maxdepth: 2 + + other_page + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`search` +---- + +The skeleton above has a link to one other page, 'doc/other_page.rst'. Simple +header with some text will do for now: + +[literal] +---- +Other Page +========== + +Lorem ipsum dolor sit amet... +---- + +The files above are enough to build HTML documentation to 'html' directory. + +[source,bash] +$ make docs # all the docs, including EDoc and AsciiDoc if applicable +$ make sphinx # Sphinx docs specifically + +=== Erlang.mk configuration + +Default Erlang.mk settings are equivalent to adding to project's makefile +following lines: + +[source,make] +SPHINX_FORMATS = html +SPHINX_SOURCE = doc + +To change the location of Sphinx sources, you need to set `$(SPHINX_SOURCE)` +variable. 'conf.py' file should also be placed in that directory, unless you +specify `$(SPHINX_CONFDIR)`. + +Variable `$(SPHINX_OPTS)` allows to provide options to `sphinx-build`, which +is particularly useful for `-D name=value` options. You can even forego +'doc/conf.py' file, using `-D name=value` in combination with `-C` option, +though you will need to manually call `make sphinx` or add `sphinx` target to +dependencies of `docs`. + +`$(SPHINX_FORMATS)` variable lists formats to generate. By default only HTML +is generated, but it can also include man pages or LaTeX document for building +PDF. See +http://www.sphinx-doc.org/en/stable/invocation.html#cmdoption-sphinx-build-b[description of `-b` option] +for `sphinx-build` for list of known formats. + +Formats are by default generated to a directory called after the format +('html' for HTML, 'man' for man pages, and so on). To change this behaviour +for specific format, you can set `$(sphinx_$(format)_output)` variable, e.g. +`$(sphinx_html_output)` for 'html' or `$(sphinx_man_output)` for 'man'. +There are also `$(sphinx_$(format)_opts)` variables for setting `sphinx-build` +options for a single format only. + +=== Generating man pages + +To generate man pages, you need to include `man` in `$(SPHINX_FORMATS)` in +your makefile and define `man_pages` option in 'doc/conf.py': + +[source,python] +---- +man_pages = [ + ('doc_name', 'page_name', 'Manpage Title', ['Page Author'], 1), +] +---- + +As http://www.sphinx-doc.org/en/stable/config.html#options-for-manual-page-output[Sphinx documentation] +says, the structure is following: + +* 'doc_name' is the path to man page's source (relative `$(SPHINX_SOURCE)`), + without the '.rst' suffix +* 'page_name' is the name of resulting man page, which will be used as a base + for output file name and will be included in generated man page +* 'Manpage Title' is a short, one-line description, which will be included in + generated man page on a position that's used by `apropos` command +* 'Page Author' (or more of them) will be included in autogenerated 'AUTHOR' + section, and leaving this field empty disables generating 'AUTHOR' section +* '1' is the number of section of the man page + +With the above configuration (and Erlang.mk defaults), 'doc/doc_name.rst' will +be used to generate 'man/page_name.1'. + +NOTE: You probably want to include a link to the man page in other +documentation, possibly in 'doc/index.rst'. diff --git a/plugins/sphinx.mk b/plugins/sphinx.mk new file mode 100644 index 0000000..4718247 --- /dev/null +++ b/plugins/sphinx.mk @@ -0,0 +1,62 @@ +# Copyright 2017, Stanislaw Klekot +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-sphinx sphinx + +# Configuration. + +SPHINX_BUILD ?= sphinx-build +SPHINX_SOURCE ?= doc +SPHINX_CONFDIR ?= +SPHINX_FORMATS ?= html +SPHINX_DOCTREES ?= $(ERLANG_MK_TMP)/sphinx.doctrees +SPHINX_OPTS ?= + +#sphinx_html_opts = +#sphinx_html_output = html +#sphinx_man_opts = +#sphinx_man_output = man +#sphinx_latex_opts = +#sphinx_latex_output = latex + +# Helpers. + +sphinx_build_0 = @echo " SPHINX" $1; $(SPHINX_BUILD) -N -q +sphinx_build_1 = $(SPHINX_BUILD) -N +sphinx_build_2 = set -x; $(SPHINX_BUILD) +sphinx_build = $(sphinx_build_$(V)) + +define sphinx.build +$(call sphinx_build,$1) -b $1 -d $(SPHINX_DOCTREES) $(if $(SPHINX_CONFDIR),-c $(SPHINX_CONFDIR)) $(SPHINX_OPTS) $(sphinx_$1_opts) -- $(SPHINX_SOURCE) $(call sphinx.output,$1) + +endef + +define sphinx.output +$(if $(sphinx_$1_output),$(sphinx_$1_output),$1) +endef + +# Targets. + +ifneq ($(wildcard $(if $(SPHINX_CONFDIR),$(SPHINX_CONFDIR),$(SPHINX_SOURCE))/conf.py),) +docs:: sphinx +distclean:: distclean-sphinx +endif + +help:: + $(verbose) printf "%s\n" "" \ + "Sphinx targets:" \ + " sphinx Generate Sphinx documentation." \ + "" \ + "ReST sources and 'conf.py' file are expected in directory pointed by" \ + "SPHINX_SOURCE ('doc' by default). SPHINX_FORMATS lists formats to build (only" \ + "'html' format is generated by default); target directory can be specified by" \ + 'setting sphinx_$${format}_output, for example: sphinx_html_output = output/html' \ + "Additional Sphinx options can be set in SPHINX_OPTS." + +# Plugin-specific targets. + +sphinx: + $(foreach F,$(SPHINX_FORMATS),$(call sphinx.build,$F)) + +distclean-sphinx: + $(gen_verbose) rm -rf $(filter-out $(SPHINX_SOURCE),$(foreach F,$(SPHINX_FORMATS),$(call sphinx.output,$F))) diff --git a/test/plugin_sphinx.mk b/test/plugin_sphinx.mk new file mode 100644 index 0000000..a31475a --- /dev/null +++ b/test/plugin_sphinx.mk @@ -0,0 +1,180 @@ +# Sphinx plugin. + +SPHINX_CASES = build source-dir formats format-opts +SPHINX_TARGETS = $(addprefix sphinx-,$(SPHINX_CASES)) + +.PHONY: sphinx $(SPHINX_TARGETS) + +sphinx: $(SPHINX_TARGETS) + +sphinx-build: build clean + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Generate Sphinx config" + $(call sphinx-generate-doc-skeleton) + + $i "Run Sphinx" + $t $(MAKE) -C $(APP) sphinx $v + + $i "Check that documentation was generated" + $t test -f $(APP)/html/index.html + $t test -f $(APP)/html/manpage.html + + $i "Distclean the application" + $t $(MAKE) -C $(APP) distclean $v + + $i "Check that the generated documentation was removed" + $t test ! -e $(APP)/html/index.html + $t test ! -e $(APP)/html/manpage.html + + $i "Set 'today' macro with command-line options" + $t echo "SPHINX_OPTS = -D 'today=erlang_mk_sphinx_today'" >> $(APP)/Makefile + + $i "Run Sphinx" + $t $(MAKE) -C $(APP) sphinx $v + + $i "Check that the 'today' macro was defined" + $t grep -q erlang_mk_sphinx_today $(APP)/html/manpage.html + +sphinx-source-dir: build clean + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Change documentation source directory" + $t echo "SPHINX_SOURCE = documentation" >> $(APP)/Makefile + + $i "Generate Sphinx config" + $(call sphinx-generate-doc-skeleton,documentation) + + $i "Run Sphinx (html)" + $t $(MAKE) -C $(APP) sphinx $v + + $i "Check that documentation was generated" + $t test -f $(APP)/html/index.html + $t test -f $(APP)/html/manpage.html + +sphinx-formats: build clean + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Define formats generated by Sphinx" + $t echo "SPHINX_FORMATS = html man" >> $(APP)/Makefile + + $i "Generate Sphinx config" + $(call sphinx-generate-doc-skeleton) + + $i "Run Sphinx (html + man)" + $t $(MAKE) -C $(APP) sphinx $v + + $i "Check that documentation was generated" + $t test -f $(APP)/man/sphinx_$(APP).1 + $t test -f $(APP)/html/index.html + $t test -f $(APP)/html/manpage.html + + $i "Distclean the application" + $t $(MAKE) -C $(APP) distclean $v + + $i "Check that the generated documentation was removed" + $t test ! -e $(APP)/man/sphinx_$(APP).1 + $t test ! -e $(APP)/html/index.html + $t test ! -e $(APP)/html/manpage.html + + $i "Change documentation output directories" + $t echo "sphinx_html_output = sphinx/html_output" >> $(APP)/Makefile + $t echo "sphinx_man_output = sphinx/man_output" >> $(APP)/Makefile + + $i "Run Sphinx (html + man)" + $t $(MAKE) -C $(APP) sphinx $v + + $i "Check that documentation was generated" + $t test -f $(APP)/sphinx/man_output/sphinx_$(APP).1 + $t test -f $(APP)/sphinx/html_output/index.html + $t test -f $(APP)/sphinx/html_output/manpage.html + + $i "Distclean the application" + $t $(MAKE) -C $(APP) distclean $v + + $i "Check that the generated documentation was removed" + $t test ! -e $(APP)/sphinx/man_output/sphinx_$(APP).1 + $t test ! -e $(APP)/sphinx/html_output/index.html + $t test ! -e $(APP)/sphinx/html_output/manpage.html + +sphinx-format-opts: build clean + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Define formats generated by Sphinx" + $t echo "SPHINX_FORMATS = html man" >> $(APP)/Makefile + + $i "Change format-specific options" + $t echo "sphinx_html_opts = -D 'today=erlang_mk_sphinx_html_today'" >> $(APP)/Makefile + $t echo "sphinx_man_opts = -D 'today=erlang_mk_sphinx_man_today'" >> $(APP)/Makefile + + $i "Generate Sphinx config" + $(call sphinx-generate-doc-skeleton) + + $i "Run Sphinx (html + man)" + $t $(MAKE) -C $(APP) sphinx $v + + $i "Check that the 'today' macro was defined correctly" + $t grep -q erlang_mk_sphinx_html_today $(APP)/html/manpage.html + $t grep -q erlang_mk_sphinx_man_today $(APP)/man/sphinx_$(APP).1 + + +define sphinx-generate-doc-skeleton +$t mkdir $(APP)/$(if $1,$1,doc)/ +$t printf "%s\n" \ + "project = '$(APP)'" \ + "master_doc = 'index'" \ + "source_suffix = '.rst'" \ + "man_pages = [('manpage', 'sphinx_$(APP)', 'Man Page', [], 1)]" \ + "" > $(APP)/$(if $1,$1,doc)/conf.py + +$t printf "%s\n" \ + "***********" \ + "Sphinx Docs" \ + "***********" \ + "" \ + "ToC" \ + "===" \ + "" \ + ".. toctree::" \ + "" \ + " manpage" \ + "" \ + "Indices" \ + "=======" \ + "" \ + '* :ref:`genindex`' \ + '* :ref:`modindex`' \ + '* :ref:`search`' \ + "" > $(APP)/$(if $1,$1,doc)/index.rst + +$t printf "%s\n" \ + "********" \ + "Man Page" \ + "********" \ + "" \ + "Synopsis" \ + "========" \ + "" \ + ".. code-block:: none" \ + "" \ + " erlang-sphinx-mk-man [--help]" \ + "" \ + "today = |today|" \ + "" > $(APP)/$(if $1,$1,doc)/manpage.rst +endef -- cgit v1.2.3