Skip to content

Commit eab9142

Browse files
committed
Fix semiwrap tools
1 parent adef55a commit eab9142

File tree

11 files changed

+267
-369
lines changed

11 files changed

+267
-369
lines changed

src/semiwrap/tool/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from .__main__ import main

src/semiwrap/tool/__main__.py

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,13 @@
22
import sys
33

44
from .build_dep import BuildDep
5-
from .create_gen import GenCreator
6-
from .create_imports import ImportCreator
7-
from .parse_maven import MavenParser
8-
from .platform_info import PlatformInfo
9-
from .show_override import ShowOverrides
5+
from .create_yaml import GenCreator
6+
from .create_imports import ImportCreator, UpdateInit
107
from .scan_headers import HeaderScanner
118

129

1310
def main():
14-
parser = argparse.ArgumentParser(prog="robotpy-build")
11+
parser = argparse.ArgumentParser(prog="semiwrap")
1512
parent_parser = argparse.ArgumentParser(add_help=False)
1613
subparsers = parser.add_subparsers(dest="cmd")
1714
subparsers.required = True
@@ -21,9 +18,7 @@ def main():
2118
GenCreator,
2219
HeaderScanner,
2320
ImportCreator,
24-
PlatformInfo,
25-
ShowOverrides,
26-
MavenParser,
21+
UpdateInit,
2722
):
2823
cls.add_subparser(parent_parser, subparsers).set_defaults(cls=cls)
2924

@@ -40,8 +35,8 @@ def main():
4035
else:
4136
retval = 0
4237

43-
return retval
38+
sys.exit(retval)
4439

4540

4641
if __name__ == "__main__":
47-
sys.exit(main())
42+
main()

src/semiwrap/tool/build_dep.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import subprocess
22
import sys
3-
4-
from .util import get_setup
3+
import tomli
54

65

76
class BuildDep:
@@ -21,10 +20,9 @@ def add_subparser(cls, parent_parser, subparsers):
2120
return parser
2221

2322
def run(self, args):
24-
s = get_setup()
25-
requirements = s.pyproject.get("build-system", {}).get("requires", [])
26-
requirements.extend(s.setup_kwargs.get("install_requires", ""))
27-
requirements.append("wheel")
23+
with open("pyproject.toml", "rb") as fp:
24+
pyproject = tomli.load(fp)
25+
requirements = pyproject.get("build-system", {}).get("requires", [])
2826

