1
|
|
|
#!/usr/bin/env python3 |
2
|
5 |
|
"""This module is used for creation of autoloaders.""" |
3
|
|
|
|
4
|
5 |
|
import glob # filename matching |
5
|
5 |
|
import os # path work |
6
|
5 |
|
import shutil # file copying |
7
|
|
|
|
8
|
5 |
|
from bbarchivist import bbconstants # versions/constants |
9
|
5 |
|
from bbarchivist import exceptions # exception handling |
10
|
5 |
|
from bbarchivist import jsonutils # json |
11
|
5 |
|
from bbarchivist import pseudocap # implement cap |
12
|
5 |
|
from bbarchivist import utilities # directory handler |
13
|
|
|
|
14
|
5 |
|
__author__ = "Thurask" |
15
|
5 |
|
__license__ = "WTFPL v2" |
16
|
5 |
|
__copyright__ = "2015-2018 Thurask" |
17
|
|
|
|
18
|
|
|
|
19
|
5 |
|
def read_files(localdir, core=False): |
20
|
|
|
""" |
21
|
|
|
Read list of signed files, return name assignments. |
22
|
|
|
|
23
|
|
|
:param localdir: Directory to use. |
24
|
|
|
:type localdir: str |
25
|
|
|
|
26
|
|
|
:param core: If we're using a core OS image. Default is false. |
27
|
|
|
:type core: bool |
28
|
|
|
""" |
29
|
5 |
|
oslist = read_os_files(localdir, core) |
30
|
|
|
# [8960, 8x30, 8974, ti] |
31
|
5 |
|
radlist = read_radio_files(localdir) |
32
|
|
|
# [ti, z10, z10_vzw, q10, z30, z3, 8974] |
33
|
5 |
|
pairdict = {} |
34
|
5 |
|
mapping = {0:3, 1:0, 2:0, 3:0, 4:0, 5:1, 6:2} |
35
|
5 |
|
for idx, rad in enumerate(radlist): |
36
|
5 |
|
pairdict[rad] = oslist[mapping[idx]] |
37
|
5 |
|
filtdict = {k: v for k, v in pairdict.items() if k} # pop None |
38
|
5 |
|
return filtdict |
39
|
|
|
|
40
|
|
|
|
41
|
5 |
|
def find_signed_file(match, localdir, title, silent=False): |
42
|
|
|
""" |
43
|
|
|
Use pattern matching to find a signed file in a directory. |
44
|
|
|
|
45
|
|
|
:param match: Match pattern to use. |
46
|
|
|
:type match: str |
47
|
|
|
|
48
|
|
|
:param localdir: Directory to use. |
49
|
|
|
:type localdir: str |
50
|
|
|
|
51
|
|
|
:param title: File type, in case it isn't found. |
52
|
|
|
:type title: str |
53
|
|
|
|
54
|
|
|
:param silent: Don't print that a file wasn't found. Default is False. |
55
|
|
|
:type silent: bool |
56
|
|
|
""" |
57
|
5 |
|
try: |
58
|
5 |
|
signedfile = glob.glob(os.path.join(localdir, match))[0] |
59
|
5 |
|
except IndexError: |
60
|
5 |
|
signedfile = None |
61
|
5 |
|
if not silent: |
62
|
5 |
|
print("No {0} found".format(title)) |
63
|
5 |
|
return signedfile |
64
|
|
|
|
65
|
|
|
|
66
|
5 |
|
def generate_os_fixes(core=False): |
67
|
|
|
""" |
68
|
|
|
Generate name regexes for OS signed files. |
69
|
|
|
|
70
|
|
|
:param core: If we're using a core OS image. Default is false. |
71
|
|
|
:type core: bool |
72
|
|
|
""" |
73
|
5 |
|
if core: |
74
|
5 |
|
fix8960 = "*qc8960.*_sfi.BB*.signed" |
75
|
5 |
|
fixomap_new = "*winchester.*_sfi.BB*.signed" |
76
|
5 |
|
fixomap_old = "*os.factory_sfi.BB*.signed" |
77
|
5 |
|
fix8930 = "*qc8x30.BB*.signed" |
78
|
5 |
|
fix8974_new = "*qc8974.BB*.signed" |
79
|
5 |
|
fix8974_old = "*qc8974.*_sfi.BB*.signed" |
80
|
|
|
else: |
81
|
5 |
|
fix8960 = "*qc8960.*_sfi.desktop.BB*.signed" |
82
|
5 |
|
fixomap_new = "*winchester.*_sfi.desktop.BB*.signed" |
83
|
5 |
|
fixomap_old = "*os.factory_sfi.desktop.BB*.signed" |
84
|
5 |
|
fix8930 = "*qc8x30.desktop.BB*.signed" |
85
|
5 |
|
fix8974_new = "*qc8974.desktop.BB*.signed" |
86
|
5 |
|
fix8974_old = "*qc8974.*_sfi.desktop.BB*.signed" |
87
|
5 |
|
return fix8960, fixomap_new, fixomap_old, fix8930, fix8974_new, fix8974_old |
88
|
|
|
|
89
|
|
|
|
90
|
5 |
|
def read_os_files(localdir, core=False): |
91
|
|
|
""" |
92
|
|
|
Read list of OS signed files, return name assignments. |
93
|
|
|
|
94
|
|
|
:param localdir: Directory to use. |
95
|
|
|
:type localdir: str |
96
|
|
|
|
97
|
|
|
:param core: If we're using a core OS image. Default is false. |
98
|
|
|
:type core: bool |
99
|
|
|
""" |
100
|
5 |
|
fix8960, fixomap_new, fixomap_old, fix8930, fix8974_new, fix8974_old = generate_os_fixes(core) |
101
|
|
|
# 8960 |
102
|
5 |
|
os_8960 = find_signed_file(fix8960, localdir, "8960 OS") |
103
|
|
|
# 8x30 (10.3.1 MR+) |
104
|
5 |
|
os_8x30 = find_signed_file(fix8930, localdir, "8x30 OS", True) |
105
|
5 |
|
if os_8x30 is None: |
106
|
5 |
|
os_8x30 = find_signed_file(fix8960, localdir, "8x30 OS") |
107
|
|
|
# 8974 |
108
|
5 |
|
os_8974 = find_signed_file(fix8974_new, localdir, "8974 OS", True) |
109
|
5 |
|
if os_8974 is None: |
110
|
5 |
|
os_8974 = find_signed_file(fix8974_old, localdir, "8974 OS") |
111
|
|
|
# OMAP |
112
|
5 |
|
os_ti = find_signed_file(fixomap_new, localdir, "OMAP OS", True) |
113
|
5 |
|
if os_ti is None: |
114
|
5 |
|
os_ti = find_signed_file(fixomap_old, localdir, "OMAP OS") |
115
|
5 |
|
return [os_8960, os_8x30, os_8974, os_ti] |
116
|
|
|
|
117
|
|
|
|
118
|
5 |
|
def read_radio_files(localdir): |
119
|
|
|
""" |
120
|
|
|
Read list of radio signed files, return name assignments. |
121
|
|
|
|
122
|
|
|
:param localdir: Directory to use. |
123
|
|
|
:type localdir: str |
124
|
|
|
""" |
125
|
|
|
# STL100-1 |
126
|
5 |
|
radio_ti = find_signed_file("*radio.m5730*.signed", localdir, "OMAP radio") |
127
|
|
|
# STL100-X |
128
|
5 |
|
radio_z10 = find_signed_file("*radio.qc8960.BB*.signed", localdir, "8960 radio") |
129
|
|
|
# STL100-4 |
130
|
5 |
|
radio_z10_vzw = find_signed_file("*radio.qc8960*omadm*.signed", localdir, "VZW 8960 radio") |
131
|
|
|
# Q10/Q5 |
132
|
5 |
|
radio_q10 = find_signed_file("*radio.qc8960*wtr.*signed", localdir, "Q10/Q5 radio") |
133
|
|
|
# Z30/Classic |
134
|
5 |
|
radio_z30 = find_signed_file("*radio.qc8960*wtr5*.signed", localdir, "Z30/Classic radio") |
135
|
|
|
# Z3 |
136
|
5 |
|
radio_z3 = find_signed_file("*radio.qc8930*wtr5*.signed", localdir, "Z3 radio") |
137
|
|
|
# Passport |
138
|
5 |
|
radio_8974 = find_signed_file("*radio.qc8974*wtr2*.signed", localdir, "Passport radio") |
139
|
5 |
|
return [radio_ti, radio_z10, radio_z10_vzw, radio_q10, radio_z30, radio_z3, radio_8974] |
140
|
|
|
|
141
|
|
|
|
142
|
5 |
|
def zeropad(splitver, idx, padlen): |
143
|
|
|
""" |
144
|
|
|
Zero-pad an element of an OS/radio version to a certain length. |
145
|
|
|
|
146
|
|
|
:param splitver: OS/radio version, but split into quarters. |
147
|
|
|
:type splitver: list(str) |
148
|
|
|
|
149
|
|
|
:param idx: Index of splitver which must be checked. |
150
|
|
|
:type idx: int |
151
|
|
|
|
152
|
|
|
:param padlen: Length to pad to. |
153
|
|
|
:type padlen: int |
154
|
|
|
""" |
155
|
5 |
|
if len(splitver[idx]) < padlen: |
156
|
5 |
|
splitver[idx] = splitver[idx].rjust(padlen, "0") |
157
|
5 |
|
return splitver |
158
|
|
|
|
159
|
|
|
|
160
|
5 |
|
def versionpad(splitver): |
161
|
|
|
""" |
162
|
|
|
Properly pad an OS/radio version. |
163
|
|
|
|
164
|
|
|
:param splitver: OS/radio version, but split into quarters. |
165
|
|
|
:type splitver: list(str) |
166
|
|
|
""" |
167
|
5 |
|
splitver = zeropad(splitver, 2, 2) |
168
|
5 |
|
splitver = zeropad(splitver, 3, 4) |
169
|
5 |
|
return splitver |
170
|
|
|
|
171
|
|
|
|
172
|
5 |
|
def pretty_formatter(osversion, radioversion): |
173
|
|
|
""" |
174
|
|
|
Format OS/radio versions to cope with systems with poor sorting. |
175
|
|
|
|
176
|
|
|
:param osversion: OS version, 10.x.y.zzzz. |
177
|
|
|
:type osversion: str |
178
|
|
|
|
179
|
|
|
:param radioversion: Radio version, 10.x.y.zzzz. |
180
|
|
|
:type radioversion: str |
181
|
|
|
""" |
182
|
|
|
# 10.x.y.zzz becomes 10.x.0y.0zzz |
183
|
5 |
|
splitos = osversion.split(".") |
184
|
5 |
|
splitos = versionpad(splitos) |
185
|
5 |
|
the_os = ".".join(splitos) |
186
|
5 |
|
splitrad = radioversion.split(".") |
187
|
5 |
|
splitrad = versionpad(splitrad) |
188
|
5 |
|
the_radio = ".".join(splitrad) |
189
|
5 |
|
return the_os, the_radio |
190
|
|
|
|
191
|
|
|
|
192
|
5 |
|
def format_suffix(altradio=None, radioversion=None, core=False): |
193
|
|
|
""" |
194
|
|
|
Formulate suffix for hybrid autoloaders. |
195
|
|
|
|
196
|
|
|
:param altradio: If a hybrid autoloader is being made. |
197
|
|
|
:type altradio: bool |
198
|
|
|
|
199
|
|
|
:param radioversion: The hybrid radio version, if applicable. |
200
|
|
|
:type radioversion: str |
201
|
|
|
|
202
|
|
|
:param core: If we're using a core OS image. Default is false. |
203
|
|
|
:type core: bool |
204
|
|
|
""" |
205
|
5 |
|
suffix = "_R{0}".format(radioversion) if altradio and radioversion else "" |
206
|
5 |
|
if core: |
207
|
5 |
|
suffix += "_CORE" |
208
|
5 |
|
return suffix |
209
|
|
|
|
210
|
|
|
|
211
|
5 |
|
def generate_loaders(osversion, radioversion, radios=True, localdir=None, altradio=False, core=False): |
212
|
|
|
""" |
213
|
|
|
Create and label autoloaders for :mod:`bbarchivist.scripts.archivist`. |
214
|
|
|
|
215
|
|
|
:param osversion: OS version, 10.x.y.zzzz. |
216
|
|
|
:type osversion: str |
217
|
|
|
|
218
|
|
|
:param radioversion: Radio version, 10.x.y.zzzz. |
219
|
|
|
:type radioversion: str |
220
|
|
|
|
221
|
|
|
:param radios: Whether to make radios or not. True by default. |
222
|
|
|
:type radios: bool |
223
|
|
|
|
224
|
|
|
:param localdir: Working path. Default is local dir. |
225
|
|
|
:type localdir: str |
226
|
|
|
|
227
|
|
|
:param altradio: If we're using an alternate radio. Default is false. |
228
|
|
|
:type altradio: bool |
229
|
|
|
|
230
|
|
|
:param core: If we're using a core OS image. Default is false. |
231
|
|
|
:type core: bool |
232
|
|
|
""" |
233
|
|
|
# default parsing |
234
|
5 |
|
localdir = utilities.dirhandler(localdir, os.getcwd()) |
235
|
5 |
|
print("GETTING FILENAMES...") |
236
|
5 |
|
filedict = read_files(localdir, core) |
237
|
5 |
|
osversion, radioversion = pretty_formatter(osversion, radioversion) |
238
|
5 |
|
suffix = format_suffix(altradio, radioversion, core) |
239
|
|
|
# Generate loaders |
240
|
5 |
|
print("CREATING LOADERS...") |
241
|
5 |
|
filtrad = [rad for rad in filedict.keys() if rad] # pop None |
242
|
5 |
|
generate_individual_loaders(filtrad, osversion, radioversion, suffix, filedict, radios, localdir) |
243
|
|
|
|
244
|
|
|
|
245
|
5 |
|
def generate_individual_loaders(filtrad, osversion, radioversion, suffix, filedict, radios, localdir): |
246
|
|
|
""" |
247
|
|
|
Generate individual loaders when generating several at once. |
248
|
|
|
|
249
|
|
|
:param filtrad: List of radio files, if they exist. |
250
|
|
|
:type filtrad: list(str) |
251
|
|
|
|
252
|
|
|
:param osversion: OS version, 10.x.y.zzzz. |
253
|
|
|
:type osversion: str |
254
|
|
|
|
255
|
|
|
:param radioversion: Radio version, 10.x.y.zzzz. |
256
|
|
|
:type radioversion: str |
257
|
|
|
|
258
|
|
|
:param suffix: Alternate radio, or blank. |
259
|
|
|
:type suffix: str |
260
|
|
|
|
261
|
|
|
:param filedict: Dictionary of radio:OS pairs. |
262
|
|
|
:type filedict: dict(str: str) |
263
|
|
|
|
264
|
|
|
:param radios: Whether to make radios or not. True by default. |
265
|
|
|
:type radios: bool |
266
|
|
|
|
267
|
|
|
:param localdir: Working path. Default is local dir. |
268
|
|
|
:type localdir: str |
269
|
|
|
""" |
270
|
5 |
|
for radval in filtrad: |
271
|
5 |
|
device = generate_device(radval) |
272
|
5 |
|
osname = generate_filename(device, osversion, suffix) |
273
|
5 |
|
osfile = filedict[radval] |
274
|
5 |
|
if osfile is not None: |
275
|
5 |
|
wrap_pseudocap(osname, localdir, osfile, radval) |
276
|
5 |
|
if radios: |
277
|
5 |
|
radname = generate_filename(device, radioversion, "") |
278
|
5 |
|
wrap_pseudocap(radname, localdir, radval) |
279
|
|
|
|
280
|
|
|
|
281
|
|
|
|
282
|
5 |
|
def wrap_pseudocap(filename, folder, first, second=None): |
283
|
|
|
""" |
284
|
|
|
A filtered, excepting wrapper for pseudocap. |
285
|
|
|
|
286
|
|
|
:param filename: The title of the new loader. |
287
|
|
|
:type filename: str |
288
|
|
|
|
289
|
|
|
:param folder: The folder to create the loader in. |
290
|
|
|
:type folder: str |
291
|
|
|
|
292
|
|
|
:param first: The first signed file, required. |
293
|
|
|
:type first: str |
294
|
|
|
|
295
|
|
|
:param second: The second signed file, optional. |
296
|
|
|
:type second: str |
297
|
|
|
""" |
298
|
5 |
|
if first is None: |
299
|
5 |
|
print("No OS!") |
300
|
5 |
|
raise SystemError |
301
|
5 |
|
try: |
302
|
5 |
|
pseudocap.make_autoloader(filename, [first, second], folder=folder) |
303
|
5 |
|
except (OSError, IndexError, SystemError) as exc: |
304
|
5 |
|
msg = "Could not create {0}".format(filename) |
305
|
5 |
|
exceptions.handle_exception(exc, msg, None) |
306
|
|
|
|
307
|
|
|
|
308
|
5 |
|
def generate_skeletons(): |
309
|
|
|
""" |
310
|
|
|
Read JSON to get a dict of all filename components. |
311
|
|
|
""" |
312
|
5 |
|
namelist = {0: None, 1: None, 2: None, 3: None, 4: None, 5: None, 6: None} |
313
|
5 |
|
data = jsonutils.load_json('integermap') |
314
|
5 |
|
for key in data: |
315
|
5 |
|
if key['id'] in namelist: |
316
|
5 |
|
namelist[key['id']] = (key['parts']) |
317
|
5 |
|
namelist[key['id']].append(".exe") |
318
|
5 |
|
return namelist |
319
|
|
|
|
320
|
|
|
|
321
|
5 |
|
def generate_device(radio): |
322
|
|
|
""" |
323
|
|
|
Read JSON to get the device integer ID from device radio. |
324
|
|
|
|
325
|
|
|
:param radio: The radio filename to look up. |
326
|
|
|
:type radio: str |
327
|
|
|
""" |
328
|
5 |
|
data = jsonutils.load_json('integermap') |
329
|
5 |
|
for key in data: |
330
|
5 |
|
if key['radtype'] in radio: |
331
|
5 |
|
idx = int(key['id']) |
332
|
5 |
|
break |
333
|
5 |
|
return idx |
334
|
|
|
|
335
|
|
|
|
336
|
5 |
|
def generate_filename(device, version, suffix=None): |
337
|
|
|
""" |
338
|
|
|
Use skeleton dict to create loader filenames. |
339
|
|
|
|
340
|
|
|
:param device: Device to use. |
341
|
|
|
:type device: int |
342
|
|
|
|
343
|
|
|
:param version: OS or radio version. |
344
|
|
|
:type version: str |
345
|
|
|
|
346
|
|
|
:param suffix: Alternate radio, or blank. |
347
|
|
|
:type suffix: str |
348
|
|
|
""" |
349
|
5 |
|
thed = generate_skeletons() |
350
|
5 |
|
if device < 0: |
351
|
5 |
|
return None |
352
|
5 |
|
dev = thed[device] |
353
|
5 |
|
if suffix is None: |
354
|
5 |
|
suffix = "" |
355
|
5 |
|
return "{0}{1}{2}{3}{4}".format(dev[0], version, suffix, dev[1], dev[2]) |
356
|
|
|
|
357
|
|
|
|
358
|
5 |
|
def generate_lazy_loader( |
359
|
|
|
osversion, device, |
360
|
|
|
localdir=None, altradio=None, core=False): |
361
|
|
|
""" |
362
|
|
|
Create and label autoloaders for :mod:`bbarchivist.scripts.lazyloader`. |
363
|
|
|
:func:`generate_loaders`, but for making one OS/radio loader. |
364
|
|
|
|
365
|
|
|
:param osversion: OS version, 10.x.y.zzzz. |
366
|
|
|
:type osversion: str |
367
|
|
|
|
368
|
|
|
:param device: Selected device, from |
369
|
|
|
:type device: int |
370
|
|
|
|
371
|
|
|
:param localdir: Working path. Default is local dir. |
372
|
|
|
:type localdir: str |
373
|
|
|
|
374
|
|
|
:param altradio: The alternate radio in use, if there is one. |
375
|
|
|
:type altradio: str |
376
|
|
|
|
377
|
|
|
:param core: If we're using a core OS image. Default is false. |
378
|
|
|
:type core: bool |
379
|
|
|
""" |
380
|
|
|
# default parsing |
381
|
5 |
|
localdir = utilities.dirhandler(localdir, os.getcwd()) |
382
|
5 |
|
print("CREATING LOADER...") |
383
|
5 |
|
suffix = format_suffix(bool(altradio), altradio, core) |
384
|
5 |
|
osfile = None |
385
|
5 |
|
absoglob = "{0}{1}".format(localdir, os.sep) |
386
|
5 |
|
try: |
387
|
5 |
|
osfile = str(glob.glob("{0}*_sfi*.signed".format(absoglob))[0]) |
388
|
5 |
|
except IndexError: |
389
|
5 |
|
print("No OS found") |
390
|
|
|
else: |
391
|
5 |
|
generate_lazy_set(osversion, device, osfile, suffix, absoglob, localdir) |
392
|
|
|
|
393
|
|
|
|
394
|
5 |
|
def generate_lazy_set(osversion, device, osfile, suffix, absoglob, localdir=None): |
395
|
|
|
""" |
396
|
|
|
Get radio file and then generate autoloader. |
397
|
|
|
|
398
|
|
|
:param osversion: OS version, 10.x.y.zzzz. |
399
|
|
|
:type osversion: str |
400
|
|
|
|
401
|
|
|
:param device: Selected device, from |
402
|
|
|
:type device: int |
403
|
|
|
|
404
|
|
|
:param osfile: OS signed filename. |
405
|
|
|
:type osfile: str |
406
|
|
|
|
407
|
|
|
:param suffix: Loader name suffix. |
408
|
|
|
:type suffix: str |
409
|
|
|
|
410
|
|
|
:param absoglob: Local path + path separator. |
411
|
|
|
:type absoglob: str |
412
|
|
|
|
413
|
|
|
:param localdir: Working path. Default is local dir. |
414
|
|
|
:type localdir: str |
415
|
|
|
""" |
416
|
5 |
|
radiofile = None |
417
|
5 |
|
try: |
418
|
5 |
|
sset = set(glob.glob("{0}*.signed".format(absoglob))) |
419
|
5 |
|
rset = sset - set(glob.glob("{0}*_sfi*.signed".format(absoglob))) |
420
|
5 |
|
radiofile = str(list(rset)[0]) |
421
|
5 |
|
except IndexError: |
422
|
5 |
|
print("No radio found") |
423
|
|
|
else: |
424
|
5 |
|
loadername = generate_lazy_filename(osversion, suffix, device) |
425
|
5 |
|
wrap_pseudocap(loadername, localdir, osfile, radiofile) |
426
|
|
|
|
427
|
|
|
|
428
|
5 |
|
def generate_lazy_filename(osversion, suffix, device): |
429
|
|
|
""" |
430
|
|
|
Read JSON to formulate a single filename. |
431
|
|
|
|
432
|
|
|
:param osversion: OS version. |
433
|
|
|
:type osversion: str |
434
|
|
|
|
435
|
|
|
:param suffix: Alternate radio, or just blank. |
436
|
|
|
:type suffix: str |
437
|
|
|
|
438
|
|
|
:param device: Device to use. |
439
|
|
|
:type device: int |
440
|
|
|
""" |
441
|
5 |
|
data = jsonutils.load_json('integermap') |
442
|
5 |
|
for key in data: |
443
|
5 |
|
if key['id'] == device: |
444
|
5 |
|
fname = key['parts'] |
445
|
5 |
|
break |
446
|
5 |
|
return "{0}{1}{2}{3}.exe".format(fname[0], osversion, suffix, fname[1]) |
447
|
|
|
|
448
|
|
|
|
449
|
5 |
|
def point_point_copy(inpath, outpath, filename): |
450
|
|
|
""" |
451
|
|
|
Copy a file from one absolute path to another. |
452
|
|
|
|
453
|
|
|
:param inpath: Input path. |
454
|
|
|
:type inpath: str |
455
|
|
|
|
456
|
|
|
:param outpath: Output path. |
457
|
|
|
:type outpath: str |
458
|
|
|
|
459
|
|
|
:param filename: Filename. |
460
|
|
|
:type filename: str |
461
|
|
|
""" |
462
|
5 |
|
shutil.copy(os.path.join(inpath, filename), os.path.join(outpath, filename)) |
463
|
|
|
|
464
|
|
|
|
465
|
5 |
|
def point_point_bulk(inpath, outpath, files): |
466
|
|
|
""" |
467
|
|
|
Copy a list of files from one absolute path to another. |
468
|
|
|
|
469
|
|
|
:param inpath: Input path. |
470
|
|
|
:type inpath: str |
471
|
|
|
|
472
|
|
|
:param outpath: Output path. |
473
|
|
|
:type outpath: str |
474
|
|
|
|
475
|
|
|
:param files: List of filenames. |
476
|
|
|
:type files: list(str) |
477
|
|
|
""" |
478
|
5 |
|
for file in files: |
479
|
5 |
|
point_point_copy(inpath, outpath, file) |
480
|
|
|
|
481
|
|
|
|
482
|
5 |
|
def generate_tclloader_script(dirname, batchfile, shfile, wipe=True): |
483
|
|
|
""" |
484
|
|
|
Copy script files from site-packages to loader directory. |
485
|
|
|
|
486
|
|
|
:param dirname: Name for final directory and loader. |
487
|
|
|
:type dirname: str |
488
|
|
|
|
489
|
|
|
:param batchfile: Path to flashall.bat. |
490
|
|
|
:type batchfile: str |
491
|
|
|
|
492
|
|
|
:param shfile: Path to flashall.sh. |
493
|
|
|
:type shfile: str |
494
|
|
|
|
495
|
|
|
:param wipe: If the final loader wipes userdata. Default is True. |
496
|
|
|
:type wipe: bool |
497
|
|
|
""" |
498
|
5 |
|
shutil.copy(batchfile, os.path.join(dirname, "flashall.bat")) |
499
|
5 |
|
shutil.copy(shfile, os.path.join(dirname, "flashall.sh")) |
500
|
5 |
|
if not wipe: |
501
|
5 |
|
tclloader_nowipe(os.path.join(dirname, "flashall.bat")) |
502
|
5 |
|
tclloader_nowipe(os.path.join(dirname, "flashall.sh")) |
503
|
|
|
|
504
|
|
|
|
505
|
5 |
|
def tclloader_nowipe(infile): |
506
|
|
|
""" |
507
|
|
|
Modify a script file to strike references to wiping the phone. |
508
|
|
|
|
509
|
|
|
:param infile: Path to script file to modify. |
510
|
|
|
:type infile: str |
511
|
|
|
""" |
512
|
5 |
|
filterout = ("oem securewipe", "flash userdata") |
513
|
5 |
|
with open(infile, "r+", newline="") as afile: |
514
|
5 |
|
content = afile.read() |
515
|
5 |
|
afile.seek(0) |
516
|
5 |
|
for line in content.split("\n"): |
517
|
5 |
|
if not any(part in line for part in filterout): |
518
|
5 |
|
afile.write(line + "\n") |
519
|
5 |
|
afile.truncate() |
520
|
|
|
|
521
|
|
|
|
522
|
5 |
|
def generate_google_host(hostin, hostout): |
523
|
|
|
""" |
524
|
|
|
Generate host directory from Google platform tools, i.e. fastboot. |
525
|
|
|
|
526
|
|
|
:param hostin: Directory containing files to copy. |
527
|
|
|
:type hostin: str |
528
|
|
|
|
529
|
|
|
:param hostout: Directory that files are to be copied to. |
530
|
|
|
:type hostout: str |
531
|
|
|
""" |
532
|
5 |
|
platforms = ["linux", "windows", "darwin"] |
533
|
5 |
|
inouts = {os.path.join(hostin, plat, "platform-tools"): os.path.join(hostout, "{0}-x86".format(plat), "bin") for plat in platforms} |
534
|
5 |
|
for infile, outfile in inouts.items(): |
535
|
5 |
|
shutil.copytree(infile, outfile) |
536
|
|
|
|
537
|
|
|
|
538
|
5 |
|
def generate_tclloader_host(hostin, hostout): |
539
|
|
|
""" |
540
|
|
|
Generate host directory from autoloader template, i.e. fastboot. |
541
|
|
|
|
542
|
|
|
:param hostin: Directory containing files to copy. |
543
|
|
|
:type hostin: str |
544
|
|
|
|
545
|
|
|
:param hostout: Directory that files are to be copied to. |
546
|
|
|
:type hostout: str |
547
|
|
|
""" |
548
|
5 |
|
os.makedirs(os.path.join(hostout, "darwin-x86", "bin")) |
549
|
5 |
|
os.makedirs(os.path.join(hostout, "linux-x86", "bin")) |
550
|
5 |
|
os.makedirs(os.path.join(hostout, "windows-x86", "bin")) |
551
|
5 |
|
macfile = os.path.join("darwin-x86", "bin", "fastboot") |
552
|
5 |
|
linfile = os.path.join("linux-x86", "bin", "fastboot") |
553
|
5 |
|
winx = ["AdbWinApi.dll", "AdbWinUsbApi.dll", "fastboot.exe"] |
554
|
5 |
|
winfiles = [os.path.join("windows-x86", "bin", x) for x in winx] |
555
|
5 |
|
winfiles.extend([linfile, macfile]) |
556
|
5 |
|
point_point_bulk(hostin, hostout, winfiles) |
557
|
|
|
|
558
|
|
|
|
559
|
5 |
|
def generate_tclloader_sig(sigin, sigout): |
560
|
|
|
""" |
561
|
|
|
Generate common signature files. |
562
|
|
|
|
563
|
|
|
:param sigin: Directory containing files to copy. |
564
|
|
|
:type sigin: str |
565
|
|
|
|
566
|
|
|
:param sigout: Directory that files are to be copied to. |
567
|
|
|
:type sigout: str |
568
|
|
|
""" |
569
|
5 |
|
for entry in ["boot", "recovery"]: |
570
|
5 |
|
shutil.copy(os.path.join(sigin, "{0}.img.production.sig".format(entry)), os.path.join(sigout, "{0}.img.sig".format(entry))) |
571
|
|
|
|
572
|
|
|
|
573
|
5 |
|
def generate_tclloader_csig(sigin, sigout, carrier): |
574
|
|
|
""" |
575
|
|
|
Generate carrier variant signature files. |
576
|
|
|
|
577
|
|
|
:param sigin: Directory containing files to copy. |
578
|
|
|
:type sigin: str |
579
|
|
|
|
580
|
|
|
:param sigout: Directory that files are to be copied to. |
581
|
|
|
:type sigout: str |
582
|
|
|
|
583
|
|
|
:param carrier: Carrier to check: att, sprint, china, vzw |
584
|
|
|
:type carrier: str |
585
|
|
|
""" |
586
|
5 |
|
for entry in ["boot", "recovery"]: |
587
|
5 |
|
shutil.copy(os.path.join(sigin, "{1}.img.production-{0}.sig".format(carrier, entry)), os.path.join(sigout, "{1}.img{0}.sig".format(carrier, entry))) |
588
|
|
|
|
589
|
|
|
|
590
|
5 |
|
def generate_tclloader_carriers(sigin, sigout): |
591
|
|
|
""" |
592
|
|
|
Collect carrier variant signature files. |
593
|
|
|
|
594
|
|
|
:param sigin: Directory containing files to copy. |
595
|
|
|
:type sigin: str |
596
|
|
|
|
597
|
|
|
:param sigout: Directory that files are to be copied to. |
598
|
|
|
:type sigout: str |
599
|
|
|
""" |
600
|
5 |
|
prods = set(x.split("-")[-1].split(".")[0] for x in os.listdir(sigin) if "production-" in x) - {"boot", "recovery"} |
601
|
5 |
|
if prods: |
602
|
5 |
|
generate_tclloader_carriter(sigin, sigout, prods) |
603
|
|
|
|
604
|
|
|
|
605
|
5 |
|
def generate_tclloader_carriter(sigin, sigout, prods): |
606
|
|
|
""" |
607
|
|
|
Iterate carrier variant signature files. |
608
|
|
|
|
609
|
|
|
:param sigin: Directory containing files to copy. |
610
|
|
|
:type sigin: str |
611
|
|
|
|
612
|
|
|
:param sigout: Directory that files are to be copied to. |
613
|
|
|
:type sigout: str |
614
|
|
|
|
615
|
|
|
:param prods: Set of carriers. |
616
|
|
|
:type prods: set(str) |
617
|
|
|
""" |
618
|
5 |
|
for carr in prods: |
619
|
5 |
|
generate_tclloader_csig(sigin, sigout, carr) |
620
|
|
|
|
621
|
|
|
|
622
|
5 |
|
def generate_tclloader_mbn(mdnin, mdnout): |
623
|
|
|
""" |
624
|
|
|
Generate mbn files. |
625
|
|
|
|
626
|
|
|
:param mdnin: Directory containing files to copy. |
627
|
|
|
:type mdnin: str |
628
|
|
|
|
629
|
|
|
:param mdnout: Directory that files are to be copied to. |
630
|
|
|
:type mdnout: str |
631
|
|
|
""" |
632
|
5 |
|
files = ["devcfg.mbn", "devcfg_cn.mbn", "rpm.mbn", "tz.mbn"] |
633
|
5 |
|
point_point_bulk(mdnin, mdnout, files) |
634
|
|
|
|
635
|
|
|
|
636
|
5 |
|
def generate_tclloader_omniset(omnin, omnilist, prefix, suffix, filt): |
637
|
|
|
""" |
638
|
|
|
Generic function to generate sets. |
639
|
|
|
|
640
|
|
|
:param omnin: Directory containing files to copy. |
641
|
|
|
:type omnin: str |
642
|
|
|
|
643
|
|
|
:param omnilist: List of variants. |
644
|
|
|
:type omnilist: list(str) |
645
|
|
|
|
646
|
|
|
:param prefix: Prefix, before items in list. |
647
|
|
|
:type prefix: str |
648
|
|
|
|
649
|
|
|
:param suffix: Suffix, after items in list. |
650
|
|
|
:type suffix: str |
651
|
|
|
|
652
|
|
|
:param filt: Filter, required to pick file out of directory listing. |
653
|
|
|
:type filt: str |
654
|
|
|
""" |
655
|
5 |
|
omfiles = set(os.path.join(omnin, "{1}{0}{2}".format(omni, prefix, suffix)) for omni in omnilist) |
656
|
5 |
|
infiles = set(os.path.join(omnin, filex) for filex in os.listdir(omnin) if filt in filex) |
657
|
5 |
|
return omfiles, infiles |
658
|
|
|
|
659
|
|
|
|
660
|
5 |
|
def generate_tclloader_oemset(oemin, oems): |
661
|
|
|
""" |
662
|
|
|
Generate sets for OEM variants. |
663
|
|
|
|
664
|
|
|
:param oemin: Directory containing files to copy. |
665
|
|
|
:type oemin: str |
666
|
|
|
|
667
|
|
|
:param oems: List of OEM variants. |
668
|
|
|
:type oems: list(str) |
669
|
|
|
""" |
670
|
5 |
|
ofiles, infiles = generate_tclloader_omniset(oemin, oems, "", ".img", "oem_") |
671
|
5 |
|
return ofiles, infiles |
672
|
|
|
|
673
|
|
|
|
674
|
5 |
|
def generate_tclloader_oemfilt(oemin, oems): |
675
|
|
|
""" |
676
|
|
|
Filter non-existent OEM variants. |
677
|
|
|
|
678
|
|
|
:param oemin: Directory containing files to copy. |
679
|
|
|
:type oemin: str |
680
|
|
|
|
681
|
|
|
:param oems: List of OEM variants. |
682
|
|
|
:type oems: list(str) |
683
|
|
|
""" |
684
|
5 |
|
ofiles, infiles = generate_tclloader_oemset(oemin, oems) |
685
|
5 |
|
coll = [os.path.basename(oemf).replace(".img", "") for oemf in ofiles - infiles] |
686
|
5 |
|
oems = [oemp for oemp in oems if oemp not in coll] |
687
|
5 |
|
return oems |
688
|
|
|
|
689
|
|
|
|
690
|
5 |
|
def generate_tclloader_radset(radin, rads): |
691
|
|
|
""" |
692
|
|
|
Generate sets for radio variants. |
693
|
|
|
|
694
|
|
|
:param radin: Directory containing files to copy. |
695
|
|
|
:type radin: str |
696
|
|
|
|
697
|
|
|
:param rads: List of radio variants. |
698
|
|
|
:type rads: list(str) |
699
|
|
|
""" |
700
|
5 |
|
rfiles, infiles = generate_tclloader_omniset(radin, rads, "NON-HLOS-", ".bin", "NON-HLOS-") |
701
|
5 |
|
return rfiles, infiles |
702
|
|
|
|
703
|
|
|
|
704
|
5 |
|
def generate_tclloader_radfilt(radin, rads): |
705
|
|
|
""" |
706
|
|
|
Filter non-existent radio variants. |
707
|
|
|
|
708
|
|
|
:param radin: Directory containing files to copy. |
709
|
|
|
:type radin: str |
710
|
|
|
|
711
|
|
|
:param rads: List of radio variants. |
712
|
|
|
:type rads: list(str) |
713
|
|
|
""" |
714
|
5 |
|
rfiles, infiles = generate_tclloader_radset(radin, rads) |
715
|
5 |
|
coll = [os.path.basename(radf).replace(".bin", "").replace("NON-HLOS-", "") for radf in rfiles - infiles] |
716
|
5 |
|
rads = [radp for radp in rads if radp not in coll] |
717
|
5 |
|
return rads |
718
|
|
|
|
719
|
|
|
|
720
|
5 |
|
def generate_tclloader_deps(platform): |
721
|
|
|
""" |
722
|
|
|
Generate platform-specific file names. |
723
|
|
|
|
724
|
|
|
:param platform: Platform type (i.e. subdirectory of target/product). |
725
|
|
|
:type platform: str |
726
|
|
|
""" |
727
|
5 |
|
if platform == "bbry_qc8953": # KEYone |
728
|
5 |
|
oems = ["oem_att", "oem_china", "oem_common", "oem_sprint", "oem_vzw", "oem_indonesia", "oem_russia"] |
729
|
5 |
|
radios = ["china", "dschina", "emea", "global", "india", "japan", "usa"] |
730
|
5 |
|
elif platform == "bbry_qc8953krypton": # Motion |
731
|
5 |
|
oems = ["oem_att", "oem_common", "oem_sprint", "oem_russia"] |
732
|
5 |
|
radios = ["americas", "cdma", "dscn", "dsglobal", "ssglobal"] |
733
|
5 |
|
elif platform == "bbry_sdm660": # KEY2 |
734
|
5 |
|
oems = ["oem_att", "oem_china", "oem_common", "oem_india", "oem_indonesia", "oem_sprint", "oem_russia"] |
735
|
5 |
|
radios = ["americas", "cn", "dsglobal", "dsjapan", "global", "japan"] |
736
|
5 |
|
return oems, radios |
737
|
|
|
|
738
|
|
|
|
739
|
5 |
|
def generate_tclloader_looseends(imgout, platform): |
740
|
|
|
""" |
741
|
|
|
Handle files that need to be handled. |
742
|
|
|
|
743
|
|
|
:param imgout: Directory that files are to be copied to. |
744
|
|
|
:type imgout: str |
745
|
|
|
|
746
|
|
|
:param platform: Platform type (i.e. subdirectory of target/product). |
747
|
|
|
:type platform: str |
748
|
|
|
""" |
749
|
5 |
|
if platform == "bbry_qc8953": # KEYone |
750
|
5 |
|
pass # no special exceptions |
751
|
5 |
|
elif platform == "bbry_qc8953krypton": # Motion |
752
|
5 |
|
looseends_krypton(imgout, platform) |
753
|
5 |
|
elif platform == "bbry_sdm660": # KEY2 |
754
|
5 |
|
pass # TODO: KEY2 autoloader |
|
|
|
|
755
|
|
|
|
756
|
|
|
|
757
|
5 |
|
def looseends_krypton(imgout, platform): |
|
|
|
|
758
|
|
|
""" |
759
|
|
|
Handle files that need to be handled, for the Motion platform. |
760
|
|
|
|
761
|
|
|
:param imgout: Directory that files are to be copied to. |
762
|
|
|
:type imgout: str |
763
|
|
|
|
764
|
|
|
:param platform: Platform type (i.e. subdirectory of target/product). |
765
|
|
|
:type platform: str |
766
|
|
|
""" |
767
|
5 |
|
oldglobal = os.path.join(imgout, "NON-HLOS-ssglobal.bin") |
768
|
5 |
|
newglobal = os.path.join(imgout, "NON-HLOS-global.bin") |
769
|
5 |
|
os.rename(oldglobal, newglobal) # SS intl model has different name than modem |
770
|
5 |
|
oldamericas = os.path.join(imgout, "NON-HLOS-americas.bin") |
771
|
5 |
|
newamericas = os.path.join(imgout, "NON-HLOS-dsamericas.bin") |
772
|
5 |
|
shutil.copy(oldamericas, newamericas) # DS/SS americas model use same modem |
773
|
|
|
|
774
|
|
|
|
775
|
5 |
|
def generate_tclloader_img(imgin, imgout, platform): |
776
|
|
|
""" |
777
|
|
|
Generate partition images and radios. |
778
|
|
|
|
779
|
|
|
:param imgin: Directory containing files to copy. |
780
|
|
|
:type imgin: str |
781
|
|
|
|
782
|
|
|
:param imgout: Directory that files are to be copied to. |
783
|
|
|
:type imgout: str |
784
|
|
|
|
785
|
|
|
:param platform: Platform type (i.e. subdirectory of target/product). |
786
|
|
|
:type platform: str |
787
|
|
|
""" |
788
|
5 |
|
imgs = ["recovery", "system", "userdata", "cache", "boot"] |
789
|
5 |
|
point_point_bulk(imgin, imgout, ["{0}.img".format(img) for img in imgs]) |
790
|
5 |
|
oems, radios = generate_tclloader_deps(platform) |
791
|
5 |
|
oems = generate_tclloader_oemfilt(imgin, oems) |
792
|
5 |
|
point_point_bulk(imgin, imgout, ["{0}.img".format(oem) for oem in oems]) |
793
|
5 |
|
radios = generate_tclloader_radfilt(imgin, radios) |
794
|
5 |
|
point_point_bulk(imgin, imgout, ["NON-HLOS-{0}.bin".format(rad) for rad in radios]) |
795
|
5 |
|
others = ["adspso.bin", "emmc_appsboot.mbn", "sbl1_signed.mbn"] |
796
|
5 |
|
point_point_bulk(imgin, imgout, others) |
797
|
5 |
|
generate_tclloader_looseends(imgout, platform) |
798
|
|
|
|
799
|
|
|
|
800
|
5 |
|
def generate_tclloader(localdir, dirname, platform, localtools=False, wipe=True): |
801
|
|
|
""" |
802
|
|
|
Generate Android loader from extracted template files. |
803
|
|
|
|
804
|
|
|
:param localdir: Directory containing extracted template files. |
805
|
|
|
:type localdir: str |
806
|
|
|
|
807
|
|
|
:param dirname: Name for final directory and loader. |
808
|
|
|
:type dirname: str |
809
|
|
|
|
810
|
|
|
:param platform: Platform type (i.e. subdirectory of target/product). |
811
|
|
|
:type platform: str |
812
|
|
|
|
813
|
|
|
:param localtools: If host files will be copied from a template rather than a download. Default is False. |
814
|
|
|
:type localtools: bool |
815
|
|
|
|
816
|
|
|
:param wipe: If the final loader wipes userdata. Default is True. |
817
|
|
|
:type wipe: bool |
818
|
|
|
""" |
819
|
5 |
|
if not os.path.exists(dirname): |
820
|
5 |
|
os.makedirs(dirname) |
821
|
5 |
|
hostdir = os.path.join(dirname, "host") |
822
|
5 |
|
os.makedirs(hostdir) |
823
|
5 |
|
imgdir = os.path.join(dirname, "img") |
824
|
5 |
|
os.makedirs(imgdir) |
825
|
5 |
|
generate_tclloader_script(dirname, bbconstants.FLASHBAT.location, bbconstants.FLASHSH.location, wipe) |
826
|
5 |
|
if localtools: |
827
|
5 |
|
hdir = os.path.join(localdir, "host") |
828
|
5 |
|
generate_tclloader_host(hdir, hostdir) |
829
|
|
|
else: |
830
|
5 |
|
platdir = "plattools" |
831
|
5 |
|
generate_google_host(platdir, hostdir) |
832
|
5 |
|
pdir = os.path.join(localdir, "target", "product", platform) |
833
|
5 |
|
generate_tclloader_img(pdir, imgdir, platform) |
834
|
5 |
|
sdir = os.path.join(pdir, "sig") |
835
|
5 |
|
generate_tclloader_sig(sdir, imgdir) |
836
|
5 |
|
generate_tclloader_carriers(sdir, imgdir) |
837
|
5 |
|
qdir = os.path.join(pdir, "qcbc") |
838
|
|
|
generate_tclloader_mbn(qdir, imgdir) |
839
|
|
|
|