diff --git a/default.nix b/default.nix index bdb4ee032..cecdec59a 100644 --- a/default.nix +++ b/default.nix @@ -14,6 +14,9 @@ lib ? import "${sources.nixpkgs}/lib", }: let + version = "26.05"; + revision = flake.sourceInfo.shortRev or flake.sourceInfo.dirtyShortRev; + devLib = import ./pkgs/lib.nix { inherit lib sources system; }; flakeAttrs = default.import ./maintainers/flake { }; @@ -57,6 +60,11 @@ let options = self.optionsDoc.optionsNix; }; + manuals = self.call manuals/default.nix { + inherit revision version; + modulesPath = "${sources.nixpkgs}/nixos/modules"; + }; + nixos-modules = # TODO: this is a weird shape for what we need: ngipkgs, services, modules? { diff --git a/manuals/.gitignore b/manuals/.gitignore new file mode 100644 index 000000000..2c74adb65 --- /dev/null +++ b/manuals/.gitignore @@ -0,0 +1,3 @@ +build/ +__pycache__/ +_static/_img/nix.pdf diff --git a/manuals/Contributor.md b/manuals/Contributor.md new file mode 100644 index 000000000..ea4c1e017 --- /dev/null +++ b/manuals/Contributor.md @@ -0,0 +1,6 @@ +{#Contributor_Manual} +# NGIpkgs Contributor Manual +- Version: @NGIPKGS_VERSION@ +- Revision: @NGIPKGS_REVISION@ + +ToDo diff --git a/manuals/Makefile b/manuals/Makefile new file mode 100644 index 000000000..fc15a2c67 --- /dev/null +++ b/manuals/Makefile @@ -0,0 +1,239 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = -W +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = build + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# Explicitly set SOURCE_DATE_EPOCH for Sphinx copyright +SOURCE_DATE_EPOCH = $(shell date +%s --date='Jan 1') + +.PHONY: help +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " applehelp to make an Apple Help Book" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " epub3 to make an epub3" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + @echo " coverage to run coverage check of the documentation (if enabled)" + @echo " dummy to check syntax errors of document sources" + +.PHONY: clean +clean: + rm -rf $(BUILDDIR)/* + +.PHONY: html +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + + # support for Cloudflare Pages' redirects + @cp _redirects build/html/_redirects + + # hack to make live-reload on css update work + @cp _static/css/custom.css build/html/_static/css/custom.css + + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +.PHONY: dirhtml +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +.PHONY: singlehtml +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +.PHONY: pickle +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +.PHONY: json +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +.PHONY: htmlhelp +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +.PHONY: qthelp +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/nixpkgs-cookbook.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/nixpkgs-cookbook.qhc" + +.PHONY: applehelp +applehelp: + $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp + @echo + @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." + @echo "N.B. You won't be able to view it unless you put it in" \ + "~/Library/Documentation/Help or install it in your application" \ + "bundle." + +.PHONY: devhelp +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/nixpkgs-cookbook" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/nixpkgs-cookbook" + @echo "# devhelp" + +.PHONY: epub +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +.PHONY: epub3 +epub3: + $(SPHINXBUILD) -b epub3 $(ALLSPHINXOPTS) $(BUILDDIR)/epub3 + @echo + @echo "Build finished. The epub3 file is in $(BUILDDIR)/epub3." + +.PHONY: latex +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +.PHONY: latexpdf +# Issue: https://github.com/NixOS/nixpkgs/issues/180639#issuecomment-3263260817 +# Documentation: https://github.com/NixOS/nixpkgs/blob/nixos-25.11/doc/languages-frameworks/texlive.section.md#lualatex-font-cache-sec-language-texlive-lualatex-font-cache +# Explanation: still needed with LuaLaTeX 7667 ≥ 7606 +# and using TEXMFVAR instead does not help. +latexpdf: HOME:=$(shell mktemp -d) +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +.PHONY: latexpdfja +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +.PHONY: text +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +.PHONY: man +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +.PHONY: texinfo +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +.PHONY: info +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +.PHONY: gettext +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +.PHONY: changes +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +.PHONY: linkcheck +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +.PHONY: doctest +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +.PHONY: coverage +coverage: + $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage + @echo "Testing of coverage in the sources finished, look at the " \ + "results in $(BUILDDIR)/coverage/python.txt." + +.PHONY: xml +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +.PHONY: pseudoxml +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." + +.PHONY: dummy +dummy: + $(SPHINXBUILD) -b dummy $(ALLSPHINXOPTS) $(BUILDDIR)/dummy + @echo + @echo "Build finished. Dummy builder generates no files." diff --git a/manuals/Options.md b/manuals/Options.md new file mode 100644 index 000000000..f7c949e4a --- /dev/null +++ b/manuals/Options.md @@ -0,0 +1,13 @@ +{#Options} +# NGIpkgs Options +- Version: @NGIPKGS_VERSION@ +- Revision: @NGIPKGS_REVISION@ + +The following tree of options is provided by importing: +- `inputs.NGIpkgs.nixosModules.programs` +- `inputs.NGIpkgs.nixosModules.services` + +## Options +```{toctree} +Options/generated.md +``` diff --git a/manuals/Options.nix b/manuals/Options.nix new file mode 100644 index 000000000..ac3ea278b --- /dev/null +++ b/manuals/Options.nix @@ -0,0 +1,118 @@ +{ + lib, + modulesPath, + nixos-modules, + nixosOptionsDoc, + pkgs, + revision, + writeText, + ... +}: +rec { + optionsDoc = nixosOptionsDoc { + inherit revision; + options = + lib.flip lib.removeAttrs [ "_module" ] + (lib.evalModules { + class = "nixos"; + specialArgs = { + inherit pkgs modulesPath; + }; + modules = [ + { + config = { + # Explanation: do not check anything + # because NixOS options are not included. + # See also comment in NixOS' `noCheckForDocsModule`. + _module.check = false; + }; + imports = lib.attrValues nixos-modules.programs ++ lib.attrValues nixos-modules.services; + } + ]; + }).options; + }; + + # NixOS' `nixos-render-docs options commonmark` + # generates a markdown that is not compatible with MyST, + # and assumes it's only used in the context of NixOS. + # + # Description: generates a valid MyST syntax from `manuals.optionsDoc.optionsNix`. + optionsMyST = + let + fixContent = + text: + lib.replaceStrings + [ + "(#opt-" + "{.note}" + "{.warning}" + "{var}" + ] + [ + "(https://nixos.org/manual/nixos/unstable/#opt-" + "{note}" + "{warning}" + "{option}" + ] + (lib.removeSuffix "\n" text); + renderCode = + arg: + if lib.typeOf arg == "string" then + fixContent arg + else + let + text = fixContent arg.text; + in + if arg._type == "literalExpression" then + if lib.match ".*\n.*" text == null then + "`${lib.replaceStrings [ "`" ] [ "\\`" ] text}`" + else + '' + + ``` + ${lib.replaceStrings [ "```" ] [ "\\`\\`\\`" ] text} + ``` + '' + else if arg._type == "literalMD" then + text + else + # FixMe(completeness): unsupported arg._type + assert (lib.trace arg._type false); + ""; + renderId = lib.concatMapStringsSep "-" ( + part: + lib.concatStrings ( + lib.map ( + c: if "0" <= c && c <= "9" || "a" <= c && c <= "z" || "A" <= c && c <= "Z" then c else "_" + ) (lib.stringToCharacters part) + ) + ); + in + writeText "generated.md" ( + lib.concatStringsSep "\n\n" ( + lib.concatAttrValues ( + lib.mapAttrs (optName: opt: [ + ( + '' + {#option-${renderId opt.loc}} + # `${optName}` + '' + + lib.optionalString opt.readOnly '' + - ReadOnly: ${toString opt.readOnly} + '' + + '' + - Type: `${opt.type}` + - Description: ${renderCode opt.description} + '' + + lib.optionalString (opt ? "default") '' + - Default: ${renderCode opt.default} + '' + + lib.optionalString (opt ? "example") '' + - Example: ${renderCode opt.example} + '' + ) + ]) optionsDoc.optionsNix + ) + ) + ); +} diff --git a/manuals/User.md b/manuals/User.md new file mode 100644 index 000000000..f67e6114d --- /dev/null +++ b/manuals/User.md @@ -0,0 +1,6 @@ +{#User_Manual} +# NGIpkgs User Manual +- Version: @NGIPKGS_VERSION@ +- Revision: @NGIPKGS_REVISION@ + +ToDo diff --git a/manuals/_redirects b/manuals/_redirects new file mode 100644 index 000000000..342d64871 --- /dev/null +++ b/manuals/_redirects @@ -0,0 +1,4 @@ +# format documentation: +# - https://docs.netlify.com/routing/redirects/#syntax-for-the-redirects-file +# - https://docs.netlify.com/routing/redirects/redirect-options/ + diff --git a/manuals/_static/css/custom.css b/manuals/_static/css/custom.css new file mode 100644 index 000000000..ba96c835d --- /dev/null +++ b/manuals/_static/css/custom.css @@ -0,0 +1,127 @@ +:root { + --sd-color-card-border-hover: var(--pst-color-primary) !important; +} + +div.highlight-shell-session + div.highlight-none pre { + background-color: var(--pst-color-preformatted-text),1 !important; + color: var(--pst-color-preformatted-background),1 !important; +} + +div.expression > div.highlight > pre::before { + content: "Expression"; + background-color: var(--pst-color-primary); +} + +div.expression > div.highlight > pre { + border: 1px solid var(--pst-color-primary); +} + +div.value > div.highlight > pre::before { + content: "Value"; + background-color: var(--pst-color-secondary); +} + +div.value > div.highlight > pre { + border: 1px solid var(--pst-color-secondary); +} + +div.highlight > pre::before { + display: block; + position: absolute; + top: 0; + right: 0; + padding: 0 0.5em; + background-color: #b3b3b3; + color: #fff; + font-size: 0.8em; + border-radius: 0 0.4em 0 0.4em; + transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); +} + +div.highlight:hover > pre::before { + opacity: 0; +} + +html[data-theme="light"] .highlight .gi { + background-color: #ccffcc; + border: 1px solid #ccffcc; +} + +html[data-theme="light"] .highlight .gd { + background-color: #ffcccc; + border: 1px solid #ffcccc; + color: inherit !important; +} + +html[data-theme="dark"] .highlight .gi { + background-color: #005400; + border: 1px solid #005400; +} + +html[data-theme="dark"] .highlight .gd { + background-color: #540000; + border: 1px solid #540000; + color: inherit !important; +} + +.topic { + padding: 30px; +} + +.bd-links { + padding-bottom: 0 !important; +} + +.logo { + margin-bottom: 1rem; +} + +.logo a { + text-decoration: none; +} + +.logo img { + height: 3rem; + vertical-align: middle; +} + +.logo span { + margin-left: 0.125em; + font-size: 3.25rem; + vertical-align: middle; +} + +.navbar-nav li.toctree-l1 { + margin-top: 1rem; + margin-bottom: 0.5rem; +} + +.navbar-nav li.toctree-l1 > .toctree-toggle { + display: none; +} + +.navbar-nav li.toctree-l1 > a { + font-weight: 600; +} + +.navbar-nav li.toctree-l1 > ul { + padding: 0; +} + +html[data-theme="dark"] details { + background-color: #323c537d; + border: 1px solid #323c537d; +} + +html[data-theme="light"] details { + background-color: #abc8debf; + border: 1px solid #abc8debf; +} + +html[data-theme="dark"] details a { + color: #6097c1; +} + +html[data-theme="light"] details a { + color: #0042aa; +} diff --git a/manuals/_templates/about.html b/manuals/_templates/about.html new file mode 100644 index 000000000..65c1f3a6f --- /dev/null +++ b/manuals/_templates/about.html @@ -0,0 +1,10 @@ + + + + +