2927
pipargs = [
3028
sys.executable,

src/semiwrap/tool/create_gen.py

Lines changed: 0 additions & 49 deletions
This file was deleted.

src/semiwrap/tool/create_imports.py

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
11
import inspect
22
import posixpath
33
import subprocess
4+
import sys
45
import typing
56
import types
67

8+
from ..pyproject import PyProject
9+
710

811
class ImportCreator:
912
@classmethod
1013
def add_subparser(cls, parent_parser, subparsers):
1114
parser = subparsers.add_parser(
1215
"create-imports",
13-
help="Generate suitable imports for a module",
16+
help="Generate suitable imports for a module. Prefer using update-init",
1417
parents=[parent_parser],
1518
)
1619
parser.add_argument("base", help="Ex: wpiutil")
@@ -35,11 +38,17 @@ def create(self, base: str, compiled: typing.Optional[str], write: bool):
3538
try:
3639
import black
3740
except:
38-
print("Error, The following module is required to run this tool: black")
39-
exit(1)
41+
print(
42+
"Error, The following module is required to run this tool: black",
43+
file=sys.stderr,
44+
)
45+
return 1
4046

4147
if not compiled:
4248
compiled = f"{base}._{base.split('.')[-1]}"
49+
print(f"CHK base={base} compiled={compiled} (auto)")
50+
else:
51+
print(f"CHK base={base} compiled={compiled}")
4352

4453
# TODO: could probably generate this from parsed code, but seems hard
4554
ctx = {}
@@ -51,7 +60,8 @@ def create(self, base: str, compiled: typing.Optional[str], write: bool):
5160
relimport = self._rel(base, compiled)
5261

5362
stmt_compiled = "" if not compiled else f" {compiled}"
54-
begin_stmt = f"# autogenerated by 'robotpy-build create-imports {base}"
63+
begin_stmt = f"# autogenerated by 'semiwrap create-imports {base}"
64+
old_begin_stmt = f"# autogenerated by 'robotpy-build create-imports {base}"
5565

5666
stmt = inspect.cleandoc(
5767
f"""
@@ -77,6 +87,9 @@ def create(self, base: str, compiled: typing.Optional[str], write: bool):
7787

7888
# Find the beginning statement
7989
idx = startidx = fcontent.find(begin_stmt)
90+
if startidx == -1:
91+
idx = startidx = fcontent.find(old_begin_stmt)
92+
8093
if startidx != -1:
8194
for to_find in ("from", "__all__", "[", "]", "\n"):
8295
idx = fcontent.find(to_find, idx)
@@ -99,3 +112,32 @@ def create(self, base: str, compiled: typing.Optional[str], write: bool):
99112

100113
else:
101114
print(content)
115+
116+
117+
class UpdateInit:
118+
@classmethod
119+
def add_subparser(cls, parent_parser, subparsers):
120+
parser = subparsers.add_parser(
121+
"update-init",
122+
help="Updates __init__.py files using settings from tool.semiwrap.update_init",
123+
parents=[parent_parser],
124+
)
125+
return parser
126+
127+
def run(self, args):
128+
project = PyProject().project
129+
130+
if project.update_init is None:
131+
print("[tool.semiwrap].update_init not set", file=sys.stderr)
132+
return 1
133+
134+
ic = ImportCreator()
135+
136+
for to_update in project.update_init:
137+
if " " in to_update:
138+
base, compiled = to_update.split(" ", 1)
139+
else:
140+
base = to_update
141+
compiled = None
142+
143+
ic.create(base, compiled, True)

src/semiwrap/tool/create_yaml.py

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import os
2+
import pathlib
3+
import typing as T
4+
5+
from ..autowrap.generator_data import MissingReporter
6+
from ..cmd.header2dat import make_argparser, generate_wrapper
7+
from ..makeplan import InputFile, makeplan, BuildTarget
8+
9+
10+
class GenCreator:
11+
@classmethod
12+
def add_subparser(cls, parent_parser, subparsers):
13+
parser = subparsers.add_parser(
14+
"create-yaml",
15+
help="Create YAML files from parsed header files",
16+
parents=[parent_parser],
17+
)
18+
parser.add_argument(
19+
"--write", help="Write to files if they don't exist", action="store_true"
20+
)
21+
22+
return parser
23+
24+
def run(self, args):
25+
project_root = pathlib.Path.cwd()
26+
27+
# Problem: if another hatchling plugin sets PKG_CONFIG_PATH to include a .pc
28+
# file, makeplan() will fail to find it, which prevents a semiwrap program
29+
# from consuming those .pc files.
30+
#
31+
# We search for .pc files in the project root by default and add anything found
32+
# to the PKG_CONFIG_PATH to allow that to work. Probably won't hurt anything?
33+
34+
pcpaths: T.Set[str] = set()
35+
for pcfile in project_root.glob("**/*.pc"):
36+
pcpaths.add(str(pcfile.parent))
37+
38+
if pcpaths:
39+
# Add to PKG_CONFIG_PATH so that it can be resolved by other hatchling
40+
# plugins if desired
41+
pkg_config_path = os.environ.get("PKG_CONFIG_PATH")
42+
if pkg_config_path is not None:
43+
os.environ["PKG_CONFIG_PATH"] = os.pathsep.join(
44+
(pkg_config_path, *pcpaths)
45+
)
46+
else:
47+
os.environ["PKG_CONFIG_PATH"] = os.pathsep.join(pcpaths)
48+
49+
plan = makeplan(project_root, missing_yaml_ok=True)
50+
51+
for item in plan:
52+
if not isinstance(item, BuildTarget) or item.command != "header2dat":
53+
continue
54+
55+
# convert args to string so we can parse it
56+
# .. this is weird, but less annoying than other alternatives
57+
# that I can think of?
58+
argv = []
59+
for arg in item.args:
60+
if isinstance(arg, str):
61+
argv.append(arg)
62+
elif isinstance(arg, InputFile):
63+
argv.append(str(arg.path.absolute()))
64+
elif isinstance(arg, pathlib.Path):
65+
argv.append(str(arg.absolute()))
66+
else:
67+
# anything else shouldn't matter
68+
argv.append("ignored")
69+
70+
sparser = make_argparser()
71+
sargs = sparser.parse_args(argv)
72+
73+
reporter = MissingReporter()
74+
75+
generate_wrapper(
76+
name=sargs.name,
77+
src_yml=sargs.src_yml,
78+
src_h=sargs.src_h,
79+
src_h_root=sargs.src_h_root,
80+
dst_dat=None,
81+
dst_depfile=None,
82+
include_paths=sargs.include_paths,
83+
casters={},
84+
pp_defines=sargs.pp_defines,
85+
missing_reporter=reporter,
86+
report_only=True,
87+
)
88+
89+
if reporter:
90+
for name, report in reporter.as_yaml():
91+
report = f"---\n\n{report}"
92+
93+
if args.write:
94+
if not name.exists():
95+
name.parent.mkdir(parents=True, exist_ok=True)
96+
print("Writing", name)
97+
with open(name, "w") as fp:
98+
fp.write(report)
99+
else:
100+
print(name, "already exists!")
101+
102+
print("===", name, "===")
103+
print(report)

0 commit comments

Comments
 (0)