pyarmor 8.5.3__zip → 8.5.5__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.
Files changed (122) hide show
  1. {pyarmor-8.5.3 → pyarmor-8.5.5}/PKG-INFO +1 -1
  2. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/cli/__init__.py +1 -1
  3. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/cli/__main__.py +15 -7
  4. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/cli/context.py +31 -4
  5. pyarmor-8.5.5/pyarmor/cli/core.data.1 +0 -0
  6. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/cli/default.cfg +28 -1
  7. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/cli/generate.py +14 -2
  8. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/cli/repack.py +179 -0
  9. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/config.py +1 -1
  10. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor.egg-info/PKG-INFO +1 -1
  11. pyarmor-8.5.3/pyarmor/cli/core.data.1 +0 -0
  12. {pyarmor-8.5.3 → pyarmor-8.5.5}/MANIFEST.in +0 -0
  13. {pyarmor-8.5.3 → pyarmor-8.5.5}/README.md +0 -0
  14. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/README.rst +0 -0
  15. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/__init__.py +0 -0
  16. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/benchmark.py +0 -0
  17. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/build_meta.py +0 -0
  18. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/cli/bootstrap.py +0 -0
  19. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/cli/bug.py +0 -0
  20. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/cli/config.py +0 -0
  21. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/cli/core.data.2 +0 -0
  22. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/cli/core.data.3 +0 -0
  23. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/cli/docker.py +0 -0
  24. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/cli/hdinfo.py +0 -0
  25. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/cli/merge.py +0 -0
  26. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/cli/mixer.py +0 -0
  27. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/cli/plugin.py +0 -0
  28. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/cli/public_capsule.zip +0 -0
  29. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/cli/register.py +0 -0
  30. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/cli/resource.py +0 -0
  31. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/cli/shell.py +0 -0
  32. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/cobuilder.py +0 -0
  33. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/examples/README-ZH.md +0 -0
  34. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/examples/README.md +0 -0
  35. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/examples/build-for-exe.bat +0 -0
  36. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/examples/build-for-freeze.bat +0 -0
  37. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/examples/build-with-project.bat +0 -0
  38. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/examples/build-with-project.sh +0 -0
  39. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/examples/cx_Freeze/hello.py +0 -0
  40. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/examples/cx_Freeze/queens.py +0 -0
  41. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/examples/cx_Freeze/setup.py +0 -0
  42. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/examples/helloworld/foo.py +0 -0
  43. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/examples/obfuscate-app.bat +0 -0
  44. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/examples/obfuscate-app.sh +0 -0
  45. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/examples/obfuscate-pkg.bat +0 -0
  46. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/examples/obfuscate-pkg.sh +0 -0
  47. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/examples/pack-obfuscated-scripts.bat +0 -0
  48. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/examples/pack-obfuscated-scripts.sh +0 -0
  49. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/examples/py2exe/hello.py +0 -0
  50. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/examples/py2exe/queens.py +0 -0
  51. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/examples/py2exe/setup.py +0 -0
  52. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/examples/pybench/Arithmetic.py +0 -0
  53. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/examples/pybench/Calls.py +0 -0
  54. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/examples/pybench/CommandLine.py +0 -0
  55. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/examples/pybench/Constructs.py +0 -0
  56. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/examples/pybench/Dict.py +0 -0
  57. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/examples/pybench/Exceptions.py +0 -0
  58. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/examples/pybench/Imports.py +0 -0
  59. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/examples/pybench/Instances.py +0 -0
  60. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/examples/pybench/Lists.py +0 -0
  61. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/examples/pybench/Lookups.py +0 -0
  62. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/examples/pybench/NewInstances.py +0 -0
  63. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/examples/pybench/Numbers.py +0 -0
  64. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/examples/pybench/Setup.py +0 -0
  65. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/examples/pybench/Strings.py +0 -0
  66. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/examples/pybench/Tuples.py +0 -0
  67. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/examples/pybench/With.py +0 -0
  68. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/examples/pybench/clockres.py +0 -0
  69. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/examples/pybench/package/__init__.py +0 -0
  70. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/examples/pybench/package/submodule.py +0 -0
  71. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/examples/pybench/pybench.py +0 -0
  72. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/examples/pybench/systimes.py +0 -0
  73. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/examples/simple/queens.py +0 -0
  74. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/examples/testmod/hello.py +0 -0
  75. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/examples/testmod/queens.py +0 -0
  76. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/examples/testpkg/main.py +0 -0
  77. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/examples/testpkg/mypkg/__init__.py +0 -0
  78. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/examples/testpkg/mypkg/foo.py +0 -0
  79. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/helper/__init__.py +0 -0
  80. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/helper/build_data_module.py +0 -0
  81. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/helper/buildext.py +0 -0
  82. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/helper/get_bind_key.py +0 -0
  83. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/helper/get_license_info.py +0 -0
  84. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/helper/get_platform_name.py +0 -0
  85. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/helper/merge.py +0 -0
  86. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/helper/repack.py +0 -0
  87. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/helper/superuntime.py +0 -0
  88. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/license.tri +0 -0
  89. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/packer.py +0 -0
  90. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/platforms/darwin/x86_64/_pytransform.dylib +0 -0
  91. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/platforms/linux/x86/_pytransform.so +0 -0
  92. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/platforms/linux/x86_64/_pytransform.so +0 -0
  93. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/platforms/windows/x86/_pytransform.dll +0 -0
  94. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/platforms/windows/x86_64/_pytransform.dll +0 -0
  95. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/plugins/README.md +0 -0
  96. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/plugins/check_ntp_time.py +0 -0
  97. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/polyfills/__init__.py +0 -0
  98. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/polyfills/argparse.py +0 -0
  99. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/product.key +0 -0
  100. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/project.py +0 -0
  101. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/protect_code.pt +0 -0
  102. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/protect_code2.pt +0 -0
  103. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/public.key +0 -0
  104. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/public_capsule.zip +0 -0
  105. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/pyarmor-deprecated.py +0 -0
  106. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/pyarmor-webui.py +0 -0
  107. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/pyarmor.py +0 -0
  108. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/pyimcore.py +0 -0
  109. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/pyshield.key +0 -0
  110. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/pyshield.lic +0 -0
  111. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/pytransform.py +0 -0
  112. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/reform.py +0 -0
  113. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/register.py +0 -0
  114. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/sppmode.py +0 -0
  115. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor/utils.py +0 -0
  116. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor.egg-info/SOURCES.txt +0 -0
  117. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor.egg-info/dependency_links.txt +0 -0
  118. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor.egg-info/entry_points.txt +0 -0
  119. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor.egg-info/requires.txt +0 -0
  120. {pyarmor-8.5.3 → pyarmor-8.5.5}/pyarmor.egg-info/top_level.txt +0 -0
  121. {pyarmor-8.5.3 → pyarmor-8.5.5}/setup.cfg +0 -0
  122. {pyarmor-8.5.3 → pyarmor-8.5.5}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 1.1
