From 64bd07e04b22b9ccd89a9d9b8f9c1536f979de12 Mon Sep 17 00:00:00 2001 From: Maxim Averyanov Date: Thu, 27 Aug 2026 18:44:02 +0200 Subject: [PATCH] The disk images were empty, and the wheel had the old version Both found by looking at what v1.3.0 actually published rather than at what the build said. The .dmg files were 280 KB. The engine is built into a staging directory outside the checkout now - OneDrive holds handles on files in a synced folder - and tools/build_macos.py still looked in dist/, found nothing, printed a warning, and assembled a bundle without it. A bundle that looks finished and does nothing on any machine without a checkout of this repository. It imports the staging path from build_app now instead of repeating it, and refuses outright rather than warning: --no-engine is there for the case where the window alone is what you want. The wheel and sdist said 1.2.0 because the version lived in three places and the bump touched two of them. pyproject reads it from mthread_draw.__version__ now, so there is one. --- pyproject.toml | 8 +++++++- tools/build_macos.py | 32 ++++++++++++++++++++++++++------ 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index f247c60..7b7167e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,10 @@ build-backend = "setuptools.build_meta" [project] name = "mthread-draw" -version = "1.2.0" +# Read from mthread_draw.__version__ rather than written here as well. It was +# written here as well, and 1.3.0 shipped a 1.2.0 wheel because a bump touched +# the two __init__ files and not this line. +dynamic = ["version"] description = "Fast synthetic touch input, gesture recording, replay and image drawing for Android over ADB" readme = "README.md" requires-python = ">=3.9" @@ -54,6 +57,9 @@ Terms = "https://github.com/MAXAWER/MThread-Draw/blob/main/TERMS.md" [project.scripts] mthread = "mthread.cli:main" +[tool.setuptools.dynamic] +version = { attr = "mthread_draw.__version__" } + [tool.setuptools] packages = ["mthread", "mthread_draw"] diff --git a/tools/build_macos.py b/tools/build_macos.py index fef7c76..826f813 100644 --- a/tools/build_macos.py +++ b/tools/build_macos.py @@ -27,6 +27,18 @@ DIST = ROOT / "dist" PROJECT = ROOT / "macos" +# Where build_app.py leaves the engine. Imported rather than repeated: the two +# scripts disagreeing about it is what shipped an empty application. +sys.path.insert(0, str(Path(__file__).resolve().parent)) +from build_app import STAGE # noqa: E402 + + +def find_engine() -> Path | None: + for candidate in (STAGE / "mthread-draw-engine", DIST / "mthread-draw-engine"): + if candidate.is_dir(): + return candidate + return None + BUNDLE_ID = "io.github.maxawer.mthread-draw" @@ -86,7 +98,7 @@ def make_icon() -> Path | None: return icns -def assemble(binary: Path) -> Path: +def assemble(binary: Path, allow_no_engine: bool = False) -> Path: app = DIST / "MThreadDraw.app" if app.exists(): shutil.rmtree(app) @@ -123,13 +135,19 @@ def assemble(binary: Path) -> Path: plist["CFBundleIconFile"] = "MThreadDraw" (contents / "Info.plist").write_bytes(plistlib.dumps(plist)) - engine = DIST / "mthread-draw-engine" - if engine.is_dir(): + engine = find_engine() + if engine is not None: shutil.copytree(engine, contents / "Resources" / "engine") print(f" engine folded in from {engine}") + elif allow_no_engine: + print(" building without the engine, as asked: this bundle only runs " + "from a source checkout") else: - print(" no engine in dist/: build it first with tools/build_app.py, or the " - "app will look for a source checkout") + raise SystemExit( + "no engine found - run tools/build_app.py first. " + "Refusing rather than warning: a bundle without the engine looks " + "finished, weighs 300 KB, and does nothing on a machine that has no " + "checkout of this repository. Pass --no-engine if that is what you want.") size = sum(f.stat().st_size for f in app.rglob("*") if f.is_file()) print(f"built {app} ({size // 1024 // 1024} MB)") @@ -159,13 +177,15 @@ def main() -> int: parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) parser.add_argument("--dmg", action="store_true", help="also build the disk image") + parser.add_argument("--no-engine", action="store_true", + help="build the window alone, for a source checkout") args = parser.parse_args() if sys.platform != "darwin": raise SystemExit("the macOS front end only builds on macOS") DIST.mkdir(exist_ok=True) - app = assemble(build_binary()) + app = assemble(build_binary(), allow_no_engine=args.no_engine) if args.dmg: build_dmg(app) return 0