Skip to content

Commit bc8685e

Browse files
committed
Fix semiwrap tools
1 parent a8c93a7 commit bc8685e

File tree

10 files changed

+245
-347
lines changed

10 files changed

+245
-347
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: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,12 @@
33

44
from .build_dep import BuildDep
55
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
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: 5 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,10 @@ 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", [])
26+
requirements.extend(pyproject.get("project", {}).get("dependencies", []))
2827

2928
pipargs = [
3029
sys.executable,

src/semiwrap/tool/create_gen.py

Lines changed: 81 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1-
from os.path import exists
1+
import os
2+
import pathlib
3+
import typing as T
24

3-
from .util import get_setup
45
from ..autowrap.generator_data import MissingReporter
6+
from ..cmd.header2dat import make_argparser, generate_wrapper
7+
from ..makeplan import InputFile, makeplan, BuildTarget
58

69

710
class GenCreator:
@@ -15,35 +18,85 @@ def add_subparser(cls, parent_parser, subparsers):
1518
parser.add_argument(
1619
"--write", help="Write to files if they don't exist", action="store_true"
1720
)
18-
parser.add_argument("--strip-prefixes", action="append")
1921

2022
return parser
2123

2224
def run(self, args):
23-
pfx = ""
24-
if args.strip_prefixes:
25-
pfx = "strip_prefixes:\n- " + "\n- ".join(args.strip_prefixes) + "\n\n"
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)
2672

27-
s = get_setup()
28-
for wrapper in s.wrappers:
2973
reporter = MissingReporter()
30-
wrapper.on_build_gen("", reporter)
31-
32-
nada = True
33-
for name, report in reporter.as_yaml():
34-
report = f"---\n\n{pfx}{report}"
35-
36-
nada = False
37-
if args.write:
38-
if not exists(name):
39-
print("Writing", name)
40-
with open(name, "w") as fp:
41-
fp.write(report)
42-
else:
43-
print(name, "already exists!")
44-
45-
print("===", name, "===")
46-
print(report)
47-
48-
if nada:
49-
print("Nothing to do!")
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+
print("Writing", name)
96+
with open(name, "w") as fp:
97+
fp.write(report)
98+
else:
99+
print(name, "already exists!")
100+
101+
print("===", name, "===")
102+
print(report)

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)

0 commit comments

Comments
 (0)