Skip to content

Commit 8da5e59

Browse files
committed
readme edits and workflow renames
1 parent 0b87d3b commit 8da5e59

File tree

8 files changed

+94
-123
lines changed

8 files changed

+94
-123
lines changed

README.md

Lines changed: 94 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -1,161 +1,126 @@
11
# C++/Python Tool Template
22

3-
A reusable template for building a C++ commandline tool with a Python CLI wrapper, complete with GitHub Actions for CI,
4-
Docker release, and Conda release. This template lets you jump straight into implementing a C++ tool without setting
5-
up all the build, test, container, and packaging boilerplate code from scratch.
3+
A reusable template for building a C++ commandline tool (using HTSlib) with a Python CLI wrapper, complete with GitHub
4+
Actions for CI, Docker release, and Conda release. This template lets you jump straight into implementing a C++ tool
5+
without setting up all the build, test, container, and packaging boilerplate code from scratch.
66

77
Template Repo Combines:
8-
- A **C++ executable** (`linecount` - compiled with CMake)
8+
- A **C++ executable** (`aligncount_cpp` - compiled with CMake)
99
- A **Python wrapper** (`aligncount` - installed via pip)
1010
- Built-in **unit tests** (C++ and Python)
1111
- A **multi-stage Dockerfile** (builds, tests, and packages a wheel)
1212
- A **Conda recipe** (creates a cross-platform packages for Linux/macOS)
13-
- GitHub Actions for CI, Docker release, and Conda release
13+
- GitHub Actions for CI, Docker/Conda release, styling, and documentation
1414

1515

16-
## [TODO] How To
16+
## [TODO] How to use this template
1717

1818
---
19-
20-
## Repository Layout
21-
22-
├── CMakeLists.txt
23-
├──.github
24-
│ └── workflows
25-
│ ├── ci.yml
26-
│ ├── conda_release.yml
27-
│ └── docker_release.yml
28-
├── setup.py
29-
├── setup.cfg
30-
├── pyproject.toml
31-
├── src/
32-
│ └── main.cpp ← C++ “linecount” implementation
33-
├── cli/
34-
│ ├── __init__.py
35-
│ └── entrypoint.py ← Python wrapper (“aligncount” console script)
36-
├── tests/
37-
│ ├── cpp/
38-
│ │ └── test_main.cpp ← C++ unit test (Doctest + CTest)
39-
│ └── python/
40-
│ └── test_wrapper.py ← Python unit test for format_output()
41-
├── Dockerfile ← Multi-stage Docker build + test
42-
└── .gitignore
43-
44-
---
45-
46-
## C++ Executable (linecount)
47-
48-
- Source: src/main.cpp
49-
- Build system: CMake (CMakeLists.txt)
50-
- Functionality: Counts non-header lines (simulates an “alignment counter”)
51-
- Unit test: tests/cpp/test_main.cpp using Doctest; run via CTest
52-
53-
To build manually while at repo root:
54-
55-
mkdir build
56-
cd build
57-
cmake .. -DCMAKE_BUILD_TYPE=Release
58-
cmake --build . --parallel $(nproc)
59-
# Now ./linecount is available in build/
60-
./linecount sample.sam
61-
62-
---
63-
64-
## Python Wrapper (aligncount)
65-
19+
## Tool Descriptions
20+
### Python Wrapper (aligncount)
6621
- Source: cli/entrypoint.py
6722
- Entry point: aligncount console script (configured in setup.py)
68-
- Logic:
69-
1. Parses subcommands (count-mapped or count-unmapped)
70-
2. Checks that the input SAM file exists and is non-empty
71-
3. Calls `linecount <path>` and formats output via format_output(cmd, raw_bytes)
72-
23+
- Functionality:
24+
- Parses subcommands (count-mapped or count-unmapped)
25+
- Checks that the input SAM file exists and is non-empty
26+
- Calls `aligncount_cpp -a <path>` and writes to count stdout
27+
### C++ Executable (aligncount_cpp)
28+
- Source: cpp/standalone/source/main.cpp
29+
- Build system: CMake (CMakeLists.txt)
30+
- Functionality: Counts the number of SAM records
31+
---
32+
## Installation
33+
### Build and install the Python Wrapper and the C++ tool
7334
To install in a virtualenv while at repo root:
7435