2
2
  Name: pyarmor
3
- Version: 8.5.3
3
+ Version: 8.5.5
4
4
  Summary: A tool used to obfuscate python scripts, bind obfuscated scripts to fixed machine or expire obfuscated scripts.
5
5
  Home-page: https://github.com/dashingsoft/pyarmor
6
6
  Author: Jondy Zhao
@@ -1,6 +1,6 @@
1
1
  import logging
2
2
 
3
- __VERSION__ = '8.5.3'
3
+ __VERSION__ = '8.5.5'
4
4
 
5
5
  logger = logging.getLogger('cli')
6
6
 
@@ -135,8 +135,8 @@ def format_gen_args(ctx, args):
135
135
  options['user_data'] = args.bind_data
136
136
 
137
137
  if args.pack:
138
- dist_path = os.path.join(ctx.repack_path, 'dist')
139
- logger.info('implicitly set output to "%s"', dist_path)
138
+ dist_path = ctx.pack_obfpath
139
+ logger.info('implicitly save obfuscated scripts to "%s"', dist_path)
140
140
  options['output'] = dist_path
141
141
 
142
142
  return options
@@ -209,8 +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
- if not os.path.isfile(args.pack):
213
- raise CliError('--pack must be an executable file')
212
+ choices = 'auto', 'onefile', 'onedir', 'F', 'D', 'FC', 'DC'
213
+ if args.pack not in choices and not os.path.isfile(args.pack):
214
+ raise CliError('--pack must be an executable file, '
215
+ '"auto", "onefile" or "onedir"')
214
216
  if args.no_runtime:
