From 1b886c1f275fbf562106261e3602a2add7536865 Mon Sep 17 00:00:00 2001 From: Drew Devereux <drew.devereux@csiro.au> Date: Mon, 12 Apr 2021 08:05:26 +0000 Subject: [PATCH] [MCCS-519] PlantUML / RTD support --- Makefile | 9 ++------- docs/Dockerfile | 6 ++++++ docs/requirements.txt | 1 + docs/source/State_Machine.rst | 6 ++---- docs/source/adminMode_state_machine.uml | 11 +++++++++++ docs/source/conf.py | 1 + docs/source/images/AdminModeStateMachine.png | Bin 8867 -> 0 bytes 7 files changed, 23 insertions(+), 11 deletions(-) create mode 100644 docs/Dockerfile create mode 100644 docs/source/adminMode_state_machine.uml delete mode 100644 docs/source/images/AdminModeStateMachine.png diff --git a/Makefile b/Makefile index d120dd29..cf201f8e 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,6 @@ SHELL = /bin/bash DOCKER_REGISTRY_USER:=ska-telescope PROJECT = ska_tango_base IMAGE_FOR_DIAGRAMS = nexus.engageska-portugal.pt/ska-docker/ska-python-buildenv:9.3.3.1 -IMAGE_FOR_DOCS = sphinxdoc/sphinx:latest # # include makefile to pick up the standard Make targets, e.g., 'make build' # build, 'make push' docker push procedure, etc. The other Make targets @@ -57,12 +56,8 @@ generate-diagrams-in-docker-internals: ## Generate state machine diagrams (with ls -lo /diagrams/docs/source/images/ docs-in-docker: ## Generate docs inside a container - @docker run --rm -v $(PWD):/project $(IMAGE_FOR_DOCS) bash -c "cd /project && make docs-in-docker-internals" - -docs-in-docker-internals: ## Generate docs (within a container!) - test -f /.dockerenv # ensure running in docker container - python3 -m pip install -r /project/docs/requirements.txt - cd /project/docs && make clean && make html + @docker build -t ska_tango_base_docs_builder . -f docs/Dockerfile + @docker run --rm -v $(PWD):/project --user $(id -u):$(id -g) ska_tango_base_docs_builder help: ## show this help. @grep -hE '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' diff --git a/docs/Dockerfile b/docs/Dockerfile new file mode 100644 index 00000000..b7ad9a0c --- /dev/null +++ b/docs/Dockerfile @@ -0,0 +1,6 @@ +FROM readthedocs/build:latest + +COPY docs/requirements.txt . +RUN python3 -m pip install --exists-action=w --no-cache-dir --disable-pip-version-check -r requirements.txt + +ENTRYPOINT python3 -m sphinx -T -E -b html -d project/docs/build/doctrees project/docs/source project/docs/build/html diff --git a/docs/requirements.txt b/docs/requirements.txt index e4e2f8ea..a1912774 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,2 +1,3 @@ Sphinx >= 3.5.0 sphinx-rtd-theme >= 0.4.3 +sphinxcontrib-plantuml diff --git a/docs/source/State_Machine.rst b/docs/source/State_Machine.rst index ed542bfd..b8133a50 100644 --- a/docs/source/State_Machine.rst +++ b/docs/source/State_Machine.rst @@ -39,10 +39,8 @@ The admin mode state machine allows for Diagrams of the admin mode state machine are shown below. -.. figure:: images/AdminModeStateMachine.png - :alt: Diagram of the admin mode state machine, as designed - - Diagram of the admin mode state machine, as designed +.. uml:: adminMode_state_machine.uml + :caption: Diagram of the admin mode state machine, as designed .. figure:: images/AdminModeStateMachine_autogenerated.png :alt: Diagram of the admin mode state machine, as implemented diff --git a/docs/source/adminMode_state_machine.uml b/docs/source/adminMode_state_machine.uml new file mode 100644 index 00000000..24945b2c --- /dev/null +++ b/docs/source/adminMode_state_machine.uml @@ -0,0 +1,11 @@ +ONLINE --> ONLINE +ONLINE <-right-> MAINTENANCE +ONLINE <-down-> OFFLINE +MAINTENANCE -> MAINTENANCE +MAINTENANCE <-down-> OFFLINE +OFFLINE -> OFFLINE +OFFLINE <-down->NOT_FITTED +OFFLINE <-down->RESERVED +NOT_FITTED -> NOT_FITTED +NOT_FITTED <-right->RESERVED +RESERVED -> RESERVED diff --git a/docs/source/conf.py b/docs/source/conf.py index 361c6f74..8871ddca 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -100,6 +100,7 @@ extensions = [ 'sphinx.ext.todo', 'sphinx.ext.coverage', 'sphinx.ext.viewcode', + 'sphinxcontrib.plantuml' ] # Add any paths that contain templates here, relative to this directory. diff --git a/docs/source/images/AdminModeStateMachine.png b/docs/source/images/AdminModeStateMachine.png deleted file mode 100644 index 6351a89cf21b929414bfdaa2ca37028d77a32591..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8867 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 -- GitLab