pyarmor.cli 9.2.6__4-py3-none-any.whl
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/cli/__init__.py +46 -0
- pyarmor/cli/__main__.py +812 -0
- pyarmor/cli/batch.py +62 -0
- pyarmor/cli/bootstrap.py +207 -0
- pyarmor/cli/bug.py +137 -0
- pyarmor/cli/command.py +563 -0
- pyarmor/cli/config.py +306 -0
- pyarmor/cli/context.py +790 -0
- pyarmor/cli/core.data.1 +0 -0
- pyarmor/cli/core.data.2 +0 -0
- pyarmor/cli/core.data.3 +0 -0
- pyarmor/cli/default.cfg +564 -0
- pyarmor/cli/docker.py +192 -0
- pyarmor/cli/generate.py +256 -0
- pyarmor/cli/hdinfo.py +81 -0
- pyarmor/cli/merge.py +232 -0
- pyarmor/cli/mixer.py +109 -0
- pyarmor/cli/model.py +460 -0
- pyarmor/cli/plugin.py +292 -0
- pyarmor/cli/project.py +1281 -0
- pyarmor/cli/public_capsule.zip +0 -0
- pyarmor/cli/register.py +1093 -0
- pyarmor/cli/repack.py +793 -0
- pyarmor/cli/resource.py +265 -0
- pyarmor/cli/shell.py +481 -0
- pyarmor_cli-9.2.6.dist-info/METADATA +74 -0
- pyarmor_cli-9.2.6.dist-info/RECORD +30 -0
- pyarmor_cli-9.2.6.dist-info/WHEEL +6 -0
- pyarmor_cli-9.2.6.dist-info/entry_points.txt +3 -0
- pyarmor_cli-9.2.6.dist-info/top_level.txt +1 -0
pyarmor/cli/context.py
ADDED
|
@@ -0,0 +1,790 @@
|
|
|
1
|
+
#! /usr/bin/env python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
#
|
|
4
|
+
#############################################################
|
|
5
|
+
# #
|
|
6
|
+
# Copyright @ 2023 - Dashingsoft corp. #
|
|
7
|
+
# All rights reserved. #
|
|
8
|
+
# #
|
|
9
|
+
# Pyarmor #
|
|
10
|
+
# #
|
|
11
|
+
# Version: 8.0.1 - #
|
|
12
|
+
# #
|
|
13
|
+
#############################################################
|
|
14
|
+
#
|
|
15
|
+
#
|
|
16
|
+
# @File: cli/context.py
|
|
17
|
+
#
|
|
18
|
+
# @Author: Jondy Zhao (pyarmor@163.com)
|
|
19
|
+
#
|
|
20
|
+
# @Create Date: 2022-12-06
|
|
21
|
+
#
|
|
22
|
+
import configparser
|
|
23
|
+
import os
|
|
24
|
+
import sys
|
|
25
|
+
|
|
26
|
+
bootstrap_template = '''# Pyarmor $rev, $timestamp
|
|
27
|
+
from $package import __pyarmor__
|
|
28
|
+
__pyarmor__(__name__, $path, $code)
|
|
29
|
+
'''
|
|
30
|
+
|
|
31
|
+
runtime_package_template = '''# Pyarmor $rev, $timestamp
|
|
32
|
+
from .pyarmor_runtime import __pyarmor__
|
|
33
|
+
'''
|
|
34
|
+
|
|
35
|
+
multi_runtime_package_template = '''# Pyarmor $rev, $timestamp
|
|
36
|
+
def __pyarmor__():
|
|
37
|
+
import platform
|
|
38
|
+
import sys
|
|
39
|
+
from struct import calcsize
|
|
40
|
+
|
|
41
|
+
def format_system():
|
|
42
|
+
plat = platform.system().lower()
|
|
43
|
+
plat = ('cygwin' if plat.startswith('cygwin') else
|
|
44
|
+
'linux' if plat.startswith('linux') else
|
|
45
|
+
'freebsd' if plat.startswith(
|
|
46
|
+
('freebsd', 'openbsd', 'isilon onefs')) else plat)
|
|
47
|
+
if plat == 'linux':
|
|
48
|
+
if hasattr(sys, 'getandroidapilevel'):
|
|
49
|
+
plat = 'android'
|
|
50
|
+
else:
|
|
51
|
+
cname, cver = platform.libc_ver()
|
|
52
|
+
if cname == 'musl':
|
|
53
|
+
plat = 'alpine'
|
|
54
|
+
elif cname == 'libc':
|
|
55
|
+
plat = 'android'
|
|
56
|
+
return plat
|
|
57
|
+
|
|
58
|
+
def format_machine():
|
|
59
|
+
mach = platform.machine().lower()
|
|
60
|
+
arch_table = (
|
|
61
|
+
('x86', ('i386', 'i486', 'i586', 'i686', 'x86')),
|
|
62
|
+
('x86_64', ('x64', 'x86_64', 'amd64', 'intel')),
|
|
63
|
+
('arm', ('armv5',)),
|
|
64
|
+
('armv6', ('armv6l',)),
|
|
65
|
+
('armv7', ('armv7l',)),
|
|
66
|
+
('aarch32', ('aarch32',)),
|
|
67
|
+
('aarch64', ('aarch64', 'arm64')),
|
|
68
|
+
('ppc64le', ('ppc64le',)),
|
|
69
|
+
('mips32el', ('mipsel', 'mips32el')),
|
|
70
|
+
('mips64el', ('mips64el',)),
|
|
71
|
+
('riscv64', ('riscv64',)),
|
|
72
|
+
)
|
|
73
|
+
for alias, archlist in arch_table:
|
|
74
|
+
if mach in archlist:
|
|
75
|
+
mach = alias
|
|
76
|
+
break
|
|
77
|
+
return mach
|
|
78
|
+
|
|
79
|
+
plat, mach = format_system(), format_machine()
|
|
80
|
+
if plat == 'windows' and mach == 'x86_64':
|
|
81
|
+
bitness = calcsize('P'.encode()) * 8
|
|
82
|
+
if bitness == 32:
|
|
83
|
+
mach = 'x86'
|
|
84
|
+
# mach = 'universal' if plat == 'darwin' else mach
|
|
85
|
+
name = '.'.join(['_'.join([plat, mach]), 'pyarmor_runtime'])
|
|
86
|
+
return __import__(name, globals(), locals(), ['__pyarmor__'], level=1)
|
|
87
|
+
__pyarmor__ = __pyarmor__().__pyarmor__
|
|
88
|
+
'''
|
|
89
|
+
|
|
90
|
+
runtime_package_template3 = '''# Pyarmor $rev, $timestamp
|
|
91
|
+
from importlib.machinery import ExtensionFileLoader
|
|
92
|
+
from sysconfig import get_platform
|
|
93
|
+
__pyarmor__ = ExtensionFileLoader(
|
|
94
|
+
'.pyarmor_runtime', __file__.replace('__init__.py', 'pyarmor_runtime.so')
|
|
95
|
+
).load_module().__pyarmor__
|
|
96
|
+
'''
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def format_platform(plat=None, arch=None):
|
|
100
|
+
from struct import calcsize
|
|
101
|
+
from fnmatch import fnmatchcase
|
|
102
|
+
|
|
103
|
+
# Fix pyarmor.cli.core 6.5.2 issue, may be removed in 6.5.3
|
|
104
|
+
if plat is None and arch is None:
|
|
105
|
+
if os.getenv('PYARMOR_PLATFORM'):
|
|
106
|
+
plat, arch = os.getenv('PYARMOR_PLATFORM').split('.')
|
|
107
|
+
else:
|
|
108
|
+
from platform import system, machine
|
|
109
|
+
plat, arch = system().lower(), machine().lower()
|
|
110
|
+
|
|
111
|
+
plat_table = (
|
|
112
|
+
('windows', ('windows',)),
|
|
113
|
+
('cygwin', ('cygwin*',)),
|
|
114
|
+
('darwin', ('darwin',)),
|
|
115
|
+
('linux', ('linux*',)),
|
|
116
|
+
('freebsd', ('freebsd*', 'openbsd*', 'isilon onefs')),
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
arch_table = (
|
|
120
|
+
('x86', ('i?86', 'x86')),
|
|
121
|
+
('x86_64', ('x64', 'x86_64', 'amd64', 'intel')),
|
|
122
|
+
('arm', ('armv5',)),
|
|
123
|
+
('armv6', ('armv6l',)),
|
|
124
|
+
('armv7', ('armv7l',)),
|
|
125
|
+
('aarch32', ('aarch32',)),
|
|
126
|
+
('aarch64', ('aarch64', 'arm64')),
|
|
127
|
+
('ppc64le', ('ppc64le',)),
|
|
128
|
+
('mips32el', ('mipsel', 'mips32el')),
|
|
129
|
+
('mips64el', ('mips64el',)),
|
|
130
|
+
('riscv64', ('riscv64',)),
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
for alias, platlist in plat_table:
|
|
134
|
+
if any([fnmatchcase(plat, x) for x in platlist]):
|
|
135
|
+
plat = alias
|
|
136
|
+
break
|
|
137
|
+
|
|
138
|
+
for alias, archlist in arch_table:
|
|
139
|
+
if any([fnmatchcase(arch, x) for x in archlist]):
|
|
140
|
+
mach = alias
|
|
141
|
+
break
|
|
142
|
+
else:
|
|
143
|
+
raise RuntimeError('unsupported arch "%s"' % arch)
|
|
144
|
+
|
|
145
|
+
if plat == 'linux' and hasattr(sys, 'getandroidapilevel'):
|
|
146
|
+
plat = 'android'
|
|
147
|
+
|
|
148
|
+
if plat == 'windows' and mach == 'x86_64':
|
|
149
|
+
bitness = calcsize('P'.encode()) * 8
|
|
150
|
+
if bitness == 32:
|
|
151
|
+
mach = 'x86'
|
|
152
|
+
|
|
153
|
+
return '.'.join([plat, mach])
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
class Context(object):
|
|
157
|
+
|
|
158
|
+
def __init__(self, home, gpath='', lpath='', rpath='', encoding=None):
|
|
159
|
+
self.home_path = os.path.normpath(home)
|
|
160
|
+
self.global_path = os.path.join(home, gpath if gpath else 'config')
|
|
161
|
+
self.local_path = lpath if lpath else '.pyarmor'
|
|
162
|
+
self.reg_path = self.home_path if not rpath else \
|
|
163
|
+
rpath if os.path.isabs(rpath) else \
|
|
164
|
+
os.path.join(self.home_path, rpath)
|
|
165
|
+
|
|
166
|
+
# self.encoding is just for reading config file
|
|
167
|
+
self.encoding = encoding if encoding else 'utf-8'
|
|
168
|
+
cfglist = self.default_config, self.global_config, self.local_config
|
|
169
|
+
self.cfg = self._read_config(cfglist, encoding=self.encoding)
|
|
170
|
+
|
|
171
|
+
# self.runtime_package = 'pyarmor_runtime'
|
|
172
|
+
# self.runtime_suffix = '_000000'
|
|
173
|
+
# default inner key filename within runtime package
|
|
174
|
+
self.runtime_keyfile = '.pyarmor.ikey'
|
|
175
|
+
|
|
176
|
+
self.bootstrap_template = bootstrap_template
|
|
177
|
+
|
|
178
|
+
# Alias format for duplicated input names
|
|
179
|
+
self.alias_suffix = '{0}-{1}'
|
|
180
|
+
|
|
181
|
+
self.input_paths = []
|
|
182
|
+
self.outputs = []
|
|
183
|
+
self.resources = []
|
|
184
|
+
self.extra_resources = []
|
|
185
|
+
|
|
186
|
+
self.module_relations = {}
|
|
187
|
+
self.module_types = {}
|
|
188
|
+
self.variable_types = {}
|
|
189
|
+
self.module_builtins = set()
|
|
190
|
+
|
|
191
|
+
self.obfuscated_modules = set()
|
|
192
|
+
self.extra_libs = {}
|
|
193
|
+
|
|
194
|
+
self.rft_auto_excludes = set(['super'])
|
|
195
|
+
self.rft_export_names = set()
|
|
196
|
+
self.rft_transform_op = '?'
|
|
197
|
+
|
|
198
|
+
self.runtime_key = None
|
|
199
|
+
|
|
200
|
+
self.cmd_options = {}
|
|
201
|
+
self.plugins = []
|
|
202
|
+
|
|
203
|
+
def _read_config(self, filelist, encoding=None):
|
|
204
|
+
cfg = configparser.ConfigParser(
|
|
205
|
+
empty_lines_in_values=False,
|
|
206
|
+
interpolation=configparser.ExtendedInterpolation(),
|
|
207
|
+
)
|
|
208
|
+
encoding = encoding or self.encoding
|
|
209
|
+
cfg.read(filelist, encoding=encoding)
|
|
210
|
+
return cfg
|
|
211
|
+
|
|
212
|
+
def _named_config(self, name, encoding=None):
|
|
213
|
+
nlist = []
|
|
214
|
+
if self.cfg.getboolean('builder', 'propagate_package_options'):
|
|
215
|
+
i = name.find('.')
|
|
216
|
+
while i > -1:
|
|
217
|
+
nlist.append(name[:i])
|
|
218
|
+
i = name.find('.', i+1)
|
|
219
|
+
nlist.append(name)
|
|
220
|
+
flist = [os.path.join(b, a)
|
|
221
|
+
for a in nlist
|
|
222
|
+
for b in (self.global_path, self.local_path)]
|
|
223
|
+
return self._read_config(flist, encoding=encoding)
|
|
224
|
+
|
|
225
|
+
def read_token(self):
|
|
226
|
+
for filename in (self.license_group_token, self.license_token):
|
|
227
|
+
if os.path.exists(filename):
|
|
228
|
+
with open(filename, 'rb') as f:
|
|
229
|
+
return f.read()
|
|
230
|
+
|
|
231
|
+
def save_token(self, data):
|
|
232
|
+
with open(self.license_token, 'wb') as f:
|
|
233
|
+
if not data.endswith(b'=='):
|
|
234
|
+
raise RuntimeError('got invalid token %r' % data)
|
|
235
|
+
f.write(data)
|
|
236
|
+
|
|
237
|
+
def save_group_token(self, data):
|
|
238
|
+
with open(self.license_group_token, 'wb') as f:
|
|
239
|
+
if not data.endswith(b'=='):
|
|
240
|
+
raise RuntimeError('got invalid token %r' % data)
|
|
241
|
+
f.write(data)
|
|
242
|
+
|
|
243
|
+
def clear_token(self):
|
|
244
|
+
if os.path.exists(self.license_token):
|
|
245
|
+
with open(self.license_token, 'wb') as f:
|
|
246
|
+
f.close()
|
|
247
|
+
|
|
248
|
+
def group_device_file(self, devid):
|
|
249
|
+
filename = 'pyarmor-group-device.%s' % devid
|
|
250
|
+
return os.path.join(self.local_path, 'group', filename)
|
|
251
|
+
|
|
252
|
+
def read_license(self):
|
|
253
|
+
if os.path.exists(self.license_file):
|
|
254
|
+
with open(self.license_file, 'rb') as f:
|
|
255
|
+
return f.read()
|
|
256
|
+
|
|
257
|
+
def push(self, options):
|
|
258
|
+
finder = {}
|
|
259
|
+
for opt in ('recursive', 'findall', 'includes', 'excludes'):
|
|
260
|
+
if opt in options:
|
|
261
|
+
finder[opt] = options[opt]
|
|
262
|
+
if finder:
|
|
263
|
+
self.cmd_options['finder'] = finder
|
|
264
|
+
self.cmd_options.update(options)
|
|
265
|
+
|
|
266
|
+
def pop(self):
|
|
267
|
+
return self.cmd_options.clear()
|
|
268
|
+
|
|
269
|
+
def get_res_options(self, name, sect='finder'):
|
|
270
|
+
options = {}
|
|
271
|
+
if self.cfg.has_section(sect):
|
|
272
|
+
options.update(self.cfg.items(sect))
|
|
273
|
+
if sect == 'finder':
|
|
274
|
+
options.update(self.cmd_options.get('finder', {}))
|
|
275
|
+
elif sect == 'builder':
|
|
276
|
+
options.update(self.cmd_options)
|
|
277
|
+
extra_sect = ':'.join([name, sect])
|
|
278
|
+
if self.cfg.has_section(extra_sect):
|
|
279
|
+
options.update(self.cfg.items(extra_sect))
|
|
280
|
+
if name:
|
|
281
|
+
# If input path is '.', package name will start with '..'
|
|
282
|
+
cfg = self._named_config(name.strip('.') + '.ruler')
|
|
283
|
+
if cfg.has_section(sect):
|
|
284
|
+
options.update(cfg.items(sect))
|
|
285
|
+
return options
|
|
286
|
+
|
|
287
|
+
def get_path(self, local=True):
|
|
288
|
+
return self.local_path if local else self.global_path
|
|
289
|
+
|
|
290
|
+
def get_filename(self, local=True, name=None):
|
|
291
|
+
return os.path.join(self.get_path(local), name + '.ruler') if name \
|
|
292
|
+
else self.local_config if local else self.global_config
|
|
293
|
+
|
|
294
|
+
def version_info(self, verbose=3):
|
|
295
|
+
# 8.0.1
|
|
296
|
+
# 8.0.1 (trial)
|
|
297
|
+
# 8.0.1 (basic), 002000
|
|
298
|
+
# 8.0.1 (group), 002002, Product
|
|
299
|
+
# 8.0.1 (group), 002002, Product, Company
|
|
300
|
+
rev = '.'.join(self.version)
|
|
301
|
+
if not verbose:
|
|
302
|
+
return rev
|
|
303
|
+
|
|
304
|
+
licinfo = self.license_info
|
|
305
|
+
lictype = 'basic' if licinfo['features'] in (1, 17) else \
|
|
306
|
+
'pro' if licinfo['features'] == 7 else \
|
|
307
|
+
'group' if licinfo['features'] == 15 else \
|
|
308
|
+
'ci' if licinfo['features'] == 23 else \
|
|
309
|
+
'trial' if licinfo['token'] == 0 else 'unknown'
|
|
310
|
+
verinfo = ['%s (%s)' % (rev, lictype)]
|
|
311
|
+
|
|
312
|
+
if verbose > 1:
|
|
313
|
+
verinfo.append(licinfo['licno'][-6:])
|
|
314
|
+
|
|
315
|
+
if verbose > 2:
|
|
316
|
+
pname = licinfo['product']
|
|
317
|
+
verinfo.append(pname)
|
|
318
|
+
|
|
319
|
+
if verbose > 3:
|
|
320
|
+
regname = licinfo['regname']
|
|
321
|
+
if regname:
|
|
322
|
+
verinfo.append(regname)
|
|
323
|
+
|
|
324
|
+
return ', '.join(verinfo)
|
|
325
|
+
|
|
326
|
+
@property
|
|
327
|
+
def version(self):
|
|
328
|
+
return [self.cfg.get('pyarmor', x) for x in ('major', 'minor', 'patch')]
|
|
329
|
+
|
|
330
|
+
@property
|
|
331
|
+
def python_version(self):
|
|
332
|
+
return sys.version_info[:2]
|
|
333
|
+
|
|
334
|
+
@property
|
|
335
|
+
def py_gil_disabled(self):
|
|
336
|
+
from sysconfig import get_config_var
|
|
337
|
+
return 1 if get_config_var("Py_GIL_DISABLED") else 0
|
|
338
|
+
|
|
339
|
+
@property
|
|
340
|
+
def default_config(self):
|
|
341
|
+
return os.path.join(os.path.dirname(__file__), 'default.cfg')
|
|
342
|
+
|
|
343
|
+
@property
|
|
344
|
+
def global_config(self):
|
|
345
|
+
return os.path.join(self.global_path, 'global')
|
|
346
|
+
|
|
347
|
+
@property
|
|
348
|
+
def local_config(self):
|
|
349
|
+
return os.path.join(self.local_path, 'config')
|
|
350
|
+
|
|
351
|
+
def _make_public_capsule(self, filename):
|
|
352
|
+
from shutil import copy
|
|
353
|
+
os.makedirs(os.path.dirname(filename), exist_ok=True)
|
|
354
|
+
path = os.path.dirname(__file__)
|
|
355
|
+
public_capsule = os.path.join(path, 'public_capsule.zip')
|
|
356
|
+
copy(public_capsule, filename)
|
|
357
|
+
|
|
358
|
+
@property
|
|
359
|
+
def private_capsule(self):
|
|
360
|
+
filename = os.path.join(self.reg_path, '.pyarmor_capsule.zip')
|
|
361
|
+
if not os.path.exists(filename):
|
|
362
|
+
self._make_public_capsule(filename)
|
|
363
|
+
return filename
|
|
364
|
+
|
|
365
|
+
@property
|
|
366
|
+
def license_file(self):
|
|
367
|
+
return os.path.join(self.reg_path, 'license.lic')
|
|
368
|
+
|
|
369
|
+
@property
|
|
370
|
+
def license_token(self):
|
|
371
|
+
return os.path.join(self.reg_path, '.license.token')
|
|
372
|
+
|
|
373
|
+
@property
|
|
374
|
+
def license_group_token(self):
|
|
375
|
+
return os.path.join(self.reg_path, '.license.group.token')
|
|
376
|
+
|
|
377
|
+
@property
|
|
378
|
+
def license_info(self):
|
|
379
|
+
from .register import parse_token
|
|
380
|
+
return parse_token(self.read_token())
|
|
381
|
+
|
|
382
|
+
@property
|
|
383
|
+
def native_platform(self):
|
|
384
|
+
from platform import system, machine
|
|
385
|
+
return '.'.join([system().lower(), machine().lower()])
|
|
386
|
+
|
|
387
|
+
@property
|
|
388
|
+
def pyarmor_platform(self):
|
|
389
|
+
platname = os.getenv('PYARMOR_PLATFORM', self.native_platform)
|
|
390
|
+
return format_platform(*platname.split('.'))
|
|
391
|
+
|
|
392
|
+
@property
|
|
393
|
+
def target_platforms(self):
|
|
394
|
+
platforms = self.cmd_options.get('platforms')
|
|
395
|
+
return platforms if platforms else [self.native_platform]
|
|
396
|
+
|
|
397
|
+
def _check_logpath(self, logfile):
|
|
398
|
+
path = os.path.dirname(logfile)
|
|
399
|
+
if path not in ('', '.') and not os.path.exists(path):
|
|
400
|
+
os.makedirs(path)
|
|
401
|
+
return logfile
|
|
402
|
+
|
|
403
|
+
@property
|
|
404
|
+
def debug_logfile(self):
|
|
405
|
+
return self._check_logpath(
|
|
406
|
+
self.cfg['logging'].get('debug_logfile', 'pyarmor.debug.log'))
|
|
407
|
+
|
|
408
|
+
@property
|
|
409
|
+
def trace_logfile(self):
|
|
410
|
+
return self._check_logpath(
|
|
411
|
+
self.cfg['logging'].get('trace_logfile', 'pyarmor.trace.log'))
|
|
412
|
+
|
|
413
|
+
def _optb(self, section, name):
|
|
414
|
+
return self.cfg.getboolean(section, name, vars=self.cmd_options)
|
|
415
|
+
|
|
416
|
+
def _opts(self, section, name):
|
|
417
|
+
return self.cfg.get(section, name, vars=self.cmd_options)
|
|
418
|
+
|
|
419
|
+
def _opti(self, section, name):
|
|
420
|
+
return self.cfg.getint(section, name, vars=self.cmd_options)
|
|
421
|
+
|
|
422
|
+
@property
|
|
423
|
+
def recursive(self):
|
|
424
|
+
return self._optb('finder', 'recursive')
|
|
425
|
+
|
|
426
|
+
@property
|
|
427
|
+
def findall(self):
|
|
428
|
+
return self._optb('finder', 'findall')
|
|
429
|
+
|
|
430
|
+
@property
|
|
431
|
+
def pyexts(self):
|
|
432
|
+
return self._opts('finder', 'pyexts').split()
|
|
433
|
+
|
|
434
|
+
@property
|
|
435
|
+
def enable_themida(self):
|
|
436
|
+
return self._optb('builder', 'enable_themida')
|
|
437
|
+
|
|
438
|
+
@property
|
|
439
|
+
def enable_jit(self):
|
|
440
|
+
return self._optb('builder', 'enable_jit')
|
|
441
|
+
|
|
442
|
+
@property
|
|
443
|
+
def enable_bcc(self):
|
|
444
|
+
return self._optb('builder', 'enable_bcc')
|
|
445
|
+
|
|
446
|
+
@property
|
|
447
|
+
def enable_rft(self):
|
|
448
|
+
return self._optb('builder', 'enable_rft')
|
|
449
|
+
|
|
450
|
+
@property
|
|
451
|
+
def assert_call(self):
|
|
452
|
+
return self._optb('builder', 'assert_call')
|
|
453
|
+
|
|
454
|
+
@property
|
|
455
|
+
def assert_import(self):
|
|
456
|
+
return self._optb('builder', 'assert_import')
|
|
457
|
+
|
|
458
|
+
@property
|
|
459
|
+
def mix_coname(self):
|
|
460
|
+
return self._optb('builder', 'mix_coname')
|
|
461
|
+
|
|
462
|
+
@property
|
|
463
|
+
def mix_localnames(self):
|
|
464
|
+
return self._optb('builder', 'mix_localnames')
|
|
465
|
+
|
|
466
|
+
@property
|
|
467
|
+
def mix_argnames(self):
|
|
468
|
+
return self._optb('builder', 'mix_argnames')
|
|
469
|
+
|
|
470
|
+
@property
|
|
471
|
+
def mix_str(self):
|
|
472
|
+
return self._optb('builder', 'mix_str')
|
|
473
|
+
|
|
474
|
+
@property
|
|
475
|
+
def obf_module(self):
|
|
476
|
+
return self._opti('builder', 'obf_module')
|
|
477
|
+
|
|
478
|
+
@property
|
|
479
|
+
def obf_code(self):
|
|
480
|
+
return self._opti('builder', 'obf_code')
|
|
481
|
+
|
|
482
|
+
@property
|
|
483
|
+
def wrap_mode(self):
|
|
484
|
+
return self._optb('builder', 'wrap_mode')
|
|
485
|
+
|
|
486
|
+
@property
|
|
487
|
+
def restrict_module(self):
|
|
488
|
+
return self._opti('builder', 'restrict_module')
|
|
489
|
+
|
|
490
|
+
@property
|
|
491
|
+
def import_check_license(self):
|
|
492
|
+
return self._optb('builder', 'import_check_license')
|
|
493
|
+
|
|
494
|
+
@property
|
|
495
|
+
def clear_module_co(self):
|
|
496
|
+
return self._optb('builder', 'clear_module_co')
|
|
497
|
+
|
|
498
|
+
@property
|
|
499
|
+
def clear_frame_locals(self):
|
|
500
|
+
return self._optb('builder', 'clear_frame_locals')
|
|
501
|
+
|
|
502
|
+
@property
|
|
503
|
+
def import_prefix(self):
|
|
504
|
+
v = self._opts('builder', 'import_prefix')
|
|
505
|
+
return int(v) if v.isdecimal() else v
|
|
506
|
+
|
|
507
|
+
@property
|
|
508
|
+
def exclude_restrict_modules(self):
|
|
509
|
+
return self._opts('builder', 'exclude_restrict_modules').split()
|
|
510
|
+
|
|
511
|
+
@property
|
|
512
|
+
def co_threshold(self):
|
|
513
|
+
return self._opti('builder', 'co_threshold')
|
|
514
|
+
|
|
515
|
+
@property
|
|
516
|
+
def jit_iv_threshold(self):
|
|
517
|
+
return self._opti('builder', 'jit_iv_threshold')
|
|
518
|
+
|
|
519
|
+
@property
|
|
520
|
+
def exclude_co_names(self):
|
|
521
|
+
return self.cfg['builder'].get('exclude_co_names', '').split()
|
|
522
|
+
|
|
523
|
+
@property
|
|
524
|
+
def outer_keyname(self):
|
|
525
|
+
return self.cfg['builder'].get('outer_keyname', 'pyarmor.rkey')
|
|
526
|
+
|
|
527
|
+
@property
|
|
528
|
+
def use_runtime(self):
|
|
529
|
+
return self.cmd_options.get('use_runtime',
|
|
530
|
+
self.cfg['builder'].get('use_runtime'))
|
|
531
|
+
|
|
532
|
+
@property
|
|
533
|
+
def inline_plugin_marker(self):
|
|
534
|
+
marker = self.cfg['builder'].get('inline_plugin_marker', 'false')
|
|
535
|
+
if marker.lower() not in ('', 'false', '0'):
|
|
536
|
+
return '# %s: ' % marker
|
|
537
|
+
|
|
538
|
+
#
|
|
539
|
+
# runtime configuration
|
|
540
|
+
#
|
|
541
|
+
def _rt_opt(self, opt):
|
|
542
|
+
return self.cmd_options.get(opt, self.cfg['runtime'].get(opt))
|
|
543
|
+
|
|
544
|
+
@property
|
|
545
|
+
def runtime_suffix(self):
|
|
546
|
+
return self.license_info['licno'][-6:]
|
|
547
|
+
|
|
548
|
+
@property
|
|
549
|
+
def runtime_package_name(self):
|
|
550
|
+
fmt = self.cfg.get('runtime', 'package_name_format')
|
|
551
|
+
return fmt.format(suffix=self.runtime_suffix)
|
|
552
|
+
|
|
553
|
+
@property
|
|
554
|
+
def runtime_platforms(self):
|
|
555
|
+
return self._rt_opt('platforms')
|
|
556
|
+
|
|
557
|
+
@property
|
|
558
|
+
def runtime_on_error(self):
|
|
559
|
+
return self._opti('runtime', 'on_error')
|
|
560
|
+
|
|
561
|
+
@property
|
|
562
|
+
def runtime_outer(self):
|
|
563
|
+
return self._optb('runtime', 'outer')
|
|
564
|
+
|
|
565
|
+
@property
|
|
566
|
+
def runtime_period(self):
|
|
567
|
+
period = self._rt_opt('period')
|
|
568
|
+
if period:
|
|
569
|
+
c = period[-1].lower()
|
|
570
|
+
if c.isdecimal():
|
|
571
|
+
return int(period) * 3600
|
|
572
|
+
|
|
573
|
+
if c in ('m', 'h', 's'):
|
|
574
|
+
unit = {
|
|
575
|
+
's': 1,
|
|
576
|
+
'm': 60,
|
|
577
|
+
'h': 3600,
|
|
578
|
+
}
|
|
579
|
+
return int(period[:-1]) * unit[c]
|
|
580
|
+
|
|
581
|
+
return -1
|
|
582
|
+
|
|
583
|
+
@property
|
|
584
|
+
def runtime_expired(self):
|
|
585
|
+
return self._rt_opt('expired')
|
|
586
|
+
|
|
587
|
+
@property
|
|
588
|
+
def runtime_nts(self):
|
|
589
|
+
return self._opts('runtime', 'nts')
|
|
590
|
+
|
|
591
|
+
@property
|
|
592
|
+
def runtime_nts_timeout(self):
|
|
593
|
+
return self._opti('runtime', 'nts_timeout')
|
|
594
|
+
|
|
595
|
+
@property
|
|
596
|
+
def runtime_devices(self):
|
|
597
|
+
value = self._rt_opt('devices')
|
|
598
|
+
return value.splitlines() if isinstance(value, str) else value
|
|
599
|
+
|
|
600
|
+
@property
|
|
601
|
+
def runtime_interps(self):
|
|
602
|
+
interps = self._rt_opt('interps')
|
|
603
|
+
rules = interps.splitlines() if interps else []
|
|
604
|
+
cfg = self.cfg['builder']
|
|
605
|
+
if cfg.getboolean('check_debugger', False):
|
|
606
|
+
rules.append('check-debugger')
|
|
607
|
+
if cfg.getboolean('check_interp', False):
|
|
608
|
+
rules.append('check-interp')
|
|
609
|
+
if self.runtime_hook('pyarmor_runtime'):
|
|
610
|
+
rules.append('py:bootstrap')
|
|
611
|
+
return '\n'.join(rules)
|
|
612
|
+
|
|
613
|
+
@property
|
|
614
|
+
def runtime_timer(self):
|
|
615
|
+
return self._opti('runtime', 'timer')
|
|
616
|
+
|
|
617
|
+
@property
|
|
618
|
+
def runtime_simple_extension_name(self):
|
|
619
|
+
return self._optb('runtime', 'simple_extension_name')
|
|
620
|
+
|
|
621
|
+
@property
|
|
622
|
+
def runtime_user_data(self):
|
|
623
|
+
data = b''
|
|
624
|
+
filename = self.cmd_options.get('user_data')
|
|
625
|
+
if filename:
|
|
626
|
+
if filename[0] == '@':
|
|
627
|
+
with open(filename[1:], 'rb') as f:
|
|
628
|
+
data = f.read()
|
|
629
|
+
else:
|
|
630
|
+
data = filename.encode()
|
|
631
|
+
|
|
632
|
+
return data
|
|
633
|
+
|
|
634
|
+
@property
|
|
635
|
+
def runtime_messages(self):
|
|
636
|
+
value = self.cfg['runtime'].get('messages', '')
|
|
637
|
+
if value:
|
|
638
|
+
name, encoding = (value + ':utf-8').split(':')[:2]
|
|
639
|
+
cfg = self._named_config(name, encoding=encoding)
|
|
640
|
+
if cfg.has_section('runtime.message'):
|
|
641
|
+
return cfg
|
|
642
|
+
|
|
643
|
+
def runtime_package_template(self, platforms):
|
|
644
|
+
return runtime_package_template if len(platforms) < 2 else \
|
|
645
|
+
multi_runtime_package_template
|
|
646
|
+
|
|
647
|
+
@property
|
|
648
|
+
def runtime_obf_key_mode(self):
|
|
649
|
+
return self._opti('runtime', 'obf_key_mode')
|
|
650
|
+
|
|
651
|
+
@property
|
|
652
|
+
def runtime_patch_extension(self):
|
|
653
|
+
return self._opti('runtime', 'patch_extension')
|
|
654
|
+
|
|
655
|
+
#
|
|
656
|
+
# RFT settings
|
|
657
|
+
#
|
|
658
|
+
|
|
659
|
+
def rft_output_script(self, name):
|
|
660
|
+
return self._check_logpath(os.path.join(self.local_path, 'rft', name))
|
|
661
|
+
|
|
662
|
+
def rft_set_exclude_table(self, encoding=None):
|
|
663
|
+
filename = os.path.join(self.local_path, 'rft_exclude_table')
|
|
664
|
+
os.makedirs(os.path.dirname(filename), exist_ok=True)
|
|
665
|
+
with open(filename, 'w', encoding=encoding) as f:
|
|
666
|
+
f.write(' '.join(self.rft_auto_excludes))
|
|
667
|
+
|
|
668
|
+
def rft_get_exclude_table(self, encoding=None):
|
|
669
|
+
filename = os.path.join(self.local_path, 'rft_exclude_table')
|
|
670
|
+
if os.path.exists(filename):
|
|
671
|
+
with open(filename, encoding=encoding) as f:
|
|
672
|
+
return f.read().split()
|
|
673
|
+
return []
|
|
674
|
+
|
|
675
|
+
#
|
|
676
|
+
# BCC settings
|
|
677
|
+
#
|
|
678
|
+
|
|
679
|
+
@property
|
|
680
|
+
def bcc_build_path(self):
|
|
681
|
+
path = os.path.join(self.local_path, 'bcc')
|
|
682
|
+
os.makedirs(path, exist_ok=True)
|
|
683
|
+
return path
|
|
684
|
+
|
|
685
|
+
@property
|
|
686
|
+
def bcc_encoding(self):
|
|
687
|
+
return self.cfg['builder'].get('encoding', 'utf-8')
|
|
688
|
+
|
|
689
|
+
#
|
|
690
|
+
# Plugin and hook
|
|
691
|
+
#
|
|
692
|
+
def runtime_hook(self, modname):
|
|
693
|
+
for path in self.local_path, self.global_path:
|
|
694
|
+
filename = os.path.join(path, 'hooks', modname + '.py')
|
|
695
|
+
if os.path.exists(filename):
|
|
696
|
+
encoding = self.cfg['builder'].get('encoding', 'utf-8')
|
|
697
|
+
with open(filename, encoding=encoding) as f:
|
|
698
|
+
return f.read()
|
|
699
|
+
|
|
700
|
+
def runtime_plugin(self, source, target, platforms):
|
|
701
|
+
from .plugin import Plugin
|
|
702
|
+
Plugin.post_runtime(self, source, target, platforms)
|
|
703
|
+
|
|
704
|
+
#
|
|
705
|
+
# Core data, new in 8.3
|
|
706
|
+
#
|
|
707
|
+
def _core_data(self, name):
|
|
708
|
+
n = __file__.find('context.py')
|
|
709
|
+
with open(__file__[:n] + name, 'rb') as f:
|
|
710
|
+
return f.read()
|
|
711
|
+
|
|
712
|
+
@property
|
|
713
|
+
def core_data_1(self):
|
|
714
|
+
return self._core_data('core.data.1')
|
|
715
|
+
|
|
716
|
+
@property
|
|
717
|
+
def core_data_2(self):
|
|
718
|
+
return self._core_data('core.data.2')
|
|
719
|
+
|
|
720
|
+
@property
|
|
721
|
+
def core_data_3(self):
|
|
722
|
+
return self._core_data('core.data.3')
|
|
723
|
+
|
|
724
|
+
#
|
|
725
|
+
# Get http proxy of token server
|
|
726
|
+
#
|
|
727
|
+
@property
|
|
728
|
+
def token_http_proxy(self):
|
|
729
|
+
http_proxy = os.environb.get(b'http_proxy', b'')
|
|
730
|
+
if not http_proxy:
|
|
731
|
+
return b''
|
|
732
|
+
i = http_proxy.find(b'@')
|
|
733
|
+
if i > 0:
|
|
734
|
+
from base64 import b64encode
|
|
735
|
+
header = b'Authorization: Basic %s\r\n' % b64encode(http_proxy[:i])
|
|
736
|
+
else:
|
|
737
|
+
header = b''
|
|
738
|
+
i += 1
|
|
739
|
+
j = http_proxy.find(b':', i)
|
|
740
|
+
if j == -1:
|
|
741
|
+
host = http_proxy[i:]
|
|
742
|
+
port = b'80'
|
|
743
|
+
else:
|
|
744
|
+
host = http_proxy[i:j]
|
|
745
|
+
port = http_proxy[j+1:]
|
|
746
|
+
url = b'http://pyarmor.dashingsoft.com'
|
|
747
|
+
return b'\x00'.join([host, port, url, header, b'\x00'])
|
|
748
|
+
|
|
749
|
+
def request_token(self, url, timeout=6.0):
|
|
750
|
+
from urllib.request import urlopen
|
|
751
|
+
|
|
752
|
+
def get_response(host):
|
|
753
|
+
try:
|
|
754
|
+
from ssl import _create_unverified_context
|
|
755
|
+
context = _create_unverified_context()
|
|
756
|
+
req = 'https://%s%s' % (host, url)
|
|
757
|
+
except Exception:
|
|
758
|
+
context = None
|
|
759
|
+
req = 'http://%s%s' % (host, url)
|
|
760
|
+
return urlopen(req, None, timeout, context=context)
|
|
761
|
+
|
|
762
|
+
with get_response('pyarmor.dashingsoft.com') as res:
|
|
763
|
+
return res.read()
|
|
764
|
+
|
|
765
|
+
#
|
|
766
|
+
# Pack options for auto/onefile/onefolder mode
|
|
767
|
+
#
|
|
768
|
+
@property
|
|
769
|
+
def pyi_options(self):
|
|
770
|
+
from json import loads as json_loads
|
|
771
|
+
from shlex import split as split_opt
|
|
772
|
+
pyi_opts = []
|
|
773
|
+
jsmarker = 'json::'
|
|
774
|
+
for line in self.cfg['pack'].get('pyi_options', '').splitlines():
|
|
775
|
+
line = line.strip()
|
|
776
|
+
if line.startswith(jsmarker):
|
|
777
|
+
pyi_opts.extend(json_loads(line[len(jsmarker):]))
|
|
778
|
+
elif line.startswith('-'):
|
|
779
|
+
pyi_opts.extend(split_opt(line))
|
|
780
|
+
elif line:
|
|
781
|
+
pyi_opts.append(line)
|
|
782
|
+
return pyi_opts
|
|
783
|
+
|
|
784
|
+
@property
|
|
785
|
+
def pack_basepath(self):
|
|
786
|
+
return os.path.join(self.local_path, 'pack')
|
|
787
|
+
|
|
788
|
+
@property
|
|
789
|
+
def pack_obfpath(self):
|
|
790
|
+
return os.path.join(self.pack_basepath, 'dist')
|