pyarmor 8.5.6__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.6 → pyarmor-8.5.8}/PKG-INFO +1 -1
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/cli/__init__.py +1 -1
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/cli/__main__.py +7 -12
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/cli/bug.py +2 -2
- pyarmor-8.5.8/pyarmor/cli/core.data.1 +0 -0
- {pyarmor-8.5.6 → 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.6 → pyarmor-8.5.8}/pyarmor/cli/default.cfg +1 -1
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/cli/generate.py +5 -11
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/cli/repack.py +369 -195
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/config.py +1 -1
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor.egg-info/PKG-INFO +1 -1
- pyarmor-8.5.6/pyarmor/cli/core.data.1 +0 -0
- pyarmor-8.5.6/pyarmor/cli/core.data.3 +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/MANIFEST.in +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/README.md +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/README.rst +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/__init__.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/benchmark.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/build_meta.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/cli/bootstrap.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/cli/config.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/cli/context.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/cli/docker.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/cli/hdinfo.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/cli/merge.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/cli/mixer.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/cli/plugin.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/cli/public_capsule.zip +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/cli/register.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/cli/resource.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/cli/shell.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/cobuilder.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/README-ZH.md +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/README.md +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/build-for-exe.bat +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/build-for-freeze.bat +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/build-with-project.bat +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/build-with-project.sh +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/cx_Freeze/hello.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/cx_Freeze/queens.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/cx_Freeze/setup.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/helloworld/foo.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/obfuscate-app.bat +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/obfuscate-app.sh +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/obfuscate-pkg.bat +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/obfuscate-pkg.sh +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/pack-obfuscated-scripts.bat +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/pack-obfuscated-scripts.sh +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/py2exe/hello.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/py2exe/queens.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/py2exe/setup.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/pybench/Arithmetic.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/pybench/Calls.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/pybench/CommandLine.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/pybench/Constructs.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/pybench/Dict.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/pybench/Exceptions.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/pybench/Imports.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/pybench/Instances.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/pybench/Lists.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/pybench/Lookups.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/pybench/NewInstances.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/pybench/Numbers.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/pybench/Setup.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/pybench/Strings.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/pybench/Tuples.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/pybench/With.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/pybench/clockres.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/pybench/package/__init__.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/pybench/package/submodule.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/pybench/pybench.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/pybench/systimes.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/simple/queens.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/testmod/hello.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/testmod/queens.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/testpkg/main.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/testpkg/mypkg/__init__.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/testpkg/mypkg/foo.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/helper/__init__.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/helper/build_data_module.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/helper/buildext.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/helper/get_bind_key.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/helper/get_license_info.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/helper/get_platform_name.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/helper/merge.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/helper/repack.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/helper/superuntime.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/license.tri +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/packer.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/platforms/darwin/x86_64/_pytransform.dylib +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/platforms/linux/x86/_pytransform.so +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/platforms/linux/x86_64/_pytransform.so +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/platforms/windows/x86/_pytransform.dll +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/platforms/windows/x86_64/_pytransform.dll +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/plugins/README.md +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/plugins/check_ntp_time.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/polyfills/__init__.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/polyfills/argparse.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/product.key +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/project.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/protect_code.pt +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/protect_code2.pt +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/public.key +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/public_capsule.zip +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/pyarmor-deprecated.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/pyarmor-webui.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/pyarmor.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/pyimcore.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/pyshield.key +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/pyshield.lic +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/pytransform.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/reform.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/register.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/sppmode.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/utils.py +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor.egg-info/SOURCES.txt +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor.egg-info/dependency_links.txt +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor.egg-info/entry_points.txt +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor.egg-info/requires.txt +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor.egg-info/top_level.txt +0 -0
- {pyarmor-8.5.6 → pyarmor-8.5.8}/setup.cfg +0 -0
- {pyarmor-8.5.6 → 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)
|
|
@@ -6,19 +6,363 @@ import struct
|
|
|
6
6
|
import sys
|
|
7
7
|
import tempfile
|
|
8
8
|
|
|
9
|
-
from
|
|
10
|
-
from subprocess import check_call,
|
|
9
|
+
from fnmatch import fnmatch
|
|
10
|
+
from subprocess import check_call, DEVNULL
|
|
11
11
|
|
|
12
|
+
# Only used by BundleRepacker, they could be removed with deprecated routines
|
|
13
|
+
from importlib._bootstrap_external import _code_to_timestamp_pyc
|
|
12
14
|
from PyInstaller.archive.writers import ZlibArchiveWriter, CArchiveWriter
|
|
13
15
|
from PyInstaller.archive.readers import CArchiveReader
|
|
14
|
-
try:
|
|
15
|
-
from PyInstaller.loader.pyimod02_archive import ZlibArchiveReader
|
|
16
|
-
except ModuleNotFoundError:
|
|
17
|
-
# Since 5.3
|
|
18
|
-
from PyInstaller.loader.pyimod01_archive import ZlibArchiveReader
|
|
19
16
|
from PyInstaller.compat import is_darwin, is_linux, is_win
|
|
20
17
|
|
|
21
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
|
+
|
|
22
366
|
# Type codes for PYZ PYZ entries
|
|
23
367
|
PYZ_ITEM_MODULE = 0
|
|
24
368
|
PYZ_ITEM_PKG = 1
|
|
@@ -41,9 +385,6 @@ PKG_ITEM_SPLASH = 'l' # splash resources
|
|
|
41
385
|
EXTRACT_SUFFIX = '_extracted'
|
|
42
386
|
|
|
43
387
|
|
|
44
|
-
logger = logging.getLogger('repack')
|
|
45
|
-
|
|
46
|
-
|
|
47
388
|
class CArchiveReader2(CArchiveReader):
|
|
48
389
|
|
|
49
390
|
def find_magic_pattern(self, fp, magic_pattern):
|
|
@@ -93,6 +434,12 @@ class CArchiveReader2(CArchiveReader):
|
|
|
93
434
|
if hasattr(self, 'open_embedded_archive'):
|
|
94
435
|
return self.open_embedded_archive(name)
|
|
95
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
|
+
|
|
96
443
|
ndx = self.toc.find(name)
|
|
97
444
|
(dpos, dlen, ulen, flag, typcd, nm) = self.toc.get(ndx)
|
|
98
445
|
return ZlibArchiveReader(self.path, self.pkg_start + dpos)
|
|
@@ -306,13 +653,16 @@ def repack_executable(executable, buildpath, obfpath, rtentry, codesign=None):
|
|
|
306
653
|
logger.info('generate patched bundle "%s" successfully', executable)
|
|
307
654
|
|
|
308
655
|
|
|
309
|
-
class
|
|
656
|
+
class BundleRepacker:
|
|
657
|
+
"""Deprecated method since v8.5.8"""
|
|
310
658
|
|
|
311
|
-
def __init__(self, executable,
|
|
659
|
+
def __init__(self, ctx, executable, inputs, output):
|
|
660
|
+
self.ctx = ctx
|
|
312
661
|
self.executable = executable
|
|
313
|
-
self.
|
|
314
|
-
self.
|
|
315
|
-
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)
|
|
316
666
|
|
|
317
667
|
def check(self):
|
|
318
668
|
try:
|
|
@@ -360,6 +710,9 @@ class Repacker:
|
|
|
360
710
|
for x in os.scandir(os.path.dirname(executable))])
|
|
361
711
|
logger.debug('one file mode is %s', bool(self.one_file_mode))
|
|
362
712
|
|
|
713
|
+
def build(self):
|
|
714
|
+
self.repack(self.output, self.ctx.runtime_package_name)
|
|
715
|
+
|
|
363
716
|
def repack(self, obfpath, rtname, entry=None):
|
|
364
717
|
buildpath = self.buildpath
|
|
365
718
|
executable = self.executable
|
|
@@ -414,6 +767,7 @@ class Repacker:
|
|
|
414
767
|
def _fixup_darwin_rtbinary(self, rtbinary, pylib_name):
|
|
415
768
|
'''Unused since Pyarmor 8.3.0'''
|
|
416
769
|
from sys import version_info as pyver
|
|
770
|
+
from subprocess import check_output
|
|
417
771
|
pylib = os.path.normpath(os.path.join('@rpath', pylib_name))
|
|
418
772
|
output = check_output(['otool', '-L', rtbinary])
|
|
419
773
|
for line in output.splitlines():
|
|
@@ -436,183 +790,3 @@ class Repacker:
|
|
|
436
790
|
check_call(cmdlist, stdout=DEVNULL, stderr=DEVNULL)
|
|
437
791
|
except Exception as e:
|
|
438
792
|
logger.warning('%s', e)
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
# This patch is used to modify the specfile generate by PyInstaller
|
|
442
|
-
#
|
|
443
|
-
# It has 2 goals:
|
|
444
|
-
#
|
|
445
|
-
# 1. Find all the imported modules and packages
|
|
446
|
-
#
|
|
447
|
-
# Save them to hook script
|
|
448
|
-
#
|
|
449
|
-
# 2. Search scripts and packages in the path of entry script
|
|
450
|
-
#
|
|
451
|
-
# All of them will be obfuscated automatically
|
|
452
|
-
#
|
|
453
|
-
spec_patch_code = '''
|
|
454
|
-
from PyInstaller.compat import base_prefix
|
|
455
|
-
import marshal
|
|
456
|
-
import os
|
|
457
|
-
|
|
458
|
-
hiddenimports = set([])
|
|
459
|
-
plist = set([])
|
|
460
|
-
mlist = []
|
|
461
|
-
src = {src}
|
|
462
|
-
sn = len(src) + 1
|
|
463
|
-
prefix = os.path.relpath(src)
|
|
464
|
-
prefix = '' if prefix == '.' else prefix
|
|
465
|
-
|
|
466
|
-
for name, path, kind in a.pure:
|
|
467
|
-
if name.startswith('pyi_rth'):
|
|
468
|
-
continue
|
|
469
|
-
if path.startswith(src) and not path.startswith(base_prefix):
|
|
470
|
-
hiddenimports.add(name)
|
|
471
|
-
if name.find('.') == -1 and os.path.basename(path) != '__init__.py':
|
|
472
|
-
mlist.append(os.path.join(prefix, path[sn:]))
|
|
473
|
-
else:
|
|
474
|
-
pkgname = os.path.dirname(path[sn:]).split(os.sep)[0]
|
|
475
|
-
plist.add(os.path.join(prefix, pkgname))
|
|
476
|
-
else:
|
|
477
|
-
hiddenimports.add(name.split('.')[0])
|
|
478
|
-
|
|
479
|
-
with open({resfile}, 'wb') as f:
|
|
480
|
-
marshal.dump(mlist + list(plist), f)
|
|
481
|
-
with open({hookscript}, 'w') as f:
|
|
482
|
-
f.write("hiddenimports=[%s]" % ", ".join([repr(x) for x in hiddenimports]))
|
|
483
|
-
'''
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
class Repacker6:
|
|
487
|
-
"""New repacker to support PyInstaller 6.0+
|
|
488
|
-
|
|
489
|
-
Args:
|
|
490
|
-
ctx: build context
|
|
491
|
-
mode: onefile or onefolder
|
|
492
|
-
inputs: main script to pack
|
|
493
|
-
"""
|
|
494
|
-
|
|
495
|
-
def __init__(self, ctx, mode, inputs, output):
|
|
496
|
-
self.ctx = ctx
|
|
497
|
-
self.inputs = inputs
|
|
498
|
-
self.output = 'dist' if output is None else os.path.normpath(output)
|
|
499
|
-
|
|
500
|
-
self.script = self.inputs[0]
|
|
501
|
-
self.obfpath = os.path.normpath(self.ctx.pack_obfpath)
|
|
502
|
-
self.packpath = os.path.normpath(self.ctx.pack_basepath)
|
|
503
|
-
self.workpath = os.path.join(self.packpath, 'build')
|
|
504
|
-
self.pyicmd = [sys.executable, '-m', 'PyInstaller']
|
|
505
|
-
self.pyiopts = self.init_opts(mode)
|
|
506
|
-
self.autoclean = mode in ('FC', 'DC')
|
|
507
|
-
|
|
508
|
-
def init_opts(self, mode):
|
|
509
|
-
opts = []
|
|
510
|
-
exopts = '--noconfirm', '-y'
|
|
511
|
-
if mode == 'auto':
|
|
512
|
-
exopts += ('--onefile', '-F', '--onefolder', '-D')
|
|
513
|
-
else:
|
|
514
|
-
opts.append('-F' if mode in ('onefile', 'F', 'FC') else '-D')
|
|
515
|
-
opts.extend(self.ctx.pyi_options)
|
|
516
|
-
|
|
517
|
-
exvalues = '--distpath', '--specpath', '--workpath'
|
|
518
|
-
return self.filter_opts(opts, exvalues, exopts)
|
|
519
|
-
|
|
520
|
-
def filter_opts(self, opts, exvalues, exopts=None):
|
|
521
|
-
result = []
|
|
522
|
-
isvalue = False
|
|
523
|
-
for x in opts:
|
|
524
|
-
if isvalue:
|
|
525
|
-
isvalue = False
|
|
526
|
-
elif x in exvalues:
|
|
527
|
-
isvalue = True
|
|
528
|
-
elif exopts is None or x not in exopts:
|
|
529
|
-
result.append(x)
|
|
530
|
-
return result
|
|
531
|
-
|
|
532
|
-
def analysis(self):
|
|
533
|
-
"""Got imported modules and packages by PyInstaller
|
|
534
|
-
|
|
535
|
-
Generate hook script
|
|
536
|
-
Return file/dir list need to be obfuscated
|
|
537
|
-
"""
|
|
538
|
-
cmdspec = [
|
|
539
|
-
sys.executable, '-m', 'PyInstaller.utils.cliutils.makespec',
|
|
540
|
-
'--specpath', self.packpath
|
|
541
|
-
]
|
|
542
|
-
exvalues = '--name', '-N'
|
|
543
|
-
exopts = '-F', '--onefile', '-D', '--onefolder'
|
|
544
|
-
cmdspec.extend(self.filter_opts(self.pyiopts, exvalues, exopts))
|
|
545
|
-
cmdspec.append(self.script)
|
|
546
|
-
logger.debug('%s', ' '.join(cmdspec))
|
|
547
|
-
logger.info('call PyInstaller to generate specfile')
|
|
548
|
-
check_call(cmdspec, stdout=DEVNULL, stderr=DEVNULL)
|
|
549
|
-
|
|
550
|
-
name = os.path.splitext(os.path.basename(self.script))[0]
|
|
551
|
-
rtname = self.ctx.runtime_package_name
|
|
552
|
-
specfile = os.path.join(self.packpath, name + '.spec')
|
|
553
|
-
resfile = os.path.join(self.packpath, 'resources.list')
|
|
554
|
-
hookscript = os.path.join(self.packpath, 'hook-%s.py' % rtname)
|
|
555
|
-
self.patch_specfile(specfile, hookscript, resfile)
|
|
556
|
-
|
|
557
|
-
cmdlist = self.pyicmd + ['--clean', '--workpath', self.workpath]
|
|
558
|
-
cmdlist.extend(self.filter_opts(self.pyiopts, exvalues, exopts))
|
|
559
|
-
cmdlist.append(specfile)
|
|
560
|
-
logger.debug('%s', ' '.join(cmdlist))
|
|
561
|
-
logger.info('call PyInstaller to analysis, '
|
|
562
|
-
'it may take several minutes ...')
|
|
563
|
-
check_call(cmdlist, stdout=DEVNULL, stderr=DEVNULL)
|
|
564
|
-
|
|
565
|
-
with open(resfile, 'rb') as f:
|
|
566
|
-
return marshal.load(f)
|
|
567
|
-
|
|
568
|
-
def build(self):
|
|
569
|
-
"""Generate final bundle to output"""
|
|
570
|
-
script = os.path.join(self.obfpath, os.path.basename(self.inputs[0]))
|
|
571
|
-
cmdlist = self.pyicmd + [
|
|
572
|
-
'--clean',
|
|
573
|
-
'--distpath', self.output,
|
|
574
|
-
'--workpath', self.workpath,
|
|
575
|
-
'--specpath', self.packpath,
|
|
576
|
-
'--additional-hooks-dir', self.packpath,
|
|
577
|
-
]
|
|
578
|
-
cmdlist.extend(self.pyiopts)
|
|
579
|
-
cmdlist.append(script)
|
|
580
|
-
|
|
581
|
-
logger.debug('%s', ' '.join(cmdlist))
|
|
582
|
-
logger.info('call PyInstaller to generate final bundle ...\n')
|
|
583
|
-
check_call(cmdlist)
|
|
584
|
-
logger.info('')
|
|
585
|
-
logger.info('the final bundle "%s" has been generate successfully',
|
|
586
|
-
self.output)
|
|
587
|
-
|
|
588
|
-
def repack(self, *unused):
|
|
589
|
-
"""Only for compatible with Repacker"""
|
|
590
|
-
self.build()
|
|
591
|
-
|
|
592
|
-
def patch_specfile(self, specfile, hookscript, resfile):
|
|
593
|
-
# TODO: non-ascii need specify encoding to open file
|
|
594
|
-
lines = []
|
|
595
|
-
with open(specfile, 'r') as f:
|
|
596
|
-
for line in f:
|
|
597
|
-
if line.startswith('pyz = PYZ'):
|
|
598
|
-
break
|
|
599
|
-
lines.append(line)
|
|
600
|
-
|
|
601
|
-
lines.append(spec_patch_code.format(
|
|
602
|
-
src=repr(os.path.abspath(os.path.dirname(self.script))),
|
|
603
|
-
hookscript=repr(os.path.abspath(hookscript)),
|
|
604
|
-
resfile=repr(os.path.abspath(resfile))))
|
|
605
|
-
|
|
606
|
-
with open(specfile, 'w') as f:
|
|
607
|
-
f.write(''.join(lines))
|
|
608
|
-
|
|
609
|
-
def check(self):
|
|
610
|
-
if os.path.exists(self.output) and self.autoclean:
|
|
611
|
-
n = len(os.path.abspath(self.output).split(os.sep))
|
|
612
|
-
if n < 3:
|
|
613
|
-
prompt = 'Are you sure to remove path "%s" (y/n)? '
|
|
614
|
-
choice = input(prompt % self.output).lower()[:1]
|
|
615
|
-
if not choice == 'y':
|
|
616
|
-
return
|
|
617
|
-
logger.info('clean output path "%s"', self.output)
|
|
618
|
-
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
|