Skip to content

Commit e65c527

Browse files
authored
Merge pull request #181 from robotpy/scan-headers
Add CI check to ensure that all headers are ignored or wrapped
2 parents c14a487 + ce424e8 commit e65c527

File tree

10 files changed

+93
-2
lines changed

10 files changed

+93
-2
lines changed

.github/workflows/dist.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,10 @@ jobs:
212212
SCCACHE_WEBDAV_USERNAME: ${{ secrets.WPI_ARTIFACTORY_USERNAME }}
213213
SCCACHE_WEBDAV_PASSWORD: ${{ secrets.WPI_ARTIFACTORY_TOKEN }}
214214

215+
- name: Ensure all headers are accounted for
216+
run: |
217+
python -m devtools ci scan-headers
218+
215219
- uses: actions/upload-artifact@v4
216220
with:
217221
name: "pypi-meson-${{ runner.os }}-${{ runner.arch }}-${{ matrix.python_version }}"

devtools/__main__.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,26 @@ def develop(ctx: Context, package: str):
6161
project.develop()
6262

6363

64+
@main.command()
65+
@click.pass_obj
66+
def scan_headers(ctx: Context):
67+
"""Run scan-headers on all projects"""
68+
ok = True
69+
for project in ctx.subprojects.values():
70+
if project.is_semiwrap_project():
71+
with ctx.handle_exception(f"scan-headers {project.name}"):
72+
if not project.scan_headers():
73+
print(
74+
"- ERROR:",
75+
project.pyproject_path,
76+
"does not wrap/ignore every header!",
77+
)
78+
ok = False
79+
80+
if not ok:
81+
sys.exit(1)
82+
83+
6484
@main.command
6585
@click.argument("package", required=False)
6686
@click.pass_obj

devtools/ci.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,3 +128,27 @@ def build_meson_wheels(ctx: Context, no_test: bool, cross: T.Optional[str]):
128128
)
129129
if not no_test:
130130
project.test(install_requirements=True)
131+
132+
133+
@ci.command()
134+
@click.pass_obj
135+
def scan_headers(ctx: Context):
136+
"""Run scan-headers on all projects"""
137+
ok = True
138+
for project in ctx.subprojects.values():
139+
if project.is_semiwrap_project():
140+
if not project.cfg.ci_scan_headers:
141+
print("- Skipping", project.name, file=sys.stderr)
142+
continue
143+
144+
with ctx.handle_exception(f"scan-headers {project.name}"):
145+
if not project.scan_headers():
146+
print(
147+
"- ERROR:",
148+
project.pyproject_path,
149+
"does not wrap/ignore every header!",
150+
)
151+
ok = False
152+
153+
if not ok:
154+
sys.exit(1)

devtools/config.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ class SubprojectConfig:
1313
#: Whether this should be built on roborio or not
1414
roborio: bool
1515

16+
#: Whether `ci scan-headers` should include this project
17+
ci_scan_headers: bool = True
18+
1619

1720
@dataclasses.dataclass
1821
class Parameters:

devtools/subproject.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,19 @@ def develop(self):
4848
def uninstall(self):
4949
run_pip("uninstall", "-y", self.pyproject_name)
5050

51+
def scan_headers(self):
52+
"""Returns True if no headers found or False if missing headers were found"""
53+
result = run_cmd(
54+
sys.executable,
55+
"-m",
56+
"semiwrap",
57+
"scan-headers",
58+
"--check",
59+
cwd=self.path,
60+
check=False,
61+
)
62+
return result.returncode == 0
63+
5164
def update_init(self):
5265
run_cmd(
5366
sys.executable,

devtools/util.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,9 @@ def parse_input(value: typing.Any, spec: typing.Type[T], fname) -> T:
4444
raise _convert_validation_error(fname, ve) from None
4545

4646

47-
def run_cmd(*args: str, cwd=None):
47+
def run_cmd(*args: str, cwd=None, check=True):
4848
print("+", shlex.join(args))
49-
subprocess.check_call(args, cwd=cwd)
49+
return subprocess.run(args, cwd=cwd, check=check)
5050

5151

5252
def run_pip(*args: str, cwd=None):

rdev.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,10 @@ roborio = true
9898
py_version = "wrapper"
9999
roborio = true
100100

101+
# practicality over purity - this is because we use a static
102+
# library that only exists at build time
103+
ci_scan_headers = false
104+
101105
[subprojects."robotpy-apriltag"]
102106
py_version = "wrapper"
103107
roborio = true

subprojects/robotpy-cscore/pyproject.toml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,22 @@ update_init = [
7878
"cscore"
7979
]
8080

81+
scan_headers_ignore = [
82+
# Only wrapping the C++ API
83+
"cscore.h",
84+
"cscore_c.h",
85+
"cscore_raw.h",
86+
87+
# Not needed
88+
"cameraserver/CameraServerShared.h",
89+
"vision/VisionPipeline.h",
90+
"vision/VisionRunner.h",
91+
92+
# Not wrapping OpenCV or cvnp
93+
"cvnp/*",
94+
"opencv2/*"
95+
]
96+
8197
[tool.semiwrap.extension_modules."cscore._cscore"]
8298
name = "cscore"
8399

subprojects/robotpy-wpilib/pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ LiveWindow = "frc/livewindow/LiveWindow.h"
183183
# frc/motorcontrol
184184
DMC60 = "frc/motorcontrol/DMC60.h"
185185
Jaguar = "frc/motorcontrol/Jaguar.h"
186+
Koors40 = "frc/motorcontrol/Koors40.h"
186187
MotorControllerGroup = "rpy/MotorControllerGroup.h"
187188
NidecBrushless = "frc/motorcontrol/NidecBrushless.h"
188189
PWMMotorController = "frc/motorcontrol/PWMMotorController.h"
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
3+
classes:
4+
frc::Koors40:
5+
methods:
6+
Koors40:

0 commit comments

Comments
 (0)