-
Notifications
You must be signed in to change notification settings - Fork 66
Expand file tree
/
Copy pathpyinstaller.spec
More file actions
137 lines (117 loc) · 5.4 KB
/
Copy pathpyinstaller.spec
File metadata and controls
137 lines (117 loc) · 5.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# -*- mode: python ; coding: utf-8 -*-
# Run `poetry run pyinstaller pyinstaller.spec` to generate the binary.
# Set the env var `CYCODE_ONEDIR_MODE` to generate a single directory instead of a single file.
import os
import platform
import re
import subprocess
import sys
_IS_WINDOWS = platform.system() == 'Windows'
_INIT_FILE_PATH = os.path.join('cycode', '__init__.py')
_CODESIGN_IDENTITY = os.environ.get('APPLE_CERT_NAME') or None
_ONEDIR_MODE = os.environ.get('CYCODE_ONEDIR_MODE') is not None
# save the prev content of __init__ file
with open(_INIT_FILE_PATH, 'r', encoding='UTF-8') as file:
prev_content = file.read()
import dunamai as _dunamai
VERSION_PLACEHOLDER = '0.0.0'
CLI_VERSION = _dunamai.get_version('cycode', first_choice=_dunamai.Version.from_git).serialize(
metadata=False, bump=True, style=_dunamai.Style.Pep440
)
# write the version from Git Tag to freeze the value and don't depend on Git
with open(_INIT_FILE_PATH, 'w', encoding='UTF-8') as file:
file.write(prev_content.replace(VERSION_PLACEHOLDER, CLI_VERSION))
# Top-level subapp modules are loaded lazily via importlib.import_module() in
# cycode/cli/app.py to keep startup fast on hot paths (e.g. ai-guardrails scan).
# PyInstaller's static analyzer can't see those imports, so list them explicitly.
_hiddenimports = [
'cycode.cli.apps.ai_guardrails',
'cycode.cli.apps.ai_remediation',
'cycode.cli.apps.auth',
'cycode.cli.apps.configure',
'cycode.cli.apps.ignore',
'cycode.cli.apps.report',
'cycode.cli.apps.report_import',
'cycode.cli.apps.scan',
'cycode.cli.apps.status',
'cycode.cli.apps.mcp',
]
# truststore is imported lazily inside cycode/cli/utils/trust_store.py, and it picks its platform
# backend behind a sys.platform branch. Only the current platform's backend actually resolves.
if sys.version_info >= (3, 10):
_hiddenimports += ['truststore', 'truststore._windows', 'truststore._macos', 'truststore._openssl']
def _build_windows_version_info(version: str):
"""Windows-only VERSIONINFO resource."""
from PyInstaller.utils.win32.versioninfo import (
FixedFileInfo,
StringFileInfo,
StringStruct,
StringTable,
VarFileInfo,
VarStruct,
VSVersionInfo,
)
numbers = [int(part) for part in re.match(r'\d+(?:\.\d+)*', version).group(0).split('.')]
filevers = tuple((numbers + [0, 0, 0, 0])[:4])
return VSVersionInfo(
ffi=FixedFileInfo(filevers=filevers, prodvers=filevers),
kids=[
StringFileInfo(
[
StringTable(
'040904B0', # US English, Unicode
[
StringStruct('CompanyName', 'Cycode Ltd.'),
StringStruct('FileDescription', 'Cycode CLI'),
StringStruct('FileVersion', version),
StringStruct('InternalName', 'cycode-cli'),
StringStruct('OriginalFilename', 'cycode-cli.exe'),
StringStruct('ProductName', 'Cycode CLI'),
StringStruct('ProductVersion', version),
StringStruct('LegalCopyright', 'Copyright (c) Cycode Ltd.'),
StringStruct('Comments', 'MIT licensed. https://github.com/cycodehq/cycode-cli'),
],
)
]
),
VarFileInfo([VarStruct('Translation', [0x0409, 1200])]),
],
)
a = Analysis(
scripts=['cycode/cli/main.py'],
excludes=['tests', 'setuptools', 'pkg_resources'],
hiddenimports=_hiddenimports,
)
if platform.system() == 'Darwin':
# cryptography ships no macOS x86_64 wheel since 46.0.4, so on Intel it is built from source and
# dynamically links Homebrew's OpenSSL 3 (it needs symbols like `SSL_get0_group_name`, added in
# OpenSSL 3.2). PyInstaller also collects the older OpenSSL 3.0.x that ships with the
# setup-python toolcache Python; both land at the same destination name and the toolcache copy
# wins the dedup, which breaks `import cryptography` at runtime. Drop every collected
# libssl/libcrypto and inject Homebrew's, which satisfies both consumers.
try:
openssl_lib = os.path.join(subprocess.check_output(['brew', '--prefix', 'openssl@3'], text=True).strip(), 'lib')
a.binaries = [b for b in a.binaries if 'libssl' not in b[0] and 'libcrypto' not in b[0]]
for name in ('libssl.3.dylib', 'libcrypto.3.dylib'):
a.binaries.append((name, os.path.join(openssl_lib, name), 'BINARY'))
print(f'Replaced collected OpenSSL dylibs with Homebrew ones from {openssl_lib}')
except Exception as e:
print(f'Warning: Could not override OpenSSL binaries: {e}')
exe_args = [PYZ(a.pure), a.scripts, a.binaries, a.datas]
if _ONEDIR_MODE:
exe_args = [PYZ(a.pure), a.scripts]
exe = EXE(
*exe_args,
name='cycode-cli',
exclude_binaries=bool(_ONEDIR_MODE),
target_arch=None,
codesign_identity=_CODESIGN_IDENTITY,
entitlements_file='entitlements.plist',
icon='images/cycode.ico' if _IS_WINDOWS else None,
version=_build_windows_version_info(CLI_VERSION) if _IS_WINDOWS else None,
)
if _ONEDIR_MODE:
coll = COLLECT(exe, a.binaries, a.datas, name='cycode-cli')
# rollback the prev content of the __init__ file
with open(_INIT_FILE_PATH, 'w', encoding='UTF-8') as file:
file.write(prev_content)