NGIpkgs Manuals

diff --git a/manuals/_templates/download-links.html b/manuals/_templates/download-links.html new file mode 100644 index 000000000..fa9ba62c3 --- /dev/null +++ b/manuals/_templates/download-links.html @@ -0,0 +1,5 @@ + diff --git a/manuals/conf.py b/manuals/conf.py new file mode 100644 index 000000000..b5ce5456e --- /dev/null +++ b/manuals/conf.py @@ -0,0 +1,465 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys +import os +from datetime import date + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = [ + "myst_parser", + "sphinx.ext.intersphinx", + "sphinx.ext.todo", + "sphinx_copybutton", + "sphinx_design", + "sphinx_sitemap", + "notfound.extension", +] + +# Add myst-specific extensions, see what is available on +# https://myst-parser.readthedocs.io/en/latest/syntax/optional.html +myst_enable_extensions = [ + "colon_fence", + "linkify", + "tasklist", + "attrs_block", +] + +# GitHub-style automatic anchors for headings +myst_heading_anchors = 3 + +myst_number_code_blocks = [ "nix", "python" ] + +copybutton_prompt_text = r"\$ |nix-repl> " +copybutton_prompt_is_regexp = True + +# Add any paths that contain templates here, relative to this directory. +templates_path = ["_templates"] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# source_suffix = ['.rst', '.md'] +source_suffix = ".md" + +# The encoding of source files. +# source_encoding = 'utf-8-sig' + +# The master toctree document. +root_doc = "index" + +# General information about the project. +project = "https://nixos.org/community/teams/ngi/" +author = "the Nix@NGI team." +copyright = "2026-" + str(date.today().year) + ", NixOS Foundation / Nix@NGI Team" + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +release = "" + +# Explanation: many options {option}`foo` are NixOS options, +# hence not available in NGIpkgs manuals. +suppress_warnings = [ + "ref.option", +] + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +# language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +# today = '' +# Else, today_fmt is used as the format for a strftime call. +# today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This patterns also effect to html_static_path and html_extra_path +exclude_patterns = [ + #"tutorials/learning-journey/template.md" +] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +# default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +# add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +# add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +# show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = "sphinx" + +# A list of ignored prefixes for module index sorting. +# modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +# keep_warnings = False + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = True + + +# -- Options for HTML output ---------------------------------------------- + +html_baseurl = "https://ngi.nixos.org/manuals/" + +html_theme = "sphinx_book_theme" + +# https://sphinx-book-theme.readthedocs.io/en/stable/reference.html +html_theme_options = { + "repository_url": "https://github.com/ngi-nix/ngipkgs", + "repository_branch": "master", + "path_to_docs": "manuals", + "use_repository_button": True, + "show_navbar_depth": 2, +} + + +# Add any paths that contain custom themes here, relative to this directory. +# html_theme_path = [] + +# The name for this set of Sphinx documents. +# " v documentation" by default. +# html_title = 'nixpkgs-cookbook vrolling' + +# A shorter title for the navigation bar. Default is the same as html_title. +# html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +# html_logo = None + +# The name of an image file (relative to this directory) to use as a favicon of +# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +html_favicon = "favicon.ico" + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +html_extra_path = ["robots.txt"] + +# If not None, a 'Last updated on:' timestamp is inserted at every page +# bottom, using the given strftime format. +# The empty string is equivalent to '%b %d, %Y'. +# html_last_updated_fmt = None + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +# html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +html_sidebars = { + "**": [ + "about.html", + "search-field.html", + "sbt-sidebar-nav.html", + "download-links.html", + ], +} + +singlehtml_sidebars = { + "**": [ + "about.html", + "sbt-sidebar-nav.html", + "download-links.html", + ], +} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +# html_additional_pages = {} + +# If false, no module index is generated. +# html_domain_indices = True + +# If false, no index is generated. +# html_use_index = True + +# If true, the index is split into individual pages for each letter. +# html_split_index = False + +# If true, links to the reST sources are added to the pages. +# html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +# html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +# html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +# html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +# html_file_suffix = None + +# Language to be used for generating the HTML full-text search index. +# Sphinx supports the following languages: +# 'da', 'de', 'en', 'es', 'fi', 'fr', 'h', 'it', 'ja' +# 'nl', 'no', 'pt', 'ro', 'r', 'sv', 'tr', 'zh' +html_search_language = 'en' + +# A dictionary with options for the search language support, empty by default. +# 'ja' uses this config value. +# 'zh' user can custom change `jieba` dictionary path. +# html_search_options = {'type': 'default'} + +# The name of a javascript file (relative to the configuration directory) that +# implements a search results scorer. If empty, the default will be used. +# html_search_scorer = 'scorer.js' + +# Output file base name for HTML help builder. +# htmlhelp_basename = 'nixpkgs-' + +# -- Options for LaTeX output --------------------------------------------- + +# Documentation: https://www.sphinx-doc.org/en/master/latex.html +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + 'papersize': 'a4paper', + # The font size ('10pt', '11pt' or '12pt'). + #'pointsize': '10pt', + # Additional stuff for the LaTeX preamble. + 'preamble': r''' + \setcounter{tocdepth}{0} + ''', + 'sphinxsetup': r'TitleColor={RGB}{87, 154, 202}', + # Latex figure (float) alignment + #'figure_align': 'htbp', + 'extrapackages': r''' + ''', +} + +# Grouping the document tree into LaTeX files. +# Documentation: https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-latex_documents +latex_documents = [ + ( + "Contributor", + "NGIpkgs_Contributor_Manual.tex", + "NGIpkgs Contributor Manual", + "NGIpkgs Contributor", + "manual", + False, + ), + ( + "Options", + "NGIpkgs_Options.tex", + "NGIpkgs Options", + "NGIpkgs Contributors", + "howto", + False, + ), + ( + "User", + "NGIpkgs_User_Manual.tex", + "NGIpkgs User Manual", + "NGIpkgs Contributors", + "manual", + False, + ), +] + +latex_engine = "lualatex" +# The name of an image file (relative to this directory) to place at the top of +# the title page. +latex_logo = "_static/_img/nix.pdf" + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +# latex_use_parts = False + +latex_use_xindy = False + +# If true, show page references after internal links. +latex_show_pagerefs = True + +# If true, show URL addresses after external links. +latex_show_urls = 'footnote' + +# Documents to append as an appendix to all manuals. +# latex_appendices = [] + +# If false, no module index is generated. +# latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ("Contributor", "NGIpkgs_Contributor_Manual", "NGIpkgs Contributor Manual", "NGIpkgs Contributors", 5), + ("Options", "NGIpkgs_Options", "Module options provided by NGIpkgs", "NGIpkgs Contributors", 5), + ("User", "NGIpkgs_User_Manual", "NGIpkgs User Manual", "NGIpkgs Contributors", 5), +] + +# If true, show URL addresses after external links. +# man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ("Contributor", "NGIpkgs_Contributor_Manual", "NGIpkgs Contributor Manual", "NGIpkgs Contributors", "NGIpkgs", "Manual for contributors to NGIpkgs", "Miscellaneous",), + ("Options", "NGIpkgs_Options", "NGIpkgs' Options", "NGIpkgs Contributors", "NGIpkgs", "Module options provided by NGIpkgs", "Miscellaneous",), + ("User", "NGIpkgs_User_Manual", "NGIpkgs User Manual", "NGIpkgs Contributors", "NGIpkgs", "Manual for users of NGIpkgs", "Miscellaneous",), +] + +# Documents to append as an appendix to all manuals. +# texinfo_appendices = [] + +# If false, no module index is generated. +# texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'.? +# texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +# texinfo_no_detailmenu = False + + +# -- Options for Epub output ---------------------------------------------- + +# Bibliographic Dublin Core info. +epub_title = project +epub_author = author +epub_publisher = author +epub_copyright = copyright + +# The basename for the epub file. It defaults to the project name. +# epub_basename = project + +# The HTML theme for the epub output. Since the default themes are not +# optimized for small screen space, using the same theme for HTML and epub +# output is usually not wise. This defaults to 'epub', a theme designed to save +# visual space. +# epub_theme = 'epub' + +# The language of the text. It defaults to the language option +# or 'en' if the language is not set. +# epub_language = '' + +# The scheme of the identifier. Typical schemes are ISBN or URL. +# epub_scheme = '' + +# The unique identifier of the text. This can be a ISBN number +# or the project homepage. +# epub_identifier = '' + +# A unique identification for the text. +# epub_uid = '' + +# A tuple containing the cover image and cover page html template filenames. +# epub_cover = () + +# A sequence of (type, uri, title) tuples for the guide element of content.opf. +# epub_guide = () + +# HTML files that should be inserted before the pages created by sphinx. +# The format is a list of tuples containing the path and title. +# epub_pre_files = [] + +# HTML files that should be inserted after the pages created by sphinx. +# The format is a list of tuples containing the path and title. +# epub_post_files = [] + +# A list of files that should not be packed into the epub file. +epub_exclude_files = ["search.html"] + +# The depth of the table of contents in toc.ncx. +# epub_tocdepth = 3 + +# Allow duplicate toc entries. +# epub_tocdup = True + +# Choose between 'default' and 'includehidden'. +# epub_tocscope = 'default' + +# Fix unsupported image types using the Pillow. +# epub_fix_images = False + +# Scale large images. +# epub_max_image_width = 0 + +# How to display URL addresses: 'footnote', 'no', or 'inline'.? +# epub_show_urls = 'inline' + +# If false, no index is generated. +# epub_use_index = True + + +linkcheck_ignore = [ + # It's dynamic + r"https://matrix.to", + # Linkcheck fails on anchors in GH READMEs, see https://github.com/sphinx-doc/sphinx/issues/9016 + r"https://github.com/.+/.+#.+$", + # Linkcheck fails on anchors in GH browser/file viewer, see https://github.com/sphinx-doc/sphinx/issues/11484 + r"https://github\.com/.+/.+/blob/.*#.*$", + r"https://github\.com/.+/.+/tree/.*#.*$", + # Explanation: to use the Web URL to the manuals within the build output + # when referencing arbitrary files, + # because Sphinx does not have facilities to deploy arbitrary files. + # since linkchecking those URLs will fail before actually deploying them, + # we ignore them here. + r"https://ngi.nixos.org/manuals/.*$", +] + +# Anchors are not present in HTML +linkcheck_anchors_ignore = [ + # GitHub code line numbers + r"^L(\d+)(-L\d+)?$", +] + + +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = {} + +# Custom style sheets +html_css_files = [ + 'css/custom.css', +] + +sitemap_url_scheme = "{link}" + +# Not found +notfound_urls_prefix = "/" diff --git a/manuals/default.nix b/manuals/default.nix new file mode 100644 index 000000000..2b654afb8 --- /dev/null +++ b/manuals/default.nix @@ -0,0 +1,232 @@ +{ + callPackage, + fetchurl, + ghostscript, + gnused, + imagemagick, + installShellFiles, + lib, + modulesPath, + perl, + python3, + revision, + stdenv, + texinfo, + texlive, + version, + ... +}: +let + options = callPackage ./Options.nix { inherit modulesPath revision; }; + + common = stdenv.mkDerivation (finalAttrs: { + pname = "NGIpkgs-Manuals-${finalAttrs.passthru.format}"; + inherit version; + src = + with lib.fileset; + toSource { + root = ../.; + fileset = intersection (gitTracked ../.) (unions [ + (fileFilter ( + file: + lib.any file.hasExt [ + "md" + "nix" + "svg" + ] + ) ../.) + ./Makefile + ./_redirects + ./_static + ./_templates + ./conf.py + ./netlify.toml + ./robots.txt + ../projects + ]); + }; + + nativeBuildInputs = [ + finalAttrs.passthru.pythonPackages + gnused + imagemagick + perl + ]; + + patchPhase = '' + runHook prePatch + mkdir -p manuals/Options + ln -sf ${options.optionsMyST} manuals/Options/generated.md + + for manual in ${lib.concatStringsSep " " finalAttrs.passthru.manuals}; do + substituteInPlace manuals/''${manual}.md \ + --replace-fail '@NGIPKGS_REVISION@' "${revision}" \ + --replace-fail '@NGIPKGS_VERSION@' "${version}" + done + + mkdir -p manuals/_static/_img + ln -s ${finalAttrs.passthru.logo.svg} manuals/_static/_img/nix.svg + magick ${finalAttrs.passthru.logo.svg} \ + -background transparent \ + -define icon:auto-resize=32 \ + -extent "%[fx:max(w,h)]x%[fx:max(w,h)]" \ + -fuzz 10% \ + -gravity center \ + -transparent white \ + -trim +repage \ + manuals/favicon.ico + runHook postPatch + ''; + + buildPhase = '' + runHook preBuild + make -C manuals ${finalAttrs.passthru.format} + runHook postBuild + ''; + + passthru = { + inherit options; + manuals = [ + "Contributor" + "Options" + "User" + ]; + logo.svg = fetchurl { + url = "https://brand.nixos.org/logos/nixos-logomark-default-gradient-minimal.svg"; + hash = "sha256-YrOle9qo0G92vvCjy9FAkyNOdyAz1DR+xoc+/CpK0yk="; + }; + pythonPackages = python3.withPackages ( + pyPkgs: with pyPkgs; [ + linkify-it-py + myst-parser + sphinx + sphinx-book-theme + sphinx-copybutton + sphinx-design + sphinx-notfound-page + sphinx-sitemap + ] + ); + }; + }); + +in + +# Split the different formats +# in different derivations instead of different outputs +# in order to only use `nix build -f. manuals.man` +# as a `.git/hooks/pre-push` check. +lib.recurseIntoAttrs { + html = common.overrideAttrs ( + finalAttrs: previousAttrs: { + installPhase = '' + runHook preInstall + cp -R manuals/build/html $out/ + cp -t $out \ + manuals/netlify.toml \ + manuals/robots.txt + runHook postInstall + ''; + passthru = previousAttrs.passthru or { } // { + format = "html"; + }; + } + ); + + info = common.overrideAttrs (previousAttrs: { + passthru = previousAttrs.passthru or { } // { + format = "info"; + }; + nativeBuildInputs = previousAttrs.nativeBuildInputs or [ ] ++ [ texinfo ]; + installPhase = '' + runHook preInstall + mkdir -p $out/share/info + cp manuals/build/texinfo/*.info $out/share/info/ + runHook postInstall + ''; + }); + + latexpdf = common.overrideAttrs ( + finalAttrs: previousAttrs: { + nativeBuildInputs = previousAttrs.nativeBuildInputs or [ ] ++ [ + finalAttrs.passthru.texPackages + ghostscript + imagemagick + ]; + prePatch = previousAttrs.prePatch or "" + '' + mkdir -p manuals/_static/_img + magick ${finalAttrs.passthru.logo.svg} manuals/_static/_img/nix.pdf + ''; + installPhase = '' + runHook preInstall + pushd manuals/build/latex/ + mkdir -p $out + # Drastically reduce resulting PDF size + # by compressing embedded images (logo). + # + # FixMe(role): there may be a way to do it upfront using sphinx. + for pdf in NGIpkgs_*.pdf; do + ps2pdf \ + -dPDFSETTINGS="/default" \ + -dDownsampleGrayImages=false\ + -dAutoRotatePages=/None \ + -dColorImageResolution=600 \ + -dColorImageDownsampleType=/Bicubic \ + "$pdf" \ + "$out/$pdf" + done + popd + runHook postInstall + ''; + passthru = previousAttrs.passthru or { } // { + format = "latexpdf"; + # Those TeX packages are dependencies to provision + # for the build/latex/*.{tex,sty} files generated by sphinx, + # ./tex-env.nix has been generated with: + # nix -L develop -f. manuals.latexpdf + # nix run github:rgri/tex2nix -- build/latex/*.{tex,sty} + # nixfmt ./tex-env.nix + # It may have to be regenerated at some point the build is missing tex packages. + texPackages = callPackage ./tex-env.nix { + extraTexPackages = { + inherit (texlive) + latexmk + collection-fontsrecommended + collection-latexrecommended + collection-luatex + gnu-freefont # For FreeSerif.otf + ; + }; + }; + }; + } + ); + + man = common.overrideAttrs (previousAttrs: { + passthru = previousAttrs.passthru or { } // { + format = "man"; + }; + nativeBuildInputs = previousAttrs.nativeBuildInputs or [ ] ++ [ installShellFiles ]; + installPhase = '' + runHook preInstall + installManPage manuals/build/man/*.5 + runHook postInstall + ''; + }); + + singlehtml = common.overrideAttrs ( + finalAttrs: previousAttrs: { + passthru = previousAttrs.passthru or { } // { + format = "singlehtml"; + }; + installPhase = '' + runHook preInstall + cp -R manuals/build/singlehtml $out/ + cp -t $out \ + manuals/netlify.toml \ + manuals/robots.txt + runHook postInstall + ''; + } + ); +} diff --git a/manuals/index.md b/manuals/index.md new file mode 100644 index 000000000..6bf997d67 --- /dev/null +++ b/manuals/index.md @@ -0,0 +1,5 @@ +```{toctree} +User.md +Contributor.md +Options.md +``` diff --git a/manuals/netlify.toml b/manuals/netlify.toml new file mode 100644 index 000000000..a6502798a --- /dev/null +++ b/manuals/netlify.toml @@ -0,0 +1,15 @@ +[[redirects]] +from = "/manual/nix/unstable/*" +to = "https://hydra.nixos.org/job/nix/master/manual/latest/download/1/manual/:splat" +status = 200 +force = true +[redirects.headers] +X-From = "NGIpkgs-12e7be5d" + +[[redirects]] +from = "/manual/nix/development/*" +to = "https://hydra.nixos.org/job/nix/master/manual/latest/download/1/manual/:splat" +status = 200 +force = true +[redirects.headers] +X-From = "NGIpkgs-12e7be5d" diff --git a/manuals/robots.txt b/manuals/robots.txt new file mode 100644 index 000000000..e317ff7d1 --- /dev/null +++ b/manuals/robots.txt @@ -0,0 +1,4 @@ +User-agent: * +Disallow: /manuals/_static/ +Disallow: /manuals/_sources/ +Sitemap: https://ngi.nixos.org/manuals/sitemap.xml diff --git a/manuals/tex-env.nix b/manuals/tex-env.nix new file mode 100644 index 000000000..d3e450f79 --- /dev/null +++ b/manuals/tex-env.nix @@ -0,0 +1,84 @@ +# Generated with tex2nix 0.0.0 +{ + texlive, + extraTexPackages ? { }, +}: +(texlive.combine ( + { + inherit (texlive) scheme-small; + "amsmath" = texlive."amsmath"; + "atbegshi" = texlive."atbegshi"; + "auxhook" = texlive."auxhook"; + "bidi" = texlive."bidi"; + "bigintcalc" = texlive."bigintcalc"; + "bitset" = texlive."bitset"; + "booktabs" = texlive."booktabs"; + "capt-of" = texlive."capt-of"; + "changepage" = texlive."changepage"; + "cmap" = texlive."cmap"; + "colortbl" = texlive."colortbl"; + "ctablestack" = texlive."ctablestack"; + "etex" = texlive."etex"; + "etexcmds" = texlive."etexcmds"; + "etoolbox" = texlive."etoolbox"; + "fancyhdr" = texlive."fancyhdr"; + "fancyvrb" = texlive."fancyvrb"; + "float" = texlive."float"; + "fncychap" = texlive."fncychap"; + "fontspec" = texlive."fontspec"; + "footmisc" = texlive."footmisc"; + "framed" = texlive."framed"; + "geometry" = texlive."geometry"; + "gettitlestring" = texlive."gettitlestring"; + "hopatch" = texlive."hopatch"; + "hycolor" = texlive."hycolor"; + "hypcap" = texlive."hypcap"; + "hyperref" = texlive."hyperref"; + "ifmtarg" = texlive."ifmtarg"; + "iftex" = texlive."iftex"; + "infwarerr" = texlive."infwarerr"; + "intcalc" = texlive."intcalc"; + "kvdefinekeys" = texlive."kvdefinekeys"; + "kvoptions" = texlive."kvoptions"; + "kvsetkeys" = texlive."kvsetkeys"; + "letltxmacro" = texlive."letltxmacro"; + "listings" = texlive."listings"; + "ltxcmds" = texlive."ltxcmds"; + "luabidi" = texlive."luabidi"; + "luacode" = texlive."luacode"; + "luaotfload" = texlive."luaotfload"; + "luatexbase" = texlive."luatexbase"; + "luavlna" = texlive."luavlna"; + "marvosym" = texlive."marvosym"; + "minitoc" = texlive."minitoc"; + "natbib" = texlive."natbib"; + "needspace" = texlive."needspace"; + "notoccite" = texlive."notoccite"; + "ntheorem" = texlive."ntheorem"; + "paralist" = texlive."paralist"; + "parskip" = texlive."parskip"; + "pdfescape" = texlive."pdfescape"; + "pdftexcmds" = texlive."pdftexcmds"; + "placeins" = texlive."placeins"; + "polyglossia" = texlive."polyglossia"; + "ragged2e" = texlive."ragged2e"; + "refcount" = texlive."refcount"; + "rerunfilecheck" = texlive."rerunfilecheck"; + "setspace" = texlive."setspace"; + "showexpl" = texlive."showexpl"; + "stringenc" = texlive."stringenc"; + "tabulary" = texlive."tabulary"; + "tex4ht" = texlive."tex4ht"; + "titlesec" = texlive."titlesec"; + "uniquecounter" = texlive."uniquecounter"; + "upquote" = texlive."upquote"; + "url" = texlive."url"; + "varwidth" = texlive."varwidth"; + "wrapfig" = texlive."wrapfig"; + "xcolor" = texlive."xcolor"; + "xifthen" = texlive."xifthen"; + "xurl" = texlive."xurl"; + + } + // extraTexPackages +))