215
217
  raise CliError('--pack conficts with --no-runtime, --use-runtime')
216
218
  if ctx.import_prefix:
@@ -230,10 +232,16 @@ def cmd_gen(ctx, args):
230
232
  return _cmd_gen_key(builder, options)
231
233
  elif args.inputs[0].lower() in ('runtime', 'run', 'r'):
232
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)
233
241
  elif args.pack:
234
242
  from .repack import Repacker
235
243
  codesign = ctx.cfg['pack'].get('codesign_identify', None)
236
- packer = Repacker(args.pack, ctx.repack_path, codesign=codesign)
244
+ packer = Repacker(args.pack, ctx.pack_basepath, codesign=codesign)
237
245
  packer.check()
238
246
  builder.process(options, packer=packer)
239
247
  Plugin.post_build(ctx, pack=args.pack)
@@ -412,8 +420,8 @@ https://pyarmor.readthedocs.io/en/stable/reference/man.html#pyarmor-gen
412
420
  'action arguments'
413
421
  ).add_mutually_exclusive_group()
414
422
  group.add_argument(
415
- '--pack', metavar='BUNDLE',
416
- help='repack bundle with obfuscated scripts'
423
+ '--pack', metavar='MODE',
424
+ help='specify pack mode, onefile or onedir'
417
425
  )
