From 6c9732506c6a956e68794feff32af861d8424945 Mon Sep 17 00:00:00 2001 From: "Samuel Hierholzer (Adfinis AG)" Date: Mon, 11 Nov 2024 08:35:57 +0100 Subject: [PATCH] docs: Generate documentation with sphinx --- .gitignore | 3 ++ Makefile | 24 +++++++++++++ README.md | 4 +-- docs/Code_Reference.rst | 41 ++++++++++++++++++++++ docs/{TUTORIAL.md => Getting_Started.md} | 16 +++++---- docs/Makefile | 20 +++++++++++ docs/README.md | 1 + docs/_build/.gitkeep | 0 docs/conf.py | 43 ++++++++++++++++++++++++ docs/index.rst | 24 +++++++++++++ md-click.patch | 20 +++++++++++ pyaptly/cli.py | 19 ++++++----- pyproject.toml | 6 ++++ 13 files changed, 202 insertions(+), 19 deletions(-) create mode 100644 docs/Code_Reference.rst rename docs/{TUTORIAL.md => Getting_Started.md} (97%) create mode 100644 docs/Makefile create mode 120000 docs/README.md create mode 100644 docs/_build/.gitkeep create mode 100644 docs/conf.py create mode 100644 docs/index.rst create mode 100644 md-click.patch diff --git a/.gitignore b/.gitignore index 1455bad..603ecc3 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,6 @@ __pycache__ /.dmypy.json /.coverage /dist +docs/cli +docs/sphinx-template +docs/_build diff --git a/Makefile b/Makefile index 422e640..0396a4b 100644 --- a/Makefile +++ b/Makefile @@ -63,6 +63,30 @@ lint-code: ## check all linters .PHONY: test test: pytest mypy lint-code ## run all testing + +.PHONY: docs +docs: poetry-install + rm -vrf docs/_build/* docs/cli/* + [[ -d docs/sphinx-template ]] || git clone https://github.com/adfinis-sygroup/adsy-sphinx-template docs/sphinx-template + @docker compose exec testing bash -c "poetry install --only docs" + + # Currently md-click has a bad dependency on old click. We fix this with the next command + @docker compose exec testing bash -c "poetry run pip install md-click==1.0.1" + @docker compose exec testing bash -c "patch -f /root/.cache/pypoetry/virtualenvs/pyaptly-*-py3.11/lib/python3.11/site-packages/md_click/main.py md-click.patch || true" + + # Generate CLI docs + @docker compose exec testing bash -c "mkdir -p docs/_temp && poetry run mdclick dumps --baseModule=pyaptly.cli --baseCommand=pyaptly --docsPath=./docs/_temp" + + @cat docs/_temp/pyaptly.md docs/_temp/pyaptly-*.md > docs/Command_Line_Reference.md + # mdclick has not enough indentation + @sed -i 's/^#/##/' docs/Command_Line_Reference.md + # Add title, must happen after the above sed command + @sed -i '1a\n# Command Line Reference' docs/Command_Line_Reference.md + @rm -r docs/_temp + + # SPHINX Render + @docker compose exec testing bash -c 'cd docs/ && poetry run make html' + .PHONY: shell shell: poetry-install ## run shell @docker compose exec testing bash -c "SHELL=bash poetry shell" diff --git a/README.md b/README.md index 8861e5e..9c55b05 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ input files. - For for the old version [switch to the master branch](https://github.com/adfinis/pyaptly/tree/master) - Main branch builds contain [alpha packages](https://github.com/adfinis/pyaptly/actions/runs/8147002919), see Artifacts -# Why & How +## Why & How [Aptly](https://www.aptly.info/) is great tool for creating Debian repositories. But as soon as it's required to maintain repositories for different [environments](https://en.wikipedia.org/wiki/Deployment_environment) it gets very complicated fast. @@ -22,8 +22,6 @@ That means it's hard to roll back to a previous state if required. This problem is fixed by using fix timestamps in snapshot names. That behaviour also allows to define a fixed update spacing. It's possible to say for example "only update this snapshot once a week". -[Follow the Tutorial](./docs/TUTORIAL.md) - ## Example commands Initialize a new aptly server. diff --git a/docs/Code_Reference.rst b/docs/Code_Reference.rst new file mode 100644 index 0000000..bada780 --- /dev/null +++ b/docs/Code_Reference.rst @@ -0,0 +1,41 @@ +Code Reference +============== + +The following code reference is extracted from the source code and mainly used for debugging/development. +Users of `pyaptly` can ignore this. + +Main +---- +.. automodule:: pyaptly.main + :members: + +Mirror +------ +.. automodule:: pyaptly.mirror + :members: + +Repo +---- +.. automodule:: pyaptly.repo + :members: + +Snapshot +-------- +.. automodule:: pyaptly.snapshot + :members: + +Publish +------- +.. automodule:: pyaptly.publish + :members: + +State Reader +------------ +.. automodule:: pyaptly.state_reader + :members: + +Util +---- +.. automodule:: pyaptly.util + :members: + diff --git a/docs/TUTORIAL.md b/docs/Getting_Started.md similarity index 97% rename from docs/TUTORIAL.md rename to docs/Getting_Started.md index b39ed4f..7107ada 100644 --- a/docs/TUTORIAL.md +++ b/docs/Getting_Started.md @@ -1,3 +1,5 @@ +# Getting Started + > Note: This tutorial assumes basic knowledge of [Aptly](https://www.aptly.info/). Pyaptly is capable of managing mirrors, snapshots and publishes. @@ -6,11 +8,11 @@ But for the purpose of this tutorial we assume a clean [install of Aptly](https: TODO: Note to jump to the relevant chapter if only a subset should be managed by aptly. -# Installation +## Installation TODO (once packages are available) -# Aptly Mirror +## Aptly Mirror Pyaptly can create and update mirrors. Since mirrors are nor a very complicated construct, there's no extra logic not available within aptly. Configuring a mirror with pyaptly is pretty much the same as writing a command for aptly - except that it's declarative. @@ -42,7 +44,7 @@ Pyaptly also takes care of downloading the gpp key if it isn't availble yet. If > For a list of all configuration options of a mirror, check out [the reference](TODO: Reference link). -## updating mirrors +### updating mirrors We can also tell pyaptly to update all defined mirrors: ```bash @@ -52,9 +54,9 @@ pyaptly mirror ./config.toml update This is exactly the same as `aptly mirror update aptly` with the above config. But it will update all defined mirrors if more than one is defined, making it a bit more convenient than using `aptly` directly. -# Snapshots +## Snapshots -## Basic snapshots +### Basic snapshots Pyaptly has some extra features for snapshots, but let's start by creating a very simple snapshot first. @@ -87,7 +89,7 @@ As you see, `pyaptly` first "rotates" the snapshot by just renaming and postfixi > Similar to mirrors, pyaptly allows a variety of configuration options for snapshots. Check out [the reference](TODO: Link to reference). -## Snapshots with retention +### Snapshots with retention Snapshots with retention are a bit more complicated than simple snapshots. The retention time is either 1 day or 1 week. Other types of retention are currently not implemented. @@ -134,7 +136,7 @@ It's also important to understand that `pyaptly snapshot config.toml update` wil If we were to patch our systems only once a week, then what we want is to uncomment the line `repeat-weekly: "mon"`. This way, our snapshot would be backdated a full day to `aptly-20240102T0000Z`. This means that pyaptly would only create a new snapshot once a week, no matter how often the command has run. -# Publish +## Publish Pyaptly publishes also come with some extra sugar building on the features of the snapshots. But let's start with a simple publish again: ```bash diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..d4bb2cb --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/README.md b/docs/README.md new file mode 120000 index 0000000..32d46ee --- /dev/null +++ b/docs/README.md @@ -0,0 +1 @@ +../README.md \ No newline at end of file diff --git a/docs/_build/.gitkeep b/docs/_build/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..e075d13 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,43 @@ +# Configuration file for the Sphinx documentation builder. +# +# For the full list of built-in configuration values, see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Project information ----------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information + +project = 'Pyaptly' +copyright = 'Adfinis AG' +author = 'Adfinis AG' +release = '2.0' + +# -- General configuration --------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration + +extensions = [ + 'myst_parser', # No need to add all click files manually to TO + 'sphinx.ext.autosectionlabel', + 'sphinx.ext.autodoc' +] + +# For autodoc +import sys +from pathlib import Path +sys.path.insert(0, str(Path('..').resolve())) + +autosectionlabel_prefix_document = True + +templates_path = ['_templates'] +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', 'sphinx-template'] + +# -- Options for HTML output ------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output + +html_theme = 'adsy' +html_theme_path = ['sphinx-template/html'] +html_title = project +html_static_path = ['sphinx-template/html/adsy/static/'] + +# Output file base name for HTML help builder. +#htmlhelp_basename = 'test1234' + diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..246f96b --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,24 @@ +.. Pyaptly documentation master file, created by + sphinx-quickstart on Thu Nov 7 16:17:24 2024. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Pyaptly documentation +===================== + +Add your content using ``reStructuredText`` syntax. See the +`reStructuredText `_ +documentation for details. + + +.. toctree:: + :maxdepth: 3 + :caption: Contents: + + README.md + Getting_Started.md + Command_Line_Reference.md + Code_Reference.rst + +.. automodule:: pyaptly + :members: diff --git a/md-click.patch b/md-click.patch new file mode 100644 index 0000000..563b81b --- /dev/null +++ b/md-click.patch @@ -0,0 +1,20 @@ ++++ ./a ./b 2024-11-08 13:56:06.904479048 +0000 +@@ -49,12 +49,12 @@ + parent = helpdct.get("parent", "") or '' + options = { + opt.name: { +- "usage": '\n'.join(opt.opts), +- "prompt": opt.prompt, +- "required": opt.required, +- "default": opt.default, +- "help": opt.help, +- "type": str(opt.type) ++ "usage": '\n'.join(opt.opts), ++ "prompt": getattr(opt, "prompt", None), ++ "required": getattr(opt, "required", None), ++ "default": getattr(opt, "default", None), ++ "help": getattr(opt, "help", None), ++ "type": str(getattr(opt, "type", None)) + } + for opt in helpdct.get('params', []) + } diff --git a/pyaptly/cli.py b/pyaptly/cli.py index 8a8c49b..111e83c 100644 --- a/pyaptly/cli.py +++ b/pyaptly/cli.py @@ -27,7 +27,7 @@ def entry_point(): debug = False try: - cli.main(argv[1:]) + pyaptly.main(argv[1:]) except (CalledProcessError, PyaptlyCliError): pass # already logged except Exception as e: @@ -59,14 +59,15 @@ def __init__(self, **kwargs): @click.group() -def cli(): +@click.version_option() +def pyaptly(): """Show basic command group.""" pass # TODO legacy is here to be able to do early alpha and get feedback from users. # remove when there is full replacement. -@cli.command(help="run legacy command parser") +@pyaptly.command(help="run legacy command parser") @click.argument("passthrough", nargs=-1) def legacy(passthrough): """Run legacy pyaptly cli.""" @@ -75,7 +76,7 @@ def legacy(passthrough): main.main(argv=passthrough) -@cli.command() +@pyaptly.command() @click.option("--info/--no-info", "-i/-ni", default=False, type=bool) @click.option("--debug/--no-debug", "-d/-nd", default=False, type=bool) @click.option( @@ -98,7 +99,7 @@ def repo(**kwargs): repo.repo(cfg, args=fake_args) -@cli.command() +@pyaptly.command() @click.option("--info/--no-info", "-i/-ni", default=False, type=bool) @click.option("--debug/--no-debug", "-d/-nd", default=False, type=bool) @click.option( @@ -121,7 +122,7 @@ def mirror(**kwargs): mirror.mirror(cfg, args=fake_args) -@cli.command() +@pyaptly.command() @click.option("--info/--no-info", "-i/-ni", default=False, type=bool) @click.option("--debug/--no-debug", "-d/-nd", default=False, type=bool) @click.option( @@ -144,7 +145,7 @@ def snapshot(**kwargs): snapshot.snapshot(cfg, args=fake_args) -@cli.command() +@pyaptly.command() @click.option("--info/--no-info", "-i/-ni", default=False, type=bool) @click.option("--debug/--no-debug", "-d/-nd", default=False, type=bool) @click.option( @@ -167,7 +168,7 @@ def publish(**kwargs): publish.publish(cfg, args=fake_args) -@cli.command() +@pyaptly.command() @click.option("--debug/--no-debug", "-d/-nd", default=False, type=bool) @click.argument( "yaml_path", @@ -207,7 +208,7 @@ def yaml_to_toml(yaml_path: Path, toml_path: Path, add_defaults: bool, debug: bo ) -@cli.command() +@pyaptly.command() @click.option("--debug/--no-debug", "-d/-nd", default=False, type=bool) @click.argument( "in_path", diff --git a/pyproject.toml b/pyproject.toml index ee66c05..6839f87 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -53,6 +53,12 @@ python-lsp-server = "^1.9.0" python-lsp-ruff = "^2.2.0" # TODO: remove this as soon as most people have converted their config. + +[tool.poetry.group.docs.dependencies] +sphinx = "^8.1.3" +myst-parser = "^4.0.0" +sphinx-rtd-theme = "^3.0.1" + [tool.coverage.run] omit = ["pyaptly/tomli_w/_writer.py"]