diff --git a/.github/workflows/gh_pages.yml b/.github/workflows/gh_pages.yml new file mode 100644 index 00000000..f9a57b93 --- /dev/null +++ b/.github/workflows/gh_pages.yml @@ -0,0 +1,127 @@ +# Build and deploy documentation to GitHub Pages +name: GitHub Pages + +on: [ push, pull_request ] + +env: + DEFAULT_BRANCH: "release" + +jobs: + build-and-deploy: + name: Build and deploy to gh-pages + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + lfs: true + + - name: Debugging information + run: | + echo "github.ref:" ${{github.ref}} + echo "github.event_name:" ${{github.event_name}} + echo "github.head_ref:" ${{github.head_ref}} + echo "github.base_ref:" ${{github.base_ref}} + set -x + git rev-parse --abbrev-ref HEAD + git branch + git branch -a + git remote -v + python -V + pip list --not-required + pip list + + # Clone and set up the old gh-pages branch + - name: Clone old gh-pages + if: ${{ github.event_name == 'push' }} + run: | + set -x + git fetch + ( git branch gh-pages remotes/origin/gh-pages && git clone . --branch=gh-pages _gh-pages/ ) || mkdir _gh-pages + rm -rf _gh-pages/.git/ + mkdir -p _gh-pages/branch/ + + # If a push and default branch, copy build to _gh-pages/ as the "main" + # deployment. + - name: Build and copy documentation (default branch) + if: | + contains(github.event_name, 'push') && + contains(github.ref, env.DEFAULT_BRANCH) + run: | + set -x + mkdir -p _build/html/versions + + # create two copies of the documentation + # 1. the frozen version, represented as vX.X in the version switcher + docker build -t musica -f docker/Dockerfile.docs . + id=$(docker create musica) + docker cp $id:/build/docs/sphinx tmpdocs + docker rm -v $id + version=$(sed -nr "s/^release = f'v(.+)\{suffix\}'.*$/\1/p" docs/source/conf.py) + mv tmpdocs _build/html/versions/${version} + + # 2. stable, represented as vX.X (stable) in the version switcher + # edit conf.py to produce a version string that looks like vX.X (stable) + docker build -t musica -f docker/Dockerfile.docs --build-arg SUFFIX=" (stable)" . + id=$(docker create musica) + docker cp $id:/build/docs/sphinx tmpdocs + docker rm -v $id + mv tmpdocs _build/html/versions/stable + # Delete everything under _gh-pages/ that is from the + # primary branch deployment. Excludes the other branches + # _gh-pages/branch-* paths, and not including + # _gh-pages itself. + find _gh-pages/ -mindepth 1 ! -path '_gh-pages/branch*' ! -path '_gh-pages/versions*' -delete + rsync -a _build/html/versions/stable/* _gh-pages/ + mkdir -p _gh-pages/versions + rsync -a _build/html/versions/* _gh-pages/versions + # mv docs/switcher.json _gh-pages + + # If a push and not on default branch, then copy the build to + # _gh-pages/branch/$brname (transforming '/' into '--') + - name: Build and copy documentation (branch) + if: | + contains(github.event_name, 'push') && + !contains(github.ref, env.DEFAULT_BRANCH) + run: | + set -x + docker build -t musica -f docker/Dockerfile.docs . + id=$(docker create musica) + docker cp $id:/build/docs/sphinx tmpdocs + docker rm -v $id + brname="${{github.ref}}" + brname="${brname##refs/heads/}" + brdir=${brname//\//--} # replace '/' with '--' + rm -rf _gh-pages/branch/${brdir} + rsync -a tmpdocs/ _gh-pages/branch/${brdir} + + # Go through each branch in _gh-pages/branch/, if it's not a + # ref, then delete it. + - name: Delete old feature branches + if: ${{ github.event_name == 'push' }} + run: | + set -x + for brdir in `ls _gh-pages/branch/` ; do + brname=${brdir//--/\/} # replace '--' with '/' + if ! git show-ref remotes/origin/$brname ; then + echo "Removing $brdir" + rm -r _gh-pages/branch/$brdir/ + fi + done + + # Add the .nojekyll file + - name: nojekyll + if: ${{ github.event_name == 'push' }} + run: | + touch _gh-pages/.nojekyll + + # Deploy + # https://github.com/peaceiris/actions-gh-pages + - name: Deploy + uses: peaceiris/actions-gh-pages@v3 + if: ${{ github.event_name == 'push' }} + with: + publish_branch: gh-pages + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: _gh-pages/ + force_orphan: true diff --git a/CMakeLists.txt b/CMakeLists.txt index a69d73e8..7f7a21b6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,6 +28,7 @@ option(MUSICA_ENABLE_TESTS "Builds tests that ensures each enabled MUSICA compon option(MUSICA_ENABLE_MPI "Enable MPI parallel support" OFF) option(MUSICA_ENABLE_OPENMP "Enable OpemMP support" OFF) option(MUSICA_ENABLE_MEMCHECK "Enable memory checking" OFF) +option(MUSICA_BUILD_DOCS "Build the documentation" OFF) cmake_dependent_option( MUSICA_ENABLE_TUVX "Builds TUV-x, a photolysis calculator library" ON "MUSICA_BUILD_FORTRAN_INTERFACE" OFF) @@ -91,6 +92,10 @@ endif() include(dependencies) +if(MUSICA_BUILD_DOCS) + add_subdirectory(docs) +endif() + ################################################################################ # Tests if(MUSICA_ENABLE_TESTS) diff --git a/docker/Dockerfile.docs b/docker/Dockerfile.docs new file mode 100644 index 00000000..b3cc510e --- /dev/null +++ b/docker/Dockerfile.docs @@ -0,0 +1,33 @@ +FROM fedora:37 + +RUN dnf -y update \ + && dnf -y install \ + doxygen \ + gcc-c++ \ + gcc \ + gdb \ + git \ + cmake \ + make \ + lcov \ + valgrind \ + python3 \ + python3-pip \ + && dnf clean all + +COPY . /musica/ + +RUN pip3 install -r /musica/docs/requirements.txt + +ARG SUFFIX="" +ENV SWITCHER_SUFFIX=$SUFFIX + +RUN echo "The suffix is '$SWITCHER_SUFFIX'" + +RUN mkdir /build \ + && cd /build \ + && cmake -D MUSICA_BUILD_DOCS=ON \ + /musica \ + && make docs + +WORKDIR /build diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt new file mode 100644 index 00000000..5e14eef1 --- /dev/null +++ b/docs/CMakeLists.txt @@ -0,0 +1,20 @@ +################################################################################ +# Sphinx + +set(SPHINX_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/source) +set(SPHINX_BUILD ${CMAKE_CURRENT_BINARY_DIR}/sphinx) +set(SPHINX_INDEX_FILE ${SPHINX_BUILD}/index.html) + +add_custom_command( + OUTPUT ${SPHINX_INDEX_FILE} __fake_file_to_ensure_this_always_run + COMMAND + ${SPHINX_EXECUTABLE} -b html + ${SPHINX_SOURCE} ${SPHINX_BUILD} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + MAIN_DEPENDENCY ${SPHINX_SOURCE}/conf.py + COMMENT "Generating documentation with Sphinx" + # run this command each time. This way we don't have to keep track of each individual rst file + BuildDocs +) + +add_custom_target(docs ALL DEPENDS ${SPHINX_INDEX_FILE} Doxygen) diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 00000000..d0c3cbf1 --- /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 = source +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/make.bat b/docs/make.bat new file mode 100644 index 00000000..747ffb7b --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=source +set BUILDDIR=build + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.https://www.sphinx-doc.org/ + exit /b 1 +) + +if "%1" == "" goto help + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 00000000..b86ccb7c --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,5 @@ +sphinx +sphinx-book-theme +sphinx-copybutton +sphinx-design +sphinxcontrib-bibtex diff --git a/docs/source/_static/custom.css b/docs/source/_static/custom.css new file mode 100644 index 00000000..c51b21d1 --- /dev/null +++ b/docs/source/_static/custom.css @@ -0,0 +1,41 @@ +.sd-card-img-top { + width: 33% !important; + display: block; + margin-left: auto; + margin-right: auto; + margin-top: 10px; +} + +.download-div { + display: flex; + flex-direction: row; + justify-content: space-around; + margin-bottom: 1rem; +} + +.download-button { + display: inline-block; + padding: 10px 20px; + background-color: #3498db; + color: white; + border: none; + border-radius: 5px; + text-align: center; + text-decoration: none; + font-size: 16px; + cursor: pointer; + transition: background-color 0.3s; +} + +.transparent-image > img { + background-color: unset !important; +} + +.download-button:hover { + background-color: #2980b9; +} + +blockquote { + padding: unset; + border-left: unset; +} \ No newline at end of file diff --git a/docs/source/_static/favicon/favicon.ico b/docs/source/_static/favicon/favicon.ico new file mode 100644 index 00000000..7905e965 Binary files /dev/null and b/docs/source/_static/favicon/favicon.ico differ diff --git a/docs/source/_static/index_api.svg b/docs/source/_static/index_api.svg new file mode 100644 index 00000000..1851b2d7 --- /dev/null +++ b/docs/source/_static/index_api.svg @@ -0,0 +1,97 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_static/index_contribute.svg b/docs/source/_static/index_contribute.svg new file mode 100644 index 00000000..eb06c21c --- /dev/null +++ b/docs/source/_static/index_contribute.svg @@ -0,0 +1,76 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_static/index_getting_started.svg b/docs/source/_static/index_getting_started.svg new file mode 100644 index 00000000..1f3eda8b --- /dev/null +++ b/docs/source/_static/index_getting_started.svg @@ -0,0 +1,66 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_static/index_user_guide.svg b/docs/source/_static/index_user_guide.svg new file mode 100644 index 00000000..b3742e0c --- /dev/null +++ b/docs/source/_static/index_user_guide.svg @@ -0,0 +1,67 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + \ No newline at end of file diff --git a/docs/source/conf.py b/docs/source/conf.py new file mode 100644 index 00000000..29217117 --- /dev/null +++ b/docs/source/conf.py @@ -0,0 +1,75 @@ +# Configuration file for the Sphinx documentation builder. +# +# This file only contains a selection of the most common options. For a full +# list see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +import os +import sys +import datetime +sys.path.insert(0, os.path.abspath('.')) + +# -- Project information ----------------------------------------------------- + +project = 'MUSICA' +copyright = f'2024-{datetime.datetime.now().year}, NCAR/UCAR' +author = 'NCAR/UCAR' + +suffix = '' +# the suffix is required. This is controlled by the dockerfile that builds the docs +release = f'0.0.0' + +# -- General configuration --------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx_copybutton', + 'sphinx_design', + 'sphinxcontrib.bibtex', +] + +bibtex_bibfiles = ['references.bib'] +suppress_warnings = ["bibtex.missing_field"] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = [] + + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'pydata_sphinx_theme' + +html_theme_options = { + "external_links": [], + "github_url": "https://github.com/NCAR/musica", + "navbar_end": ["version-switcher", "navbar-icon-links"], + "pygment_light_style": "tango", + "pygment_dark_style": "monokai" +} + +html_css_files = [ + 'custom.css' +] + +# 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'] + +html_favicon = '_static/favicon/favicon.ico' diff --git a/docs/source/index.rst b/docs/source/index.rst new file mode 100644 index 00000000..e1de8b76 --- /dev/null +++ b/docs/source/index.rst @@ -0,0 +1,54 @@ +.. musica documentation HTML titles +.. +.. # (over and under) for module headings +.. = for sections +.. - for subsections +.. ^ for subsubsections +.. ~ for subsubsubsections +.. " for paragraphs + +================================== +Welcome to MUSICA's documentation! +================================== + +.. grid:: 1 1 2 2 + :gutter: 2 + + .. grid-item-card:: Getting started + :img-top: _static/index_getting_started.svg + :link: getting_started + :link-type: doc + + Check out the getting started guide to build and install musica. + + .. grid-item-card:: User guide + :img-top: _static/index_user_guide.svg + :link: user_guide/index + :link-type: doc + + .. grid-item-card:: API reference + :img-top: _static/index_api.svg + :link: api/index + :link-type: doc + + .. grid-item-card:: Contributors guide + :img-top: _static/index_contribute.svg + :link: contributing/index + :link-type: doc + + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + +.. getting_started +.. user_guide/index +.. api/index +.. contributing/index +.. citing_and_bibliography/index + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`search`