7536
python3 -m venv venv
7637
source venv/bin/activate
77-
pip install --upgrade pip setuptools scikit-build pytest
38+
pip install --upgrade pip setuptools scikit-build
7839
pip install .
79-
# Now you have:
80-
# - linecount (C++ binary, in venv/bin)
81-
# - aligncount (Python wrapper, in venv/bin)
82-
83-
Run the wrapper (just counts file lines that don't start with `@`):
8440

85-
aligncount count-mapped -i sample.sam
86-
aligncount count-unmapped -i sample.sam
41+
Now you have:
42+
- aligncount_cpp (C++ binary, in venv/bin)
43+
- aligncount (Python wrapper, in venv/bin)
8744

88-
---
89-
90-
## Unit Tests
45+
Run the wrapper (counts the number of SAM records in a file):
9146

92-
### C++ Tests
93-
94-
- Framework: Doctest (fetched via ExternalProject_Add in CMake)
95-
- Test file: tests/cpp/test_main.cpp
96-
- Run:
97-
98-
cd build
99-
ctest --output-on-failure
47+
aligncount count-mapped -a sample.sam
48+
aligncount count-unmapped -a sample.sam
10049

101-
### Python Tests
102-
103-
- Framework: pytest
104-
- Test file: tests/python/test_wrapper.py
105-
- Run:
106-
107-
source venv/bin/activate
108-
pytest -q
109-
110-
---
111-
112-
## Dockerfile
50+
Note, the installation command implicitly builds the C++ tool via scikit-build/cmake. If you want to
51+
install the Python Wrapper by itself do (does not install aligncount_cpp):
52+
53+
python3 -m venv venv
54+
pip install --upgrade pip setuptools
55+
cd cli
56+
pip install .
11357

58+
### Dockerfile
11459
A multi-stage Dockerfile builds and tests everything, then produces a minimal runtime image:
115-
116-
1. Builder stage (ubuntu:22.04):
60+
1. Builder stage:
11761
- Installs build-time dependencies (CMake, Git, Python dev headers, pip)
118-
- Compiles C++ (linecount) and runs CTest
119-
- Builds a Python wheel (bundles linecount + aligncount)
120-
121-
2. Final stage (ubuntu:22.04):
62+
- Compiles C++ (aligncount_cpp) and runs CTest
63+
- Builds a Python wheel (bundles aligncount_cpp + aligncount)
64+
2. Final stage:
12265
- Installs runtime dependencies (Python, pip)
123-
- Installs the wheel (placing linecount and aligncount into /usr/local/bin)
124-
- Runs the Python unit test (pytest test_wrapper.py)
66+
- Installs the wheel (placing aligncount_cpp and aligncount into /usr/local/bin)
67+
- Runs the Python wrapper unit tests
12568
- Sets ENTRYPOINT ["aligncount"]
12669

12770
Build and test in one command:
12871

129-
docker build -t your-org/aligncount-demo:latest .
72+
docker build -t aligncount:latest .
13073

13174
Run:
13275

133-
docker run --rm your-org/aligncount-demo:latest --help
76+
docker run --rm aligncount:latest --help
13477

135-
---
13678

137-
## Conda-Build Recipe
79+
### Manually build the C++ tool aligncount_cpp
80+
To build manually while at repo root:
13881

139-
The `conda-recipe/meta.yaml` contains instructions for the conda-build command to create the conda package for different
140-
platforms, skipping windows. The recipe expects certain environment variables to be set, which are set by the GitHub
141-
action `conda_release.yml`. The expected environment variables are:
82+
mkdir build
83+
cd build
84+
cmake ../cpp/standalone -DCMAKE_BUILD_TYPE=Release
85+
cmake --build .
14286

143-
```
144-
REPO_NAME # Name of the repo, e.g. cpp-python-tool-template
145-
VERSION # Tool version, e.g. 0.0.1
146-
TAR_URL # URL to the repo archive, e.g. https://github.com/user/foo/archive/refs/tags/v0.0.1.tar.gz
147-
SHA256 # SHA256 checksum of the repo archive
148-
REPO_HOME # URL to the repo home, e.g. https://github.com/user/foo
149-
```
87+
Now you have aligncount_cpp available in the build folder. Run the tool to counts SAM records:
88+
89+
./aligncount -a sample.sam
15090

15191
---
92+
## Unit Tests
15293

153-
## GitHub Actions
94+
### C++ Tests
95+
To run the C++ tool tests at repo root do:
96+
97+
cmake -S cpp/test -B build/test
98+
cmake --build build/test
99+
CTEST_OUTPUT_ON_FAILURE=1 cmake --build build/test --target test
100+
101+
### Python Tests
102+
To run the python wrapper tests at repo root do:
154103

155-
### .github/workflows/ci.yml
104+
export PYTHONPATH="$PWD/cli:${PYTHONPATH}"
105+
pytest tests
156106

157-
This workflow is triggered whenever something is commited to the main branch. It builds the tool and runs the unit tests.
107+
The export command is required if the wrapper is not installed.
158108

109+
---
110+
## GitHub Action Workflows
111+
112+
### On new tag releases:
113+
- `.github/workflows/conda_release.yml` Creates and publishes a conda package for various platforms.
114+
- `.github/workflows/release_release.yml` Compiles and publishes the Dockerfile to docker hub.
115+
- `.github/workflows/cpp_documentation.yml` Builds and publishes documentation for the C++ tool.
116+
### On commits or pull requests to main/master branch:
117+
- `.github/workflows/cpp_wrapper_ci.yml` Builds, installs, and tests the C++ tool and wrapper on ubuntu.
118+
- `.github/workflows/cpp_install.yml` Builds, installs, and tests the C++ tool on ubuntu.
119+
- `.github/workflows/cpp_macos.yml` Builds and tests the C++ tool on MacOS.
120+
- `.github/workflows/cpp_standalone.yml` Builds the C++ tool on ubuntu.
121+
- `.github/workflows/cpp_ubuntu.yml` Tests the C++ tool on ubuntu.
122+
- `.github/workflows/cpp_style.yml` Checks C++ and CMake source style.
123+
---
159124
### .github/workflows/docker_release.yml
160125

161126
This workflow is triggered whenever a new tag for the repo is released. It builds the docker image for linux/amd64
@@ -174,20 +139,26 @@ e.g. cpp-python-tool-template.
174139
The workflow assumes your anaconda username and token are stored as repository secrets under `ANACONDA_USER`
175140
and `ANACONDA_TOKEN`.
176141

177-
## .gitignore
142+
---
143+
## Conda-Build Recipe
178144

179-
Included patterns to ignore:
180-
- macOS system files (.DS_Store, ._*)
181-
- CMake and CLion build directories (build/, cmake-build-debug/, _skbuild/, wheelhouse/)
182-
- Python venvs and caches (venv/, __pycache__/, .pytest_cache/, *.egg-info/)
183-
- IDE files (PyCharm/CLion .idea/, *.iml)
184-
- Conda build artifacts (conda-bld/, pkgs/)
145+
The `conda-recipe/meta.yaml` contains instructions for the conda-build command to create the conda package that
146+
contains the C++ tool and the python wrapper. The recipe expects certain environment variables to be set, which
147+
are set by the GitHub action `conda_release.yml`. The expected environment variables are:
185148

149+
```
150+
REPO_NAME # Name of the repo, e.g. cpp-python-tool-template
151+
VERSION # Tool version, e.g. 0.0.1
152+
TAR_URL # URL to the repo archive, e.g. https://github.com/user/foo/archive/refs/tags/v0.0.1.tar.gz
153+
SHA256 # SHA256 checksum of the repo archive
154+
REPO_HOME # URL to the repo home, e.g. https://github.com/user/foo
155+
```
186156
---
157+
## Miscellaneous Notes
187158

159+
---
188160
## What’s Next
189161

190-
- Customize: Adapt this template to use the https://github.com/filipdutescu/modern-cpp-template, and include htslib
191-
- Write a how-to section detailing how to clone the repo and make any necessary edits
162+
- See github issues for this repo
192163

193164
With this template, you have a fully tested building, packaging, and distribution pipeline out of the box. Happy coding!

0 commit comments

Comments
 (0)