Skip to content

Commit fbcbf3b

Browse files
committed
nox manage cargo-binstall
1 parent 4481ab3 commit fbcbf3b

File tree

4 files changed

+177
-8
lines changed

4 files changed

+177
-8
lines changed

docs/README.md

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,11 @@ This folder is only for generating the documentation about CLI and runtime permi
44
Please [visit our website][gh-pages] to see generated documentation.
55

66
[gh-pages]: https://cpp-linter.github.io/cpp-linter-rs
7-
[uv]: https://docs.astral.sh/uv/
87

98
## Build and inspect locally
109

1110
To view the documentation locally, some software needs to be installed.
12-
This project's dependencies are managed with a tool called [`uv`][uv].
13-
So, [`uv`][uv] is the only software that needs to be manually installed beforehand.
1411

15-
After [`uv`][uv] is installed, building (and viewing) the docs is as simple as
16-
17-
```shell
18-
uvx nox -s docs -- --open
19-
```
12+
> [!IMPORTANT]
13+
> Please review of [Contributing doc](docs/getting-started.md)
14+
> which contains instruction about building and inspecting docs.

docs/docs/getting-started.md

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# Contributing
2+
3+
This project requires the following tools installed:
4+
5+
- :simple-rust: [rust](https://rustup.rs/)
6+
- :simple-uv: [`uv` (Python Project management tool)](https://docs.astral.sh/uv/)
7+
8+
## Getting started
9+
10+
After checking out the repo locally, use
11+
12+
```sh
13+
uv sync
14+
```
15+
16+
This creates a venv at ".venv/" in repo root (if it doesn't exist).
17+
It also installs dev dependencies like `pre-commit`, `nox`, `ruff`, and `mypy`.
18+
19+
See [`uv sync` docs](https://docs.astral.sh/uv/reference/cli/#uv-sync)
20+
for more detailed usage.
21+
22+
<!-- markdownlint-disable MD028 -->
23+
24+
> [!TIP]
25+
> To register the pre-commit hooks, use:
26+
>
27+
> ```shell
28+
> uv run pre-commit install
29+
> ```
30+
31+
### Cargo-managed binaries
32+
33+
The tasks run with `nox` will ensure cargo-managed binaries are installed as needed.
34+
35+
### Running tests
36+
37+
Use nox to run tests:
38+
39+
```sh
40+
uv run nox -s test
41+
```
42+
43+
Different test profiles are still defined in .config/nextest.toml.
44+
The above command uses the "default" profile, but to mimic the CI, use:
45+
46+
```sh
47+
uv run nox -s test -- --profile ci
48+
```
49+
50+
To generate a coverage report:
51+
52+
```sh
53+
uv run nox -s llvm-cov -- --open
54+
```
55+
56+
The `-- --open` part is optional. It opens the built coverage report in your default browser.
57+
58+
The uploaded codecov report is generated with
59+
60+
```sh
61+
uv run nox -s lcov
62+
```
63+
64+
### Generating docs
65+
66+
To view the docs locally, use
67+
68+
```sh
69+
uv run nox -s docs -- --open
70+
```
71+
72+
The `-- --open` part is optional. It opens the built docs in your default browser.
73+
74+
In CI, docs are built using
75+
76+
```sh
77+
uv run nox -s docs-build
78+
```

docs/mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ nav:
1212
- python.md
1313
- node.md
1414
- changelog.md
15+
- getting-started.md
1516
- other-licenses.md
1617

1718
theme:

noxfile.py

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import logging
2+
import platform
3+
import re
24
import sys
35
import nox
46

@@ -10,6 +12,73 @@
1012

1113
nox.options.default_venv_backend = "uv"
1214

15+
BIN_STALL_CARGO = re.compile(r"^([^\s]+)\s([^:]+):")
16+
CARGO_BINSTALL = "cargo-binstall"
17+
18+
19+
class CargoInstaller:
20+
def __init__(self, session: nox.Session):
21+
cargo_installed: str | None = session.run(
22+
"cargo", "install", "--list", external=True, silent=True
23+
)
24+
assert cargo_installed is not None, "Is rust cargo installed?"
25+
cargo_bins: dict[str, str] = {}
26+
for line in cargo_installed.splitlines():
27+
found = BIN_STALL_CARGO.match(line)
28+
if found is not None:
29+
name, version = found.groups()
30+
cargo_bins.setdefault(name, version)
31+
self.cargo_bins = cargo_bins
32+
self.cargo_install_cmd: tuple[str, ...] = ("cargo", "install")
33+
34+
if CARGO_BINSTALL in cargo_bins:
35+
ci_logger.info(
36+
"Found %s: %s" % (CARGO_BINSTALL, cargo_bins[CARGO_BINSTALL])
37+
)
38+
self.cargo_install_cmd = ("cargo", "binstall", "-y")
39+
else:
40+
ci_logger.info("Installing %s" % CARGO_BINSTALL)
41+
match platform.system():
42+
case "Windows":
43+
one_liner = """Set-ExecutionPolicy Unrestricted -Scope Process; iex (iwr "https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.ps1").Content"""
44+
session.run(*one_liner.split(), external=True)
45+
case "Linux" | "Darwin":
46+
one_liner = "curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash"
47+
session.run(*one_liner.split(), external=True)
48+
case _:
49+
session.run(
50+
*self.cargo_install_cmd,
51+
CARGO_BINSTALL,
52+
"--locked",
53+
external=True,
54+
)
55+
56+
def check_install(self, req: str, session: nox.Session):
57+
"""Use cargo to ensure `req` is installed.
58+
59+
Parameters:
60+
req: The package name (on crates.io) to check and install.
61+
Supports explicit version in the form
62+
63+
Typically this is the project's name as published on crates.io.
64+
"""
65+
66+
ver = None
67+
if "@" in req:
68+
req, ver = req.split("@", 1)[:2]
69+
70+
def install():
71+
ci_logger.info("Installing %s" % req)
72+
dep = req if not ver else f"{req}@{ver}"
73+
session.run(*self.cargo_install_cmd, dep, "--locked", external=True)
74+
75+
installed = False
76+
if req in self.cargo_bins:
77+
ci_logger.info("Found %s %s" % (req, self.cargo_bins[req]))
78+
installed = True
79+
if ver or not installed:
80+
install()
81+
1382

1483
def uv_sync(session: nox.Session, *args: str):
1584
session.run_install(
@@ -79,6 +148,13 @@ def test(session: nox.Session):
79148
Otherwise, the default profile is used.
80149
"""
81150
uv_sync(session, "--group", "test")
151+
installer = CargoInstaller(session)
152+
for req in [
153+
"cargo-llvm-cov",
154+
"cargo-nextest",
155+
]:
156+
installer.check_install(req, session)
157+
82158
session.run(
83159
"cargo",
84160
"llvm-cov",
@@ -102,6 +178,8 @@ def test_clean(session: nox.Session):
102178
This is useful if coverage data needs to be
103179
completely refreshed.
104180
"""
181+
installer = CargoInstaller(session)
182+
installer.check_install("cargo-llvm-cov", session)
105183
session.run("cargo", "llvm-cov", "clean", external=True)
106184

107185

@@ -114,6 +192,8 @@ def llvm_cov(session: nox.Session):
114192
115193
Otherwise, the default profile is used.
116194
"""
195+
installer = CargoInstaller(session)
196+
installer.check_install("cargo-llvm-cov", session)
117197
session.run(
118198
"cargo",
119199
"llvm-cov",
@@ -135,6 +215,9 @@ def pretty_cov(session: nox.Session):
135215
136216
Otherwise, the default profile is used.
137217
"""
218+
installer = CargoInstaller(session)
219+
for req in ["cargo-llvm-cov", "llvm-cov-pretty"]:
220+
installer.check_install(req, session)
138221
session.run(
139222
"cargo",
140223
"llvm-cov",
@@ -156,6 +239,8 @@ def lcov(session: nox.Session):
156239
Useful for codecov uploads and VSCode extensions
157240
like "Coverage Gutters".
158241
"""
242+
installer = CargoInstaller(session)
243+
installer.check_install("cargo-llvm-cov", session)
159244
session.run(
160245
"cargo",
161246
"llvm-cov",
@@ -177,3 +262,13 @@ def lint(session: nox.Session):
177262
"cargo", "clippy", "--allow-staged", "--allow-dirty", "--fix", external=True
178263
)
179264
session.run("cargo", "fmt", external=True)
265+
266+
267+
@nox.session(python=False)
268+
def install(session: nox.Session):
269+
"""Install necessary software in global env"""
270+
271+
installer = CargoInstaller(session)
272+
273+
for req in session.posargs:
274+
installer.check_install(req, session)

0 commit comments

Comments
 (0)