418
426
  group.add_argument(
419
427
  '--no-runtime', action='store_true', help=argparse.SUPPRESS
@@ -366,10 +366,6 @@ class Context(object):
366
366
  return self._check_logpath(
367
367
  self.cfg['logging'].get('trace_logfile', 'pyarmor.trace.log'))
368
368
 
369
- @property
370
- def repack_path(self):
371
- return os.path.join(self.local_path, 'pack')
372
-
373
369
  def _optb(self, section, name):
374
370
  return self.cfg.getboolean(section, name, vars=self.cmd_options)
375
371
 
@@ -608,6 +604,10 @@ class Context(object):
608
604
  def runtime_obf_key_mode(self):
609
605
  return self._opti('runtime', 'obf_key_mode')
610
606
 
607
+ @property
608
+ def runtime_patch_extension(self):
609
+ return self._opti('runtime', 'patch_extension')
610
+
611
611
  #
612
612
  # RFT settings
613
613
  #
@@ -717,3 +717,30 @@ class Context(object):
717
717
 
718
718
  with get_response('pyarmor.dashingsoft.com') as res:
719
719
  return res.read()
720
+
721
+ #
722
+ # Pack options for auto/onefile/onefolder mode
723
+ #
724
+ @property
725
+ def pyi_options(self):
726
+ from json import loads as json_loads
727
+ from shlex import split as split_opt
728
+ pyi_opts = []
729
+ jsmarker = 'json::'
730
+ for line in self.cfg['pack'].get('pyi_options', '').splitlines():
731
+ line = line.strip()
732
+ if line.startswith(jsmarker):
733
+ pyi_opts.extend(json_loads(line[len(jsmarker):]))
734
+ elif line.startswith('-'):
735
+ pyi_opts.extend(split_opt(line))
736
+ elif line:
737
+ pyi_opts.append(line)
738
+ return pyi_opts
739
+
740
+ @property
741
+ def pack_basepath(self):
742
+ return os.path.join(self.local_path, 'pack')
743
+
744
+ @property
745
+ def pack_obfpath(self):
746
+ return os.path.join(self.pack_basepath, 'dist')
Binary file
@@ -3,7 +3,7 @@
3
3
  ;; Pyarmor version
4
4
  major = 8
5
5
  minor = 5
6
- patch = 3
6
+ patch = 5
7
7
 
8
8
  ;; Compatible core version
9
9
  cli.core = 6.5.1
@@ -223,6 +223,19 @@ package_name_format = pyarmor_runtime_{suffix}
223
223
  ;; pyarmor_runtime.so
224
224
  simple_extension_name = 1
225
225
 
226
+ ;; Whether patching extension to embedded runtime key
227
+ ;;
228
+ ;; 0: do not patch extension, but store runtime key to one file
229
+ ;; 1: runtime key is embedded into extension
230
+ ;;
231
+ ;; The purpose is to solve code sign issue for Darwin platform
232
+ ;; Do not patch extension will keep code sign, so need not re-sign
233
+ ;; But it need an extra file.
234
+ ;;
235
+ ;; Note: it's different from outer runtime key.
236
+ ;;
237
+ patch_extension = 1
238
+
226
239
  ;; Obfuscate runtime key
227
240
  ;; 0: no obfuscation
228
241
  ;; 1: simple obfuscation
@@ -342,6 +355,20 @@ strip = 0
342
355
  ;; append, append it to archive
343
356
  no_matched_pyc = error
344
357
 
358
+ ;; Extra options to call PyInstaller when packing the obfuscated scripts
359
+ ;; One option one line, name and value separted by one whitespace
360
+ ;; For example
361
+ ;;
362
+ ;; pyi_options = -w
363
+ ;; --add-data default.cfg:.
364
+ ;; --icon myapp.ico
365
+ ;;
366
+ ;; The following options could not be used here:
367
+ ;;
368
+ ;; --distpath, --workpath, --specpath
369
+ ;;
370
+ ; pyi_options =
371
+
345
372
  [bcc]
346
373
  unsupported_functions = exec eval super locals __assert_armored__
347
374
  unsupported_nodes = AsyncFunctionDef AsyncFor AsyncWith Await Yield YieldFrom GeneratorExp NamedExpr MatchValue MatchSingleton MatchSequence MatchMapping MatchClass MatchStar MatchAs MatchOr
@@ -62,6 +62,13 @@ class Finder(object):
62
62
  self.ctx.obfuscated_modules.add(res.pkgname)
63
63
  self.ctx.extra_resources.append(res)
64
64
 
65
+ def append(self, resources):
66
+ resnames = [x.pkgname for x in self.ctx.resources]
67
+ for res in self._build_resource(resources):
68
+ if res.pkgname not in resnames:
69
+ self.ctx.obfuscated_modules.add(res.pkgname)
70
+ self.ctx.extra_resources.append(res)
71
+
65
72
  def process(self):
66
73
  logger.info('search inputs ...')
67
74
  self.prepare(self.ctx.input_paths)
@@ -149,8 +156,13 @@ class Builder(object):
149
156
  finder = Finder(self.ctx)
150
157
  finder.process()
151
158
 
152
- if packer and options.get('self_contained'):
153
- finder.process_extra(packer.contents)
159
+ if packer:
160
+ if options.get('self_contained'):
161
+ finder.process_extra(packer.contents)
162
+ if hasattr(packer, 'analysis'):
163
+ auto_resources = packer.analysis()
164
+ logger.info('find extra resources: %s', auto_resources)
165
+ finder.append(auto_resources)
154
166
 
155
167
  Pytransform3.pre_build(self.ctx)
156
168
 
@@ -3,6 +3,7 @@ import marshal
3
3
  import os
4
4
  import shutil
5
5
  import struct
6
+ import sys
6
7
  import tempfile
7
8
 
8
9
  from importlib._bootstrap_external import _code_to_timestamp_pyc
@@ -435,3 +436,181 @@ class Repacker:
435
436
  check_call(cmdlist, stdout=DEVNULL, stderr=DEVNULL)
436
437
  except Exception as e:
437
438
  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
+ cmdspec.extend(self.filter_opts(self.pyiopts, ('--name', '-N')))
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
+ name = os.path.splitext(os.path.basename(self.script))[0]
549
+ rtname = self.ctx.runtime_package_name
550
+ specfile = os.path.join(self.packpath, name + '.spec')
551
+ resfile = os.path.join(self.packpath, 'resources.list')
552
+ hookscript = os.path.join(self.packpath, 'hook-%s.py' % rtname)
553
+ self.patch_specfile(specfile, hookscript, resfile)
554
+
555
+ cmdlist = self.pyicmd + ['--clean', '--workpath', self.workpath]
556
+ cmdlist.extend(self.pyiopts)
557
+ cmdlist.append(specfile)
558
+ logger.debug('%s', ' '.join(cmdlist))
559
+ logger.info('call PyInstaller to analysis, '
560
+ 'it may take several minutes ...')
561
+ check_call(cmdlist, stdout=DEVNULL, stderr=DEVNULL)
562
+
563
+ with open(resfile, 'rb') as f:
564
+ return marshal.load(f)
565
+
566
+ def build(self):
567
+ """Generate final bundle to output"""
568
+ script = os.path.join(self.obfpath, os.path.basename(self.inputs[0]))
569
+ cmdlist = self.pyicmd + [
570
+ '--clean',
571
+ '--distpath', self.output,
572
+ '--workpath', self.workpath,
573
+ '--specpath', self.packpath,
574
+ '--additional-hooks-dir', self.packpath,
575
+ ]
576
+ cmdlist.extend(self.pyiopts)
577
+ cmdlist.append(script)
578
+
579
+ logger.debug('%s', ' '.join(cmdlist))
580
+ logger.info('call PyInstaller to generate final bundle ...\n')
581
+ check_call(cmdlist)
582
+ logger.info('')
583
+ logger.info('the final bundle "%s" has been generate successfully',
584
+ self.output)
585
+
586
+ def repack(self, *unused):
587
+ """Only for compatible with Repacker"""
588
+ self.build()
589
+
590
+ def patch_specfile(self, specfile, hookscript, resfile):
591
+ # TODO: non-ascii need specify encoding to open file
592
+ lines = []
593
+ with open(specfile, 'r') as f:
594
+ for line in f:
595
+ if line.startswith('pyz = PYZ'):
596
+ break
597
+ lines.append(line)
598
+
599
+ lines.append(spec_patch_code.format(
600
+ src=repr(os.path.abspath(os.path.dirname(self.script))),
601
+ hookscript=repr(os.path.abspath(hookscript)),
602
+ resfile=repr(os.path.abspath(resfile))))
603
+
604
+ with open(specfile, 'w') as f:
605
+ f.write(''.join(lines))
606
+
607
+ def check(self):
608
+ if os.path.exists(self.output) and self.autoclean:
609
+ n = len(os.path.abspath(self.output).split(os.sep))
610
+ if n < 3:
611
+ prompt = 'Are you sure to remove path "%s" (y/n)? '
612
+ choice = input(prompt % self.output).lower()[:1]
613
+ if not choice == 'y':
614
+ return
615
+ logger.info('clean output path "%s"', self.output)
616
+ shutil.rmtree(self.output)
@@ -1,6 +1,6 @@
1
1
  from sys import platform
2
2
 
3
- version = '8.5.3'
3
+ version = '8.5.5'
4
4
 
5
5
  # The corresponding version of pytransform.so
6
6
  core_version = 'r52.6'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 1.1
2
2
  Name: pyarmor
3
- Version: 8.5.3
3
+ Version: 8.5.5
4
4
  Summary: A tool used to obfuscate python scripts, bind obfuscated scripts to fixed machine or expire obfuscated scripts.
5
5
  Home-page: https://github.com/dashingsoft/pyarmor
6
6
  Author: Jondy Zhao
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