pyarmor 8.5.7__zip → 8.5.8__zip
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pyarmor-8.5.7 → pyarmor-8.5.8}/PKG-INFO +1 -1
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/cli/__init__.py +1 -1
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/cli/__main__.py +7 -12
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/cli/bug.py +2 -2
- pyarmor-8.5.8/pyarmor/cli/core.data.1 +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/cli/core.data.2 +0 -0
- pyarmor-8.5.8/pyarmor/cli/core.data.3 +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/cli/default.cfg +1 -1
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/cli/generate.py +5 -11
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/cli/repack.py +368 -197
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/config.py +1 -1
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor.egg-info/PKG-INFO +1 -1
- pyarmor-8.5.7/pyarmor/cli/core.data.1 +0 -0
- pyarmor-8.5.7/pyarmor/cli/core.data.3 +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/MANIFEST.in +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/README.md +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/README.rst +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/__init__.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/benchmark.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/build_meta.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/cli/bootstrap.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/cli/config.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/cli/context.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/cli/docker.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/cli/hdinfo.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/cli/merge.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/cli/mixer.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/cli/plugin.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/cli/public_capsule.zip +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/cli/register.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/cli/resource.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/cli/shell.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/cobuilder.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/examples/README-ZH.md +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/examples/README.md +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/examples/build-for-exe.bat +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/examples/build-for-freeze.bat +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/examples/build-with-project.bat +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/examples/build-with-project.sh +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/examples/cx_Freeze/hello.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/examples/cx_Freeze/queens.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/examples/cx_Freeze/setup.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/examples/helloworld/foo.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/examples/obfuscate-app.bat +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/examples/obfuscate-app.sh +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/examples/obfuscate-pkg.bat +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/examples/obfuscate-pkg.sh +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/examples/pack-obfuscated-scripts.bat +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/examples/pack-obfuscated-scripts.sh +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/examples/py2exe/hello.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/examples/py2exe/queens.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/examples/py2exe/setup.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/examples/pybench/Arithmetic.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/examples/pybench/Calls.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/examples/pybench/CommandLine.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/examples/pybench/Constructs.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/examples/pybench/Dict.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/examples/pybench/Exceptions.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/examples/pybench/Imports.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/examples/pybench/Instances.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/examples/pybench/Lists.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/examples/pybench/Lookups.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/examples/pybench/NewInstances.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/examples/pybench/Numbers.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/examples/pybench/Setup.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/examples/pybench/Strings.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/examples/pybench/Tuples.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/examples/pybench/With.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/examples/pybench/clockres.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/examples/pybench/package/__init__.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/examples/pybench/package/submodule.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/examples/pybench/pybench.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/examples/pybench/systimes.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/examples/simple/queens.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/examples/testmod/hello.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/examples/testmod/queens.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/examples/testpkg/main.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/examples/testpkg/mypkg/__init__.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/examples/testpkg/mypkg/foo.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/helper/__init__.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/helper/build_data_module.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/helper/buildext.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/helper/get_bind_key.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/helper/get_license_info.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/helper/get_platform_name.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/helper/merge.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/helper/repack.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/helper/superuntime.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/license.tri +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/packer.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/platforms/darwin/x86_64/_pytransform.dylib +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/platforms/linux/x86/_pytransform.so +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/platforms/linux/x86_64/_pytransform.so +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/platforms/windows/x86/_pytransform.dll +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/platforms/windows/x86_64/_pytransform.dll +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/plugins/README.md +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/plugins/check_ntp_time.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/polyfills/__init__.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/polyfills/argparse.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/product.key +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/project.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/protect_code.pt +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/protect_code2.pt +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/public.key +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/public_capsule.zip +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/pyarmor-deprecated.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/pyarmor-webui.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/pyarmor.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/pyimcore.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/pyshield.key +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/pyshield.lic +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/pytransform.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/reform.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/register.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/sppmode.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor/utils.py +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor.egg-info/SOURCES.txt +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor.egg-info/dependency_links.txt +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor.egg-info/entry_points.txt +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor.egg-info/requires.txt +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/pyarmor.egg-info/top_level.txt +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/setup.cfg +0 -0
- {pyarmor-8.5.7 → pyarmor-8.5.8}/setup.py +0 -0
|
@@ -209,10 +209,10 @@ def check_gen_context(ctx, args):
|
|
|
209
209
|
raise CliError('--outer conflicts with any -e, --period, -b')
|
|
210
210
|
|
|
211
211
|
if args.pack:
|
|
212
|
-
choices = '
|
|
212
|
+
choices = 'onefile', 'onedir', 'F', 'D', 'FC', 'DC'
|
|
213
213
|
if args.pack not in choices and not os.path.isfile(args.pack):
|
|
214
|
-
raise CliError('--pack must be an executable file, '
|
|
215
|
-
'"
|
|
214
|
+
raise CliError('--pack must be an executable file, specfile, '
|
|
215
|
+
'"onefile" or "onedir"')
|
|
216
216
|
if args.no_runtime:
|
|
217
217
|
raise CliError('--pack conficts with --no-runtime, --use-runtime')
|
|
218
218
|
if ctx.import_prefix:
|
|
@@ -232,18 +232,13 @@ def cmd_gen(ctx, args):
|
|
|
232
232
|
return _cmd_gen_key(builder, options)
|
|
233
233
|
elif args.inputs[0].lower() in ('runtime', 'run', 'r'):
|
|
234
234
|
_cmd_gen_runtime(builder, options)
|
|
235
|
-
elif args.pack in ('auto', 'onefile', 'onedir', 'F', 'D', 'FC', 'DC'):
|
|
236
|
-
from .repack import Repacker6
|
|
237
|
-
packer = Repacker6(ctx, args.pack, options['inputs'], args.output)
|
|
238
|
-
packer.check()
|
|
239
|
-
builder.process(options, packer)
|
|
240
|
-
Plugin.post_build(ctx, pack=args.pack)
|
|
241
235
|
elif args.pack:
|
|
242
|
-
from .repack import
|
|
243
|
-
|
|
244
|
-
packer = Repacker(args.pack,
|
|
236
|
+
from .repack import find_packer
|
|
237
|
+
Repacker = find_packer(args.pack)
|
|
238
|
+
packer = Repacker(ctx, args.pack, options['inputs'], args.output)
|
|
245
239
|
packer.check()
|
|
246
240
|
builder.process(options, packer=packer)
|
|
241
|
+
packer.build()
|
|
247
242
|
Plugin.post_build(ctx, pack=args.pack)
|
|
248
243
|
else:
|
|
249
244
|
builder.process(options)
|
|
@@ -36,7 +36,7 @@ $tracelog
|
|
|
36
36
|
$tb
|
|
37
37
|
''')
|
|
38
38
|
|
|
39
|
-
ENABLE_DEBUG_HINTS = '''
|
|
39
|
+
ENABLE_DEBUG_HINTS = '''something is wrong
|
|
40
40
|
*=============================================================*
|
|
41
41
|
* Please enable debug option `-d` to run it again *
|
|
42
42
|
* pyarmor -d gen options ... *
|
|
@@ -49,7 +49,7 @@ ENABLE_DEBUG_HINTS = '''somthing is wrong
|
|
|
49
49
|
*=============================================================*
|
|
50
50
|
'''
|
|
51
51
|
|
|
52
|
-
SOLUTION_HINTS = Template('''
|
|
52
|
+
SOLUTION_HINTS = Template('''something is wrong
|
|
53
53
|
*=============================================================*
|
|
54
54
|
* Please check *
|
|
55
55
|
* https://pyarmor.readthedocs.io/en/latest/questions.html *
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -67,7 +67,7 @@ class Finder(object):
|
|
|
67
67
|
for res in self._build_resource(resources):
|
|
68
68
|
if res.pkgname not in resnames:
|
|
69
69
|
self.ctx.obfuscated_modules.add(res.pkgname)
|
|
70
|
-
self.ctx.
|
|
70
|
+
self.ctx.resources.append(res)
|
|
71
71
|
|
|
72
72
|
def process(self):
|
|
73
73
|
logger.info('search inputs ...')
|
|
@@ -156,13 +156,10 @@ class Builder(object):
|
|
|
156
156
|
finder = Finder(self.ctx)
|
|
157
157
|
finder.process()
|
|
158
158
|
|
|
159
|
-
if packer:
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
auto_resources = packer.analysis()
|
|
164
|
-
logger.info('find extra resources: %s', auto_resources)
|
|
165
|
-
finder.append(auto_resources)
|
|
159
|
+
if packer and hasattr(packer, 'analysis'):
|
|
160
|
+
auto_resources = packer.analysis()
|
|
161
|
+
logger.info('find extra resources: %s', auto_resources)
|
|
162
|
+
finder.append(auto_resources)
|
|
166
163
|
|
|
167
164
|
Pytransform3.pre_build(self.ctx)
|
|
168
165
|
|
|
@@ -177,6 +174,3 @@ class Builder(object):
|
|
|
177
174
|
logger.info('obfuscate scripts OK')
|
|
178
175
|
|
|
179
176
|
Pytransform3.post_build(self.ctx)
|
|
180
|
-
|
|
181
|
-
if packer:
|
|
182
|
-
packer.repack(output, self.ctx.runtime_package_name)
|
|
@@ -7,19 +7,362 @@ import sys
|
|
|
7
7
|
import tempfile
|
|
8
8
|
|
|
9
9
|
from fnmatch import fnmatch
|
|
10
|
-
from
|
|
11
|
-
from subprocess import check_call, check_output, DEVNULL
|
|
10
|
+
from subprocess import check_call, DEVNULL
|
|
12
11
|
|
|
12
|
+
# Only used by BundleRepacker, they could be removed with deprecated routines
|
|
13
|
+
from importlib._bootstrap_external import _code_to_timestamp_pyc
|
|
13
14
|
from PyInstaller.archive.writers import ZlibArchiveWriter, CArchiveWriter
|
|
14
15
|
from PyInstaller.archive.readers import CArchiveReader
|
|
15
|
-
try:
|
|
16
|
-
from PyInstaller.loader.pyimod02_archive import ZlibArchiveReader
|
|
17
|
-
except ModuleNotFoundError:
|
|
18
|
-
# Since 5.3
|
|
19
|
-
from PyInstaller.loader.pyimod01_archive import ZlibArchiveReader
|
|
20
16
|
from PyInstaller.compat import is_darwin, is_linux, is_win
|
|
21
17
|
|
|
22
18
|
|
|
19
|
+
logger = logging.getLogger('repack')
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def find_packer(mode):
|
|
23
|
+
if mode in ('onefile', 'onedir', 'F', 'D', 'FC', 'DC'):
|
|
24
|
+
return AutoRepacker
|
|
25
|
+
|
|
26
|
+
if isinstance(mode, str) and mode.endswith('.spec'):
|
|
27
|
+
return SpecRepacker
|
|
28
|
+
|
|
29
|
+
return BundleRepacker
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def autoclean_output(output, autoclean=True):
|
|
33
|
+
if os.path.exists(output) and autoclean:
|
|
34
|
+
n = len(os.path.abspath(output).split(os.sep))
|
|
35
|
+
if n < 3:
|
|
36
|
+
prompt = 'Are you sure to remove path "%s" (y/n)? '
|
|
37
|
+
choice = input(prompt % output).lower()[:1]
|
|
38
|
+
if not choice == 'y':
|
|
39
|
+
return
|
|
40
|
+
logger.info('clean output path "%s"', output)
|
|
41
|
+
shutil.rmtree(output)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
# This patch is used to modify the specfile generate by PyInstaller
|
|
45
|
+
#
|
|
46
|
+
# It mainly does:
|
|
47
|
+
#
|
|
48
|
+
# 1. Find all the imported modules and packages, save to hook script
|
|
49
|
+
#
|
|
50
|
+
# 2. Find imported modules and packages in the same path of main
|
|
51
|
+
# script, and save their names to one list (all of them will be
|
|
52
|
+
# obfuscated automatically)
|
|
53
|
+
#
|
|
54
|
+
spec_patch_code = '''
|
|
55
|
+
import marshal
|
|
56
|
+
import os
|
|
57
|
+
|
|
58
|
+
from PyInstaller.compat import base_prefix, EXTENSION_SUFFIXES
|
|
59
|
+
from sys import prefix, exec_prefix
|
|
60
|
+
from fnmatch import fnmatch
|
|
61
|
+
|
|
62
|
+
exlist = set([base_prefix, prefix, exec_prefix])
|
|
63
|
+
expats = [os.path.join(os.path.normpath(x), '*') for x in exlist]
|
|
64
|
+
|
|
65
|
+
src = {src!r}
|
|
66
|
+
resfile = {resfile!r}
|
|
67
|
+
hookscript = {hookscript!r}
|
|
68
|
+
|
|
69
|
+
nsrc = len(src) + 1
|
|
70
|
+
rsrc = os.path.relpath(src)
|
|
71
|
+
rsrc = '' if rsrc == '.' else rsrc
|
|
72
|
+
psrc = os.path.join(src, '*')
|
|
73
|
+
|
|
74
|
+
hiddenimports = set([])
|
|
75
|
+
plist = set([])
|
|
76
|
+
mlist = []
|
|
77
|
+
|
|
78
|
+
for name, path, kind in a.pure:
|
|
79
|
+
if name.startswith('pyi_rth'):
|
|
80
|
+
continue
|
|
81
|
+
hiddenimports.add(name)
|
|
82
|
+
if fnmatch(path, psrc) and not any([fnmatch(path, x) for x in expats]):
|
|
83
|
+
if name.find('.') == -1 and os.path.basename(path) != '__init__.py':
|
|
84
|
+
mlist.append(os.path.join(rsrc, path[nsrc:]))
|
|
85
|
+
else:
|
|
86
|
+
pkgname = os.path.dirname(path[nsrc:]).split(os.sep)[0]
|
|
87
|
+
plist.add(os.path.join(rsrc, pkgname))
|
|
88
|
+
|
|
89
|
+
for name, path, kind in a.binaries:
|
|
90
|
+
if kind == 'EXTENSION':
|
|
91
|
+
for x in EXTENSION_SUFFIXES:
|
|
92
|
+
if fnmatch(name, '*' + x):
|
|
93
|
+
name = name[:-len(x)]
|
|
94
|
+
break
|
|
95
|
+
hiddenimports.add(name.replace(os.sep, '.'))
|
|
96
|
+
|
|
97
|
+
with open(resfile, 'wb') as f:
|
|
98
|
+
marshal.dump(mlist + list(plist), f)
|
|
99
|
+
with open(hookscript, 'w') as f:
|
|
100
|
+
f.write("hiddenimports=[%s]" % ", ".join([repr(x) for x in hiddenimports]))
|
|
101
|
+
'''
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class AutoRepacker:
|
|
105
|
+
"""New repacker to support PyInstaller 6.0+
|
|
106
|
+
|
|
107
|
+
Args:
|
|
108
|
+
ctx: build context
|
|
109
|
+
mode: onefile or onedir
|
|
110
|
+
inputs: main script to pack
|
|
111
|
+
output: path to store final bundle, default is `dist`
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
def __init__(self, ctx, mode, inputs, output):
|
|
115
|
+
self.ctx = ctx
|
|
116
|
+
self.script = inputs[0]
|
|
117
|
+
self.output = os.path.normpath(output) if output else 'dist'
|
|
118
|
+
|
|
119
|
+
self.name = os.path.splitext(os.path.basename(self.script))[0]
|
|
120
|
+
self.obfpath = os.path.normpath(self.ctx.pack_obfpath)
|
|
121
|
+
self.packpath = os.path.normpath(self.ctx.pack_basepath)
|
|
122
|
+
self.workpath = os.path.join(self.packpath, 'build')
|
|
123
|
+
self.pyicmd = [sys.executable, '-m', 'PyInstaller']
|
|
124
|
+
self.autoclean = mode in ('FC', 'DC')
|
|
125
|
+
self.modeopt = '-F' if mode in ('onefile', 'F', 'FC') else '-D'
|
|
126
|
+
self.init_opts()
|
|
127
|
+
|
|
128
|
+
def init_opts(self):
|
|
129
|
+
self.pyiopts = []
|
|
130
|
+
|
|
131
|
+
opts = self.ctx.pyi_options
|
|
132
|
+
exopts = '--noconfirm', '-y', '--onefile', '-F', '--onedir', '-D'
|
|
133
|
+
exvalues = '--distpath', '--specpath', '--workpath'
|
|
134
|
+
|
|
135
|
+
n = 0
|
|
136
|
+
while n < len(opts):
|
|
137
|
+
x = opts[n]
|
|
138
|
+
if x in ('--name', '-n'):
|
|
139
|
+
self.name = opts[n+1]
|
|
140
|
+
|
|
141
|
+
if x in ('--noconfirm', '-y'):
|
|
142
|
+
self.autoclean = True
|
|
143
|
+
|
|
144
|
+
if x in exvalues:
|
|
145
|
+
n += 1
|
|
146
|
+
elif x not in exopts:
|
|
147
|
+
self.pyiopts.append(x)
|
|
148
|
+
n += 1
|
|
149
|
+
|
|
150
|
+
def analysis(self):
|
|
151
|
+
"""Got imported modules and packages by PyInstaller
|
|
152
|
+
|
|
153
|
+
Generate hook script
|
|
154
|
+
Return file/dir list need to be obfuscated
|
|
155
|
+
"""
|
|
156
|
+
cmdspec = [sys.executable, '-m', 'PyInstaller.utils.cliutils.makespec']
|
|
157
|
+
cmdspec.extend(self.pyiopts)
|
|
158
|
+
cmdspec.append(self.script)
|
|
159
|
+
logger.debug('%s', ' '.join(cmdspec))
|
|
160
|
+
logger.info('call PyInstaller to generate specfile')
|
|
161
|
+
check_call(cmdspec, stdout=DEVNULL, stderr=DEVNULL)
|
|
162
|
+
|
|
163
|
+
specfile = self.name + '.spec'
|
|
164
|
+
rtname = self.ctx.runtime_package_name
|
|
165
|
+
resfile = os.path.join(self.packpath, 'resources.list')
|
|
166
|
+
hookscript = os.path.join(self.packpath, 'hook-%s.py' % rtname)
|
|
167
|
+
self.patch_specfile(specfile, hookscript, resfile)
|
|
168
|
+
|
|
169
|
+
cmdlist = self.pyicmd + ['--clean', '--workpath', self.workpath]
|
|
170
|
+
cmdlist.append(specfile)
|
|
171
|
+
logger.debug('%s', ' '.join(cmdlist))
|
|
172
|
+
logger.info('call PyInstaller to analysis, '
|
|
173
|
+
'it may take several minutes ...')
|
|
174
|
+
check_call(cmdlist, stdout=DEVNULL, stderr=DEVNULL)
|
|
175
|
+
|
|
176
|
+
with open(resfile, 'rb') as f:
|
|
177
|
+
reslist = marshal.load(f)
|
|
178
|
+
|
|
179
|
+
resoptions = self.ctx.get_res_options('')
|
|
180
|
+
excludes = resoptions.get('excludes', '').split()
|
|
181
|
+
if excludes:
|
|
182
|
+
reslist = [x for x in reslist
|
|
183
|
+
if not any([fnmatch(x, pat) for pat in excludes])]
|
|
184
|
+
return reslist
|
|
185
|
+
|
|
186
|
+
def build(self):
|
|
187
|
+
"""Generate final bundle to output"""
|
|
188
|
+
obfscript = os.path.join(self.obfpath, os.path.basename(self.script))
|
|
189
|
+
cmdlist = self.pyicmd + [
|
|
190
|
+
'--clean',
|
|
191
|
+
'--distpath', self.output,
|
|
192
|
+
'--workpath', self.workpath,
|
|
193
|
+
'--additional-hooks-dir', self.packpath,
|
|
194
|
+
self.modeopt
|
|
195
|
+
]
|
|
196
|
+
cmdlist.extend(self.pyiopts)
|
|
197
|
+
cmdlist.append(obfscript)
|
|
198
|
+
|
|
199
|
+
logger.debug('%s', ' '.join(cmdlist))
|
|
200
|
+
logger.info('call PyInstaller to generate final bundle ...\n')
|
|
201
|
+
check_call(cmdlist)
|
|
202
|
+
logger.info('')
|
|
203
|
+
logger.info('the final bundle has been generated to "%s" successfully',
|
|
204
|
+
self.output)
|
|
205
|
+
|
|
206
|
+
def patch_specfile(self, specfile, hookscript, resfile):
|
|
207
|
+
lines = []
|
|
208
|
+
with open(specfile, 'r', encoding='utf-8') as f:
|
|
209
|
+
for line in f:
|
|
210
|
+
if line.startswith('pyz = PYZ'):
|
|
211
|
+
break
|
|
212
|
+
lines.append(line)
|
|
213
|
+
else:
|
|
214
|
+
logger.error('no found line starts with "pyz = PYZ"')
|
|
215
|
+
raise RuntimeError('unsupported specfile "%s"' % specfile)
|
|
216
|
+
|
|
217
|
+
lines.append(spec_patch_code.format(
|
|
218
|
+
src=os.path.abspath(os.path.dirname(self.script)),
|
|
219
|
+
hookscript=os.path.abspath(hookscript),
|
|
220
|
+
resfile=os.path.abspath(resfile)))
|
|
221
|
+
|
|
222
|
+
with open(specfile, 'w', encoding='utf-8') as f:
|
|
223
|
+
f.write(''.join(lines))
|
|
224
|
+
|
|
225
|
+
def check(self):
|
|
226
|
+
autoclean_output(self.output, self.autoclean)
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
manual_spec_patch = '''
|
|
230
|
+
# Pyarmor patch start:
|
|
231
|
+
|
|
232
|
+
def apply_pyarmor_patch():
|
|
233
|
+
|
|
234
|
+
srcpath = {srcpath!r}
|
|
235
|
+
obfpath = {obfpath!r}
|
|
236
|
+
pkgname = {rtname!r}
|
|
237
|
+
pkgpath = os.path.join(obfpath, pkgname)
|
|
238
|
+
extpath = os.path.join(pkgname, {extname!r})
|
|
239
|
+
|
|
240
|
+
if hasattr(a.pure, '_code_cache'):
|
|
241
|
+
code_cache = a.pure._code_cache
|
|
242
|
+
else:
|
|
243
|
+
from PyInstaller.config import CONF
|
|
244
|
+
code_cache = CONF['code_cache'].get(id(a.pure))
|
|
245
|
+
|
|
246
|
+
srclist = [os.path.normcase(x) for x in srcpath]
|
|
247
|
+
def match_obfuscated_script(orgpath):
|
|
248
|
+
for x in srclist:
|
|
249
|
+
if os.path.normcase(orgpath).startswith(x):
|
|
250
|
+
return os.path.join(obfpath, orgpath[len(x)+1:])
|
|
251
|
+
|
|
252
|
+
count = 0
|
|
253
|
+
for i in range(len(a.scripts)):
|
|
254
|
+
x = match_obfuscated_script(a.scripts[i][1])
|
|
255
|
+
if x and os.path.exists(x):
|
|
256
|
+
a.scripts[i] = a.scripts[i][0], x, a.scripts[i][2]
|
|
257
|
+
count += 1
|
|
258
|
+
if count == 0:
|
|
259
|
+
raise RuntimeError('No obfuscated script found')
|
|
260
|
+
|
|
261
|
+
for i in range(len(a.pure)):
|
|
262
|
+
x = match_obfuscated_script(a.pure[i][1])
|
|
263
|
+
if x and os.path.exists(x):
|
|
264
|
+
code_cache.pop(a.pure[i][0], None)
|
|
265
|
+
a.pure[i] = a.pure[i][0], x, a.pure[i][2]
|
|
266
|
+
|
|
267
|
+
a.pure.append((pkgname, os.path.join(pkgpath, '__init__.py'), 'PYMODULE'))
|
|
268
|
+
a.binaries.append((extpath, os.path.join(obfpath, extpath), 'EXTENSION'))
|
|
269
|
+
|
|
270
|
+
apply_pyarmor_patch()
|
|
271
|
+
|
|
272
|
+
# Pyarmor patch end.
|
|
273
|
+
'''
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
class SpecRepacker:
|
|
277
|
+
"""Patch specfile and use it to pack obfuscated scripts
|
|
278
|
+
|
|
279
|
+
Args:
|
|
280
|
+
ctx: build context
|
|
281
|
+
specfile: specfile need to be patched
|
|
282
|
+
inputs: main script to pack
|
|
283
|
+
output: path to store final bundle, default is `dist`
|
|
284
|
+
"""
|
|
285
|
+
|
|
286
|
+
def __init__(self, ctx, specfile, inputs, output):
|
|
287
|
+
self.ctx = ctx
|
|
288
|
+
self.specfile = specfile
|
|
289
|
+
self.script = inputs[0]
|
|
290
|
+
self.output = os.path.normpath(output) if output else 'dist'
|
|
291
|
+
|
|
292
|
+
self.pyicmd = [sys.executable, '-m', 'PyInstaller']
|
|
293
|
+
self.obfpath = os.path.normpath(self.ctx.pack_obfpath)
|
|
294
|
+
|
|
295
|
+
def build(self):
|
|
296
|
+
"""Generate patched specfile and pack obfuscated scripts"""
|
|
297
|
+
specfile = self.specfile[:-5] + '.patched.spec'
|
|
298
|
+
logger.info('generate patched specfile "%s"', specfile)
|
|
299
|
+
|
|
300
|
+
rtpkg = self.ctx.runtime_package_name
|
|
301
|
+
for x in os.listdir(os.path.join(self.obfpath, rtpkg)):
|
|
302
|
+
if x.startswith('pyarmor_runtime'):
|
|
303
|
+
extname = x
|
|
304
|
+
break
|
|
305
|
+
else:
|
|
306
|
+
raise RuntimeError('no found extension `pyarmor_runtime`')
|
|
307
|
+
|
|
308
|
+
patch = manual_spec_patch.format(
|
|
309
|
+
srcpath=[os.path.abspath(os.path.dirname(self.script))],
|
|
310
|
+
obfpath=os.path.abspath(self.obfpath),
|
|
311
|
+
rtname=self.ctx.runtime_package_name,
|
|
312
|
+
extname=extname)
|
|
313
|
+
|
|
314
|
+
with open(self.specfile, 'r', encoding='utf-8') as f:
|
|
315
|
+
lines = f.readlines()
|
|
316
|
+
|
|
317
|
+
n = 0
|
|
318
|
+
for line in lines:
|
|
319
|
+
if line.startswith('pyz = PYZ'):
|
|
320
|
+
lines[n:n] = [patch]
|
|
321
|
+
break
|
|
322
|
+
n += 1
|
|
323
|
+
else:
|
|
324
|
+
logger.error('no found line starts with "pyz = PYZ"')
|
|
325
|
+
raise RuntimeError('unsupported specfile "%s"' % self.specfile)
|
|
326
|
+
|
|
327
|
+
with open(specfile, 'w', encoding='utf-8') as f:
|
|
328
|
+
f.write(''.join(lines))
|
|
329
|
+
|
|
330
|
+
cmdlist = self.pyicmd + [
|
|
331
|
+
'--clean',
|
|
332
|
+
'--distpath', self.output,
|
|
333
|
+
'--workpath', os.path.join(self.ctx.pack_basepath, 'build'),
|
|
334
|
+
specfile
|
|
335
|
+
]
|
|
336
|
+
logger.info('call PyInstaller to generate final bundle ...'
|
|
337
|
+
'\n\n%s\n', ' '.join(cmdlist))
|
|
338
|
+
check_call(cmdlist)
|
|
339
|
+
logger.info('')
|
|
340
|
+
logger.info('the final bundle has been generated to "%s" successfully',
|
|
341
|
+
self.output)
|
|
342
|
+
|
|
343
|
+
def check(self):
|
|
344
|
+
options = self.ctx.pyi_options
|
|
345
|
+
autoclean = '-y' in options or '--noconfirm' in options
|
|
346
|
+
autoclean_output(self.output, autoclean)
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
##############################################################
|
|
350
|
+
#
|
|
351
|
+
# Deprecated routines
|
|
352
|
+
#
|
|
353
|
+
# This is the old method to repack executable generated by PyInstaller
|
|
354
|
+
#
|
|
355
|
+
# Why is it deprecated?
|
|
356
|
+
#
|
|
357
|
+
# 1. It need hack PyInstaller bundle structure which may be changed in
|
|
358
|
+
# different PyInstaller version.
|
|
359
|
+
#
|
|
360
|
+
# Actually, it doesn't work for PyInstaller 5.13+ because of this
|
|
361
|
+
#
|
|
362
|
+
# 2. Not friend to junior users
|
|
363
|
+
#
|
|
364
|
+
##
|
|
365
|
+
|
|
23
366
|
# Type codes for PYZ PYZ entries
|
|
24
367
|
PYZ_ITEM_MODULE = 0
|
|
25
368
|
PYZ_ITEM_PKG = 1
|
|
@@ -42,9 +385,6 @@ PKG_ITEM_SPLASH = 'l' # splash resources
|
|
|
42
385
|
EXTRACT_SUFFIX = '_extracted'
|
|
43
386
|
|
|
44
387
|
|
|
45
|
-
logger = logging.getLogger('repack')
|
|
46
|
-
|
|
47
|
-
|
|
48
388
|
class CArchiveReader2(CArchiveReader):
|
|
49
389
|
|
|
50
390
|
def find_magic_pattern(self, fp, magic_pattern):
|
|
@@ -94,6 +434,12 @@ class CArchiveReader2(CArchiveReader):
|
|
|
94
434
|
if hasattr(self, 'open_embedded_archive'):
|
|
95
435
|
return self.open_embedded_archive(name)
|
|
96
436
|
|
|
437
|
+
try:
|
|
438
|
+
from PyInstaller.loader.pyimod02_archive import ZlibArchiveReader
|
|
439
|
+
except ModuleNotFoundError:
|
|
440
|
+
# Since 5.3
|
|
441
|
+
from PyInstaller.loader.pyimod01_archive import ZlibArchiveReader
|
|
442
|
+
|
|
97
443
|
ndx = self.toc.find(name)
|
|
98
444
|
(dpos, dlen, ulen, flag, typcd, nm) = self.toc.get(ndx)
|
|
99
445
|
return ZlibArchiveReader(self.path, self.pkg_start + dpos)
|
|
@@ -307,13 +653,16 @@ def repack_executable(executable, buildpath, obfpath, rtentry, codesign=None):
|
|
|
307
653
|
logger.info('generate patched bundle "%s" successfully', executable)
|
|
308
654
|
|
|
309
655
|
|
|
310
|
-
class
|
|
656
|
+
class BundleRepacker:
|
|
657
|
+
"""Deprecated method since v8.5.8"""
|
|
311
658
|
|
|
312
|
-
def __init__(self, executable,
|
|
659
|
+
def __init__(self, ctx, executable, inputs, output):
|
|
660
|
+
self.ctx = ctx
|
|
313
661
|
self.executable = executable
|
|
314
|
-
self.
|
|
315
|
-
self.
|
|
316
|
-
self.
|
|
662
|
+
self.output = os.path.normpath(output) if output else 'dist'
|
|
663
|
+
self.buildpath = ctx.pack_basepath
|
|
664
|
+
self.codesign = ctx.cfg['pack'].get('codesign_identify', None)
|
|
665
|
+
self.extract_carchive(executable, self.buildpath)
|
|
317
666
|
|
|
318
667
|
def check(self):
|
|
319
668
|
try:
|
|
@@ -361,6 +710,9 @@ class Repacker:
|
|
|
361
710
|
for x in os.scandir(os.path.dirname(executable))])
|
|
362
711
|
logger.debug('one file mode is %s', bool(self.one_file_mode))
|
|
363
712
|
|
|
713
|
+
def build(self):
|
|
714
|
+
self.repack(self.output, self.ctx.runtime_package_name)
|
|
715
|
+
|
|
364
716
|
def repack(self, obfpath, rtname, entry=None):
|
|
365
717
|
buildpath = self.buildpath
|
|
366
718
|
executable = self.executable
|
|
@@ -415,6 +767,7 @@ class Repacker:
|
|
|
415
767
|
def _fixup_darwin_rtbinary(self, rtbinary, pylib_name):
|
|
416
768
|
'''Unused since Pyarmor 8.3.0'''
|
|
417
769
|
from sys import version_info as pyver
|
|
770
|
+
from subprocess import check_output
|
|
418
771
|
pylib = os.path.normpath(os.path.join('@rpath', pylib_name))
|
|
419
772
|
output = check_output(['otool', '-L', rtbinary])
|
|
420
773
|
for line in output.splitlines():
|
|
@@ -437,185 +790,3 @@ class Repacker:
|
|
|
437
790
|
check_call(cmdlist, stdout=DEVNULL, stderr=DEVNULL)
|
|
438
791
|
except Exception as e:
|
|
439
792
|
logger.warning('%s', e)
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
# This patch is used to modify the specfile generate by PyInstaller
|
|
443
|
-
#
|
|
444
|
-
# It has 2 goals:
|
|
445
|
-
#
|
|
446
|
-
# 1. Find all the imported modules and packages
|
|
447
|
-
#
|
|
448
|
-
# Save them to hook script
|
|
449
|
-
#
|
|
450
|
-
# 2. Search scripts and packages in the path of entry script
|
|
451
|
-
#
|
|
452
|
-
# All of them will be obfuscated automatically
|
|
453
|
-
#
|
|
454
|
-
spec_patch_code = '''
|
|
455
|
-
import marshal
|
|
456
|
-
import os
|
|
457
|
-
|
|
458
|
-
from PyInstaller.compat import base_prefix
|
|
459
|
-
from sys import prefix, exec_prefix
|
|
460
|
-
|
|
461
|
-
exlist = set([base_prefix, prefix, exec_prefix])
|
|
462
|
-
exlist = [os.path.normpath(x) for x in exlist]
|
|
463
|
-
|
|
464
|
-
src = {src}
|
|
465
|
-
sn = len(src) + 1
|
|
466
|
-
sdir = os.path.relpath(src)
|
|
467
|
-
sdir = '' if sdir == '.' else sdir
|
|
468
|
-
|
|
469
|
-
hiddenimports = set([])
|
|
470
|
-
plist = set([])
|
|
471
|
-
mlist = []
|
|
472
|
-
|
|
473
|
-
for name, path, kind in a.pure:
|
|
474
|
-
if name.startswith('pyi_rth'):
|
|
475
|
-
continue
|
|
476
|
-
hiddenimports.add(name)
|
|
477
|
-
if path.startswith(src) and not any([path.startswith(x) for x in exlist]):
|
|
478
|
-
if name.find('.') == -1 and os.path.basename(path) != '__init__.py':
|
|
479
|
-
mlist.append(os.path.join(sdir, path[sn:]))
|
|
480
|
-
else:
|
|
481
|
-
pkgname = os.path.dirname(path[sn:]).split(os.sep)[0]
|
|
482
|
-
plist.add(os.path.join(sdir, pkgname))
|
|
483
|
-
|
|
484
|
-
with open({resfile}, 'wb') as f:
|
|
485
|
-
marshal.dump(mlist + list(plist), f)
|
|
486
|
-
with open({hookscript}, 'w') as f:
|
|
487
|
-
f.write("hiddenimports=[%s]" % ", ".join([repr(x) for x in hiddenimports]))
|
|
488
|
-
'''
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
class Repacker6:
|
|
492
|
-
"""New repacker to support PyInstaller 6.0+
|
|
493
|
-
|
|
494
|
-
Args:
|
|
495
|
-
ctx: build context
|
|
496
|
-
mode: onefile or onedir
|
|
497
|
-
inputs: main script to pack
|
|
498
|
-
output: path to store final bundle, default is `dist`
|
|
499
|
-
"""
|
|
500
|
-
|
|
501
|
-
def __init__(self, ctx, mode, inputs, output):
|
|
502
|
-
self.ctx = ctx
|
|
503
|
-
self.inputs = inputs
|
|
504
|
-
self.output = os.path.normpath(output) if output else 'dist'
|
|
505
|
-
|
|
506
|
-
self.script = self.inputs[0]
|
|
507
|
-
self.name = os.path.splitext(os.path.basename(self.script))[0]
|
|
508
|
-
self.obfpath = os.path.normpath(self.ctx.pack_obfpath)
|
|
509
|
-
self.packpath = os.path.normpath(self.ctx.pack_basepath)
|
|
510
|
-
self.workpath = os.path.join(self.packpath, 'build')
|
|
511
|
-
self.pyicmd = [sys.executable, '-m', 'PyInstaller']
|
|
512
|
-
self.autoclean = mode in ('FC', 'DC')
|
|
513
|
-
self.modeopt = '-F' if mode in ('onefile', 'F', 'FC') else '-D'
|
|
514
|
-
self.init_opts()
|
|
515
|
-
|
|
516
|
-
def init_opts(self):
|
|
517
|
-
opts = self.ctx.pyi_options
|
|
518
|
-
exopts = '--noconfirm', '-y', '--onefile', '-F', '--onedir', '-D'
|
|
519
|
-
exvalues = '--distpath', '--specpath', '--workpath'
|
|
520
|
-
|
|
521
|
-
self.pyiopts = []
|
|
522
|
-
|
|
523
|
-
n = 0
|
|
524
|
-
while n < len(opts):
|
|
525
|
-
x = opts[n]
|
|
526
|
-
if x in ('--name', '-n'):
|
|
527
|
-
self.name = opts[n+1]
|
|
528
|
-
|
|
529
|
-
if x in exvalues:
|
|
530
|
-
n += 1
|
|
531
|
-
elif x not in exopts:
|
|
532
|
-
self.pyiopts.append(x)
|
|
533
|
-
n += 1
|
|
534
|
-
|
|
535
|
-
def analysis(self):
|
|
536
|
-
"""Got imported modules and packages by PyInstaller
|
|
537
|
-
|
|
538
|
-
Generate hook script
|
|
539
|
-
Return file/dir list need to be obfuscated
|
|
540
|
-
"""
|
|
541
|
-
cmdspec = [sys.executable, '-m', 'PyInstaller.utils.cliutils.makespec']
|
|
542
|
-
cmdspec.extend(self.pyiopts)
|
|
543
|
-
cmdspec.append(self.script)
|
|
544
|
-
logger.debug('%s', ' '.join(cmdspec))
|
|
545
|
-
logger.info('call PyInstaller to generate specfile')
|
|
546
|
-
check_call(cmdspec, stdout=DEVNULL, stderr=DEVNULL)
|
|
547
|
-
|
|
548
|
-
specfile = self.name + '.spec'
|
|
549
|
-
rtname = self.ctx.runtime_package_name
|
|
550
|
-
resfile = os.path.join(self.packpath, 'resources.list')
|
|
551
|
-
hookscript = os.path.join(self.packpath, 'hook-%s.py' % rtname)
|
|
552
|
-
self.patch_specfile(specfile, hookscript, resfile)
|
|
553
|
-
|
|
554
|
-
cmdlist = self.pyicmd + ['--clean', '--workpath', self.workpath]
|
|
555
|
-
cmdlist.append(specfile)
|
|
556
|
-
logger.debug('%s', ' '.join(cmdlist))
|
|
557
|
-
logger.info('call PyInstaller to analysis, '
|
|
558
|
-
'it may take several minutes ...')
|
|
559
|
-
check_call(cmdlist, stdout=DEVNULL, stderr=DEVNULL)
|
|
560
|
-
|
|
561
|
-
with open(resfile, 'rb') as f:
|
|
562
|
-
reslist = marshal.load(f)
|
|
563
|
-
|
|
564
|
-
resoptions = self.ctx.get_res_options('')
|
|
565
|
-
excludes = resoptions.get('excludes', '').split()
|
|
566
|
-
if excludes:
|
|
567
|
-
reslist = [x for x in reslist
|
|
568
|
-
if not any([fnmatch(x, pat) for pat in excludes])]
|
|
569
|
-
return reslist
|
|
570
|
-
|
|
571
|
-
def build(self):
|
|
572
|
-
"""Generate final bundle to output"""
|
|
573
|
-
obfscript = os.path.join(self.obfpath, os.path.basename(self.script))
|
|
574
|
-
cmdlist = self.pyicmd + [
|
|
575
|
-
'--clean',
|
|
576
|
-
'--distpath', self.output,
|
|
577
|
-
'--workpath', self.workpath,
|
|
578
|
-
'--additional-hooks-dir', self.packpath,
|
|
579
|
-
self.modeopt
|
|
580
|
-
]
|
|
581
|
-
cmdlist.extend(self.pyiopts)
|
|
582
|
-
cmdlist.append(obfscript)
|
|
583
|
-
|
|
584
|
-
logger.debug('%s', ' '.join(cmdlist))
|
|
585
|
-
logger.info('call PyInstaller to generate final bundle ...\n')
|
|
586
|
-
check_call(cmdlist)
|
|
587
|
-
logger.info('')
|
|
588
|
-
logger.info('the final bundle has been generated to "%s" successfully',
|
|
589
|
-
self.output)
|
|
590
|
-
|
|
591
|
-
def repack(self, *unused):
|
|
592
|
-
"""Only for compatible with Repacker"""
|
|
593
|
-
self.build()
|
|
594
|
-
|
|
595
|
-
def patch_specfile(self, specfile, hookscript, resfile):
|
|
596
|
-
# TODO: non-ascii need specify encoding to open file
|
|
597
|
-
lines = []
|
|
598
|
-
with open(specfile, 'r') as f:
|
|
599
|
-
for line in f:
|
|
600
|
-
if line.startswith('pyz = PYZ'):
|
|
601
|
-
break
|
|
602
|
-
lines.append(line)
|
|
603
|
-
|
|
604
|
-
lines.append(spec_patch_code.format(
|
|
605
|
-
src=repr(os.path.abspath(os.path.dirname(self.script))),
|
|
606
|
-
hookscript=repr(os.path.abspath(hookscript)),
|
|
607
|
-
resfile=repr(os.path.abspath(resfile))))
|
|
608
|
-
|
|
609
|
-
with open(specfile, 'w') as f:
|
|
610
|
-
f.write(''.join(lines))
|
|
611
|
-
|
|
612
|
-
def check(self):
|
|
613
|
-
if os.path.exists(self.output) and self.autoclean:
|
|
614
|
-
n = len(os.path.abspath(self.output).split(os.sep))
|
|
615
|
-
if n < 3:
|
|
616
|
-
prompt = 'Are you sure to remove path "%s" (y/n)? '
|
|
617
|
-
choice = input(prompt % self.output).lower()[:1]
|
|
618
|
-
if not choice == 'y':
|
|
619
|
-
return
|
|
620
|
-
logger.info('clean output path "%s"', self.output)
|
|
621
|
-
shutil.rmtree(self.output)
|
|
Binary file
|
|
Binary file
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|