Files
applepy/applepy.spec
Warezpeddler 3325436017 Initial commit
2026-04-25 23:09:31 +01:00

122 lines
3.6 KiB
Python

# PyInstaller spec: `pip install -e ".[bundle]"` then `pyinstaller applepy.spec`
# Produces dist/applepy (one-folder) with bundled applepy data (JSON, optional compliance trees).
# Run scripts/vendor_compliance_assets.sh before building to embed mSCP + Lynis (not in git).
from pathlib import Path
from PyInstaller.utils.hooks import collect_data_files
# Root of the repo when building; PyInstaller defines SPECPATH (not __file__) for .spec evaluation.
_SPEC_DIR = Path(SPECPATH)
def _mscp_data_files_excluding_generated(mscp: Path) -> list[tuple[str, str]]:
"""
Per-file datas for mSCP: omit ``build/`` (output from generate_guidance on the host) and ``.git``.
Shipping ``build/`` bloats the bundle and, after ``sudo dist/.../applepy``, can leave root-owned
trees that break the next PyInstaller clean of ``dist/applepy``.
"""
prefix = Path("applepy/data/macos_security")
out: list[tuple[str, str]] = []
for p in mscp.rglob("*"):
if not p.is_file():
continue
try:
rel = p.relative_to(mscp)
except ValueError:
continue
parts = rel.parts
if not parts:
continue
if parts[0] == "build" or parts[0] == ".git":
continue
if ".git" in parts:
continue
dest_dir = str(prefix / rel.parent)
out.append((str(p), dest_dir))
return out
def _applepy_datas_excluding_mscp_tree() -> list[tuple[str, str]]:
"""Package data from ``collect_data_files`` minus ``macos_security`` (re-added below, with filters)."""
return [(s, d) for s, d in collect_data_files("applepy") if "macos_security" not in Path(s).parts]
def _optional_mscp_datas() -> list[tuple[str, str]]:
mscp = _SPEC_DIR / "applepy" / "data" / "macos_security"
if not (mscp / "scripts" / "generate_guidance.py").is_file():
return []
return _mscp_data_files_excluding_generated(mscp)
# Lynis and other ``applepy/data`` trees stay on the collect_data_files side; mSCP is merged once here
# without ``.git`` or ``build/`` (avoids bloated bundles and root-owned build dirs after sudo runs).
datas = _applepy_datas_excluding_mscp_tree() + _optional_mscp_datas()
a = Analysis(
["applepy/__main__.py"],
pathex=[],
binaries=[],
datas=datas,
hiddenimports=[
"openpyxl",
"yaml",
"_yaml",
"xlwt",
# mSCP generate_guidance.py (run via runpy in frozen binary): explicit stdlib names as well as the hook module.
"uuid",
"zipfile",
"applepy.pyi_mscp_stdlib",
"applepy.check_progress",
"applepy.checks",
"applepy.checks.mdm.jamf",
"applepy.checks.mdm.kandji",
"applepy.catalog_cache",
"applepy.mscp_audit_parse",
"applepy.checks.fs_posture",
"applepy.checks.plan_extras",
"applepy.checks.privesc",
"applepy.checks.pyobjc_surface",
"applepy.checks.listening_ports",
"plistlib",
"sqlite3",
"objc",
"Foundation",
"AppKit",
],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
)
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
[],
exclude_binaries=True,
name="applepy",
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=False,
console=True,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)
coll = COLLECT(
exe,
a.binaries,
a.datas,
strip=False,
upx=False,
name="applepy",
)