Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,41 @@ jobs:
files: coverage.lcov
token: ${{ secrets.CODECOV_TOKEN }}
verbose: true

docs:
name: 'Build docs'
runs-on: ubuntu-latest
steps:
- name: Checkout source
uses: actions/checkout@v6
with:
fetch-depth: 0

- name: Create micromamba environment
uses: mamba-org/setup-micromamba@main
with:
environment-file: dev-environment.yml
cache-environment: true

- name: Configure CMake
run: |
cmake -Bbuild -DCMAKE_INSTALL_PREFIX=$CONDA_PREFIX

- name: Build with CMake
working-directory: build
run: cmake --build . --parallel 8

- name: Install docs dependencies
run: |
python -m pip install myst-parser sphinx sphinx-book-theme

- name: Build docs
working-directory: docs
run: |
make html

- name: Upload built docs
uses: actions/upload-artifact@v6
with:
name: git2cpp-docs
path: docs/_build/html
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@ __pycache__/
compile_commands.json
serve.log
test/test-results/

docs/_build/
docs/created/
21 changes: 21 additions & 0 deletions .readthedocs.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
version: 2

build:
os: ubuntu-24.04
tools:
python: mambaforge-23.11
jobs:
post_install:
- cmake -Bbuild -DCMAKE_INSTALL_PREFIX=$CONDA_PREFIX
- cd build && make
- python -m pip install myst-parser sphinx sphinx-book-theme
pre_build:
- cd docs && python create_markdown.py

conda:
environment: dev-environment.yml

sphinx:
builder: html
configuration: docs/conf.py
fail_on_warning: true
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,22 @@ See the `README.md` in the `wasm` directory for further details.

The latest `cockle` and JupyterLite `terminal` deployments using `git2cpp` are available at
[https://quantstack.net/git2cpp](https://quantstack.net/git2cpp)

# Documentation

The project documentation is generated from the `git2cpp` help pages. To build the documentation
locally first build `git2cpp` as usual as described above, then install the documentation
dependencies:

```bash
micromamba install myst-parser sphinx sphinx-book-theme
```

and build the documentation:

```bash
cd docs
make html
```

The top-level documentation page will be `docs/_build/html/index.html`
18 changes: 18 additions & 0 deletions docs/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# 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
python create_markdown.py
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
20 changes: 20 additions & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from datetime import date

project = "git2cpp"
author = "QuantStack"
copyright = f"2025-{date.today().year}"

extensions = [
"myst_parser",
]

exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]

html_static_path = []
html_theme = "sphinx_book_theme"
html_theme_options = {
"github_url": "https://github.com/QuantStack/git2cpp",
"home_page_in_toc": True,
"show_navbar_depth": 2,
}
html_title = "git2cpp documentation"
85 changes: 85 additions & 0 deletions docs/create_markdown.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import os
from pathlib import Path
import re
import subprocess


def get_filename(args):
directory = Path("created").joinpath(*args[:-1])
filename = args[-1] + ".md"
return directory / filename


def sanitise_line(line):
# Remove trailing whitespace otherwise the markdown parser can insert an extra \n
line = line.rstrip()

# Replace angular brackets with HTML equivalents.
line = line.replace(r"&", r"&")
line = line.replace(r"<", r"&lt;")
line = line.replace(r">", r"&gt;")

# If there are whitespace characters at the start of the line, replace the first with an &nbsp
# so that it is not discarded by the markdown parser used by the parsed-literal directive.
line = re.sub(r"^\s", r"&nbsp;", line)

return line


# Process a single subcommand, adding new subcommands found to to_process.
def process(args, to_process):
cmd = args + ["--help"]
cmd_string = " ".join(cmd)
filename = get_filename(args)
filename.parent.mkdir(parents=True, exist_ok=True)

print(f"Writing '{cmd_string}' to file {filename}")
p = subprocess.run(cmd, capture_output=True, text=True, check=True)

# Write output markdown file, identifying subcommands at the same time to provide
# links to the subcommand markdown files.
subcommands = []
with open(filename, "w") as f:
f.write(f"({filename})=\n") # Target for links.
f.write(f"# {' '.join(args)}\n")
f.write("\n")
f.write("```{parsed-literal}\n")

in_subcommand_section = False
for line in p.stdout.splitlines():
if in_subcommand_section:
match = re.match(r"^( )([\w\-_]+)(\s+.*)$", line)
if match:
subcommand = match.group(2)
subcommand_filename = get_filename(args + [subcommand])
line = match.group(1) + f"[{subcommand}]({subcommand_filename})" + match.group(3)
subcommands.append(subcommand)
elif line.startswith("SUBCOMMANDS:"):
in_subcommand_section = True

f.write(sanitise_line(line) + "\n")
f.write("```\n")

subcommands.sort()
to_process.extend(args + [subcommand] for subcommand in subcommands)

if len(subcommands) > 0:
# Hidden table of contents for subcommands of this command/subcommand.
f.write("\n")
f.write("```{toctree}\n")
f.write(":hidden:\n")
for subcommand in subcommands:
f.write(f"{args[-1]}/{subcommand}\n")
f.write("```\n")


if __name__ == "__main__":
# Modify the PATH so that git2cpp is found by name, as using a full path will cause the help
# pages to write that full path.
git2cpp_dir = Path(__file__).parent.parent / 'build'
os.environ["PATH"] = f'{git2cpp_dir}{os.pathsep}{os.environ["PATH"]}'

to_process = [["git2cpp"]]
while len(to_process) > 0:
subcommand = to_process.pop(0)
process(subcommand, to_process)
17 changes: 17 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Overview

`git2cpp` is a C++ wrapper of [libgit2](https://libgit2.org/) to provide a command-line interface
(CLI) to `git` functionality. The intended use is in WebAssembly in-browser terminals (the
[cockle](https://github.com/jupyterlite/cockle) and
[JupyterLite terminal](https://github.com/jupyterlite/terminal) projects) but it can be compiled and
used on any POSIX-compliant system.

The Help pages here are generated from the `git2cpp` command and subcommands to show the
functionality that is currently supported. If there are features missing that you would like to use,
please create an issue in the [git2cpp github repository](https://github.com/QuantStack/git2cpp).

```{toctree}
:caption: Help pages
:hidden:
created/git2cpp
```