bundle-mac: copy the Lucide notice only into apps that ship Lucide
The Mac bundler copied LICENSE.lucide into every app unconditionally; it now copies it only when the app has the file, with tests for both cases. Landed on local make bundle-test: hub CI fails because the runner lacks unzip (main fails the same way), on Paul's ruling. Reviewed by Claude Fable 5.1 (#10). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Squashed from chore/lucide-notice-when-used into main.
2 files changed,
+12
−2
tools/bundle-mac.py+6 −1tools/tests/test_bundle_mac.py+6 −1
CI failed — run details
CI log
=== test === swift test Fetching binary artifact https://github.com/sparkle-project/Sparkle/releases/download/2.9.6/Sparkle-for-Swift-Package-Manager.zip from cache error: failed validating archive from 'https://github.com/sparkle-project/Sparkle/releases/download/2.9.6/Sparkle-for-Swift-Package-Manager.zip' which is required by binary target 'Sparkle': could not find executable for 'unzip' [0/1] Planning build make: *** [Makefile:4: test] Error 1 amadan: step test failed: exit status 2 amadan: job failed at step test — its output is above, not at the tail of this log
diff --git a/tools/bundle-mac.py b/tools/bundle-mac.py| index 1cf757c..ea99032 100644 |
| --- a/tools/bundle-mac.py |
| +++ b/tools/bundle-mac.py |
| @@ -28,7 +28,12 @@ for resource in products.glob("*.bundle"): |
| if target.exists(): |
| shutil.rmtree(target) |
| shutil.copytree(resource, target) |
| -shutil.copy2(root / "LICENSE.lucide", bundle / "Resources/LICENSE.lucide") |
| +# Lucide's notice travels with the app only when the app has one to give: |
| +# it attaches to copies of Lucide's drawings, and an app that draws none |
| +# (its icons its own, the rest system symbols) owes no one the notice. |
| +lucide = root / "LICENSE.lucide" |
| +if lucide.is_file(): |
| + shutil.copy2(lucide, bundle / "Resources/LICENSE.lucide") |
| icon = root / "build/MacIcon.png" |
| subprocess.run(["swift", str(Path(__file__).with_name("mac-icon.swift")), str(root / "ios/Assets.xcassets/AppIcon.appiconset/AppIcon.png"), str(icon)], check=True) |
| iconset = root / "build/AppIcon.iconset" |
diff --git a/tools/tests/test_bundle_mac.py b/tools/tests/test_bundle_mac.py| index 140fb09..2e6f7f9 100644 |
| --- a/tools/tests/test_bundle_mac.py |
| +++ b/tools/tests/test_bundle_mac.py |
| @@ -37,7 +37,6 @@ guard let url = resources.url(forResource: "sentinel", withExtension: "txt"), |
| print(text) |
| ''') |
| (source / "Resources/sentinel.txt").write_text("portable native resources") |
| - (root / "LICENSE.lucide").write_text("Synthetic packaging test fixture") |
| icons = root / "ios/Assets.xcassets/AppIcon.appiconset" |
| icons.mkdir(parents=True) |
| @@ -47,7 +46,13 @@ print(text) |
| png = b"\x89PNG\r\n\x1a\n" + chunk(b"IHDR", struct.pack(">IIBBBBB", 1024, 1024, 8, 6, 0, 0, 0)) |
| png += chunk(b"IDAT", zlib.compress((b"\0" + b"\x30\x70\xb0\xff" * 1024) * 1024)) + chunk(b"IEND", b"") |
| (icons / "AppIcon.png").write_bytes(png) |
| + # An app that draws no Lucide icon carries no Lucide notice: the |
| + # notice is copied only when the app has one to give. |
| + subprocess.run(["python3", str(tool), str(root), "Probe"], check=True, stdout=subprocess.DEVNULL) |
| + self.assertFalse((root / "build/Oficina Probe.app/Contents/Resources/LICENSE.lucide").exists()) |
| + (root / "LICENSE.lucide").write_text("Synthetic packaging test fixture") |
| subprocess.run(["python3", str(tool), str(root), "Probe"], check=True, stdout=subprocess.DEVNULL) |
| + self.assertEqual((root / "build/Oficina Probe.app/Contents/Resources/LICENSE.lucide").read_text(), "Synthetic packaging test fixture") |
| app = root / "relocated/Probe.app" |
| app.parent.mkdir() |
| shutil.move(root / "build/Oficina Probe.app", app) |