Completed
Push — master ( ef95c0...e1ca39 )
by John
06:17
created

generate_tclloader_img()   A

Complexity

Conditions 4

Size

Total Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 4
dl 0
loc 19
ccs 0
cts 0
cp 0
crap 20
rs 9.2
c 1
b 0
f 1
1
#!/usr/bin/env python3
2 1
"""This module is used for creation of autoloaders.
3
A higher level interface for :mod:`bbarchivist.pseudocap`."""
4
5 1
import os  # path work
6 1
import glob  # filename matching
7 1
import shutil  # file copying
8 1
from bbarchivist import bbconstants  # versions/constants
9 1
from bbarchivist import exceptions  # exception handling
10 1
from bbarchivist import pseudocap  # implement cap
11
from bbarchivist import utilities  # directory handler
12 1
from bbarchivist import jsonutils  # json
13 1
14 1
__author__ = "Thurask"
15
__license__ = "WTFPL v2"
16
__copyright__ = "2015-2017 Thurask"
17 1
18
19
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 1
    :type core: bool
28
    """
29 1
    oslist = read_os_files(localdir, core)
30
    # [8960, 8x30, 8974, ti]
31 1
    radlist = read_radio_files(localdir)
32 1
    # [ti, z10, z10_vzw, q10, z30, z3, 8974]
33 1
    pairdict = {}
34 1
    mapping = {0:3, 1:0, 2:0, 3:0, 4:0, 5:1, 6:2}
35 1
    for idx, rad in enumerate(radlist):
36 1
        pairdict[rad] = oslist[mapping[idx]]
37
    filtdict = {k: v for k, v in pairdict.items() if k}  # pop None
38
    return filtdict
39 1
40
41
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 1
    :type silent: bool
56 1
    """
57 1
    try:
58 1
        signedfile = glob.glob(os.path.join(localdir, match))[0]
59 1
    except IndexError:
60 1
        signedfile = None
61 1
        if not silent:
62
            print("No {0} found".format(title))
63
    return signedfile
64 1
65
66
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 1
    :type core: bool
72 1
    """
73 1
    if core:
74 1
        fix8960 = "*qc8960.*_sfi.BB*.signed"
75 1
        fixomap_new = "*winchester.*_sfi.BB*.signed"
76 1
        fixomap_old = "*os.factory_sfi.BB*.signed"
77 1
        fix8930 = "*qc8x30.BB*.signed"
78
        fix8974_new = "*qc8974.BB*.signed"
79 1
        fix8974_old = "*qc8974.*_sfi.BB*.signed"
80 1
    else:
81 1
        fix8960 = "*qc8960.*_sfi.desktop.BB*.signed"
82 1
        fixomap_new = "*winchester.*_sfi.desktop.BB*.signed"
83 1
        fixomap_old = "*os.factory_sfi.desktop.BB*.signed"
84 1
        fix8930 = "*qc8x30.desktop.BB*.signed"
85 1
        fix8974_new = "*qc8974.desktop.BB*.signed"
86
        fix8974_old = "*qc8974.*_sfi.desktop.BB*.signed"
87
    return fix8960, fixomap_new, fixomap_old, fix8930, fix8974_new, fix8974_old
88 1
89
90
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 1
    :type core: bool
99
    """
100 1
    fix8960, fixomap_new, fixomap_old, fix8930, fix8974_new, fix8974_old = generate_os_fixes(core)
101
    # 8960
102 1
    os_8960 = find_signed_file(fix8960, localdir, "8960 OS")
103 1
    # 8x30 (10.3.1 MR+)
104 1
    os_8x30 = find_signed_file(fix8930, localdir, "8x30 OS", True)
105
    if os_8x30 is None:
106 1
        os_8x30 = find_signed_file(fix8960, localdir, "8x30 OS")
107 1
    # 8974
108 1
    os_8974 = find_signed_file(fix8974_new, localdir, "8974 OS", True)
109
    if os_8974 is None:
110 1
        os_8974 = find_signed_file(fix8974_old, localdir, "8974 OS")
111 1
    # OMAP
112 1
    os_ti = find_signed_file(fixomap_new, localdir, "OMAP OS", True)
113 1
    if os_ti is None:
114
        os_ti = find_signed_file(fixomap_old, localdir, "OMAP OS")
115
    return [os_8960, os_8x30, os_8974, os_ti]
116 1
117
118
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 1
    """
125
    # STL100-1
126 1
    radio_ti = find_signed_file("*radio.m5730*.signed", localdir, "OMAP radio")
127
    # STL100-X
128 1
    radio_z10 = find_signed_file("*radio.qc8960.BB*.signed", localdir, "8960 radio")
129
    # STL100-4
130 1
    radio_z10_vzw = find_signed_file("*radio.qc8960*omadm*.signed", localdir, "VZW 8960 radio")
131
    # Q10/Q5
132 1
    radio_q10 = find_signed_file("*radio.qc8960*wtr.*signed", localdir, "Q10/Q5 radio")
133
    # Z30/Classic
134 1
    radio_z30 = find_signed_file("*radio.qc8960*wtr5*.signed", localdir, "Z30/Classic radio")
135
    # Z3
136 1
    radio_z3 = find_signed_file("*radio.qc8930*wtr5*.signed", localdir, "Z3 radio")
137 1
    # Passport
138
    radio_8974 = find_signed_file("*radio.qc8974*wtr2*.signed", localdir, "Passport radio")
139
    return [radio_ti, radio_z10, radio_z10_vzw, radio_q10, radio_z30, radio_z3, radio_8974]
140 1
141
142
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 1
    :type padlen: int
154 1
    """
155 1
    if len(splitver[idx]) < padlen:
156
        splitver[idx] = splitver[idx].rjust(padlen, "0")
157
    return splitver
158 1
159
160
def versionpad(splitver):
161
    """
162
    Properly pad an OS/radio version.
163
164
    :param splitver: OS/radio version, but split into quarters.
165 1
    :type splitver: list(str)
166 1
    """
167 1
    splitver = zeropad(splitver, 2, 2)
168
    splitver = zeropad(splitver, 3, 4)
169
    return splitver
170 1
171
172
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 1
    """
182 1
    # 10.x.y.zzz becomes 10.x.0y.0zzz
183 1
    splitos = osversion.split(".")
184 1
    splitos = versionpad(splitos)
185 1
    the_os = ".".join(splitos)
186 1
    splitrad = radioversion.split(".")
187 1
    splitrad = versionpad(splitrad)
188
    the_radio = ".".join(splitrad)
189
    return the_os, the_radio
190 1
191
192
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 1
    :type core: bool
204 1
    """
205 1
    suffix = "_R{0}".format(radioversion) if altradio and radioversion else ""
206 1
    if core:
207
        suffix += "_CORE"
208
    return suffix
209 1
210
211
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 1
    """
233 1
    # default parsing
234 1
    localdir = utilities.dirhandler(localdir, os.getcwd())
235 1
    print("GETTING FILENAMES...")
236 1
    filedict = read_files(localdir, core)
237
    osversion, radioversion = pretty_formatter(osversion, radioversion)
238 1
    suffix = format_suffix(altradio, radioversion, core)
239 1
    # Generate loaders
240 1
    print("CREATING LOADERS...")
241
    filtrad = [rad for rad in filedict.keys() if rad]  # pop None
242
    generate_individual_loaders(filtrad, osversion, radioversion, suffix, filedict, radios, localdir)
243 1
244
245
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 1
    :type localdir: str
269 1
    """
270 1
    for radval in filtrad:
271 1
        device = generate_device(radval)
272 1
        osname = generate_filename(device, osversion, suffix)
273 1
        osfile = filedict[radval]
274 1
        if osfile is not None:
275 1
            wrap_pseudocap(osname, localdir, osfile, radval)
276 1
        if radios:
277
            radname = generate_filename(device, radioversion, "")
278
            wrap_pseudocap(radname, localdir, radval)
279
280 1
281
282
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 1
    :type second: str
297 1
    """
298 1
    if first is None:
299 1
        print("No OS!")
300 1
        raise SystemError
301 1
    try:
302 1
        pseudocap.make_autoloader(filename, [first, second], folder=folder)
303 1
    except (OSError, IndexError, SystemError) as exc:
304
        msg = "Could not create {0}".format(filename)
305
        exceptions.handle_exception(exc, msg, None)
306 1
307
308
def generate_skeletons():
309
    """
310 1
    Read JSON to get a dict of all filename components.
311 1
    """
312 1
    namelist = {0: None, 1: None, 2: None, 3: None, 4: None, 5: None, 6: None}
313 1
    data = jsonutils.load_json('integermap')
314 1
    for key in data:
315 1
        if key['id'] in namelist:
316 1
            namelist[key['id']] = (key['parts'])
317
            namelist[key['id']].append(".exe")
318
    return namelist
319 1
320
321
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 1
    :type radio: str
327 1
    """
328 1
    data = jsonutils.load_json('integermap')
329 1
    for key in data:
330 1
        if key['radtype'] in radio:
331 1
            idx = int(key['id'])
332
            break
333
    return idx
334 1
335
336
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 1
    :type suffix: str
348 1
    """
349 1
    thed = generate_skeletons()
350 1
    if device < 0:
351 1
        return None
352 1
    dev = thed[device]
353 1
    if suffix is None:
354
        suffix = ""
355
    return "{0}{1}{2}{3}{4}".format(dev[0], version, suffix, dev[1], dev[2])
356 1
357
358
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 1
    """
380 1
    # default parsing
381 1
    localdir = utilities.dirhandler(localdir, os.getcwd())
382 1
    print("CREATING LOADER...")
383 1
    suffix = format_suffix(bool(altradio), altradio, core)
384 1
    osfile = None
385 1
    absoglob = "{0}{1}".format(localdir, os.sep)
386 1
    try:
387 1
        osfile = str(glob.glob("{0}*_sfi*.signed".format(absoglob))[0])
388
    except IndexError:
389 1
        print("No OS found")
390
    else:
391
        generate_lazy_set(osversion, device, osfile, suffix, absoglob, localdir)
392 1
393
394
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 1
    :type localdir: str
415 1
    """
416 1
    radiofile = None
417 1
    try:
418 1
        sset = set(glob.glob("{0}*.signed".format(absoglob)))
419 1
        rset = sset - set(glob.glob("{0}*_sfi*.signed".format(absoglob)))
420 1
        radiofile = str(list(rset)[0])
421
    except IndexError:
422 1
        print("No radio found")
423 1
    else:
424
        loadername = generate_lazy_filename(osversion, suffix, device)
425
        wrap_pseudocap(loadername, localdir, osfile, radiofile)
426 1
427
428
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 1
    :type device: int
440 1
    """
441 1
    data = jsonutils.load_json('integermap')
442 1
    for key in data:
443 1
        if key['id'] == device:
444 1
            fname = key['parts']
445
            break
446
    return "{0}{1}{2}{3}.exe".format(fname[0], osversion, suffix, fname[1])
447
448
449
def generate_tclloader_script(dirname, batchfile, shfile):
450
    """
451
    Copy script files from site-packages to loader directory.
452
453
    :param dirname: Name for final directory and loader.
454
    :type dirname: str
455
456
    :param batchfile: Path to flashall.bat.
457
    :type batchfile: str
458
459
    :param shfile: Path to flashall.sh.
460
    :type shfile: str
461
    """
462
    shutil.copy(batchfile, os.path.join(dirname, "flashall.bat"))
463
    shutil.copy(shfile, os.path.join(dirname, "flashall.sh"))
464
465
466
def generate_tclloader_host(hostin, hostout):
467
    """
468
    Generate host directory, i.e. fastboot.
469
470
    :param hostin: Directory containing files to copy.
471
    :type hostin: str
472
473
    :param hostout: Directory that files are to be copied to.
474
    :type hostout: str
475
    """
476
    macfile = os.path.join("darwin-x86", "bin", "fastboot")
477
    linfile = os.path.join("linux-x86", "bin", "fastboot")
478
    winx = ["AdbWinApi.dll", "AdbWinUsbApi.dll", "fastboot.exe"]
479
    winfiles = [os.path.join("windows-x86", "bin", x) for x in winx]
480
    shutil.copy(os.path.join(hostin, macfile), os.path.join(hostout, macfile))
481
    shutil.copy(os.path.join(hostin, linfile), os.path.join(hostout, linfile))
482
    for file in winfiles:
483
        shutil.copy(os.path.join(hostin, file), os.path.join(hostout, file))
484
485
486
def generate_tclloader_sig(sigin, sigout):
487
    """
488
    Generate signature files.
489
490
    :param sigin: Directory containing files to copy.
491
    :type sigin: str
492
493
    :param sigout: Directory that files are to be copied to.
494
    :type sigout: str
495
    """
496
    shutil.copy(os.path.join(sigin, "boot.img.production.sig"), os.path.join(sigout, "boot.img.sig"))
497
    shutil.copy(os.path.join(sigin, "recovery.img.production.sig"), os.path.join(sigout, "recovery.img.sig"))
498
499
500
def generate_tclloader_mbn(mdnin, mdnout):
501
    """
502
    Generate mbn files.
503
504
    :param mdnin: Directory containing files to copy.
505
    :type mdnin: str
506
507
    :param mdnout: Directory that files are to be copied to.
508
    :type mdnout: str
509
    """
510
    files = ["devcfg.mbn", "devcfg_cn.mbn", "rpm.mbn", "tz.mbn"]
511
    for file in files:
512
        shutil.copy(os.path.join(mdnin, file), os.path.join(mdnout, file))
513
514
515
def generate_tclloader_img(imgin, imgout):
516
    """
517
    Generate partition images and radios.
518
519
    :param imgin: Directory containing files to copy.
520
    :type imgin: str
521
522
    :param imgout: Directory that files are to be copied to.
523
    :type imgout: str
524
    """
525
    imgs = ["oem_att", "oem_china", "oem_common", "oem_sprint", "oem_vzw", "recovery", "system", "userdata", "cache", "boot"]
526
    for img in imgs:
527
        shutil.copy(os.path.join(imgin, "{0}.img".format(img)), os.path.join(imgout, "{0}.img".format(img)))
528
    radios = ["china", "emea", "global", "india", "japan", "usa"]
529
    for rad in radios:
530
        shutil.copy(os.path.join(imgin, "NON-HLOS-{0}.bin".format(rad)), os.path.join(imgout, "NON-HLOS-{0}.bin".format(rad)))
531
    others = ["adspso.bin", "emmc_appsboot.mbn", "sbl1_signed.mbn"]
532
    for file in others:
533
        shutil.copy(os.path.join(imgin, file), os.path.join(imgout, file))
534
535
536
def generate_tclloader(localdir, dirname, platform):
537
    """
538
    Generate Android loader from extracted template files.
539
540
    :param localdir: Directory containing extracted template files.
541
    :type localdir: str
542
543
    :param dirname: Name for final directory and loader.
544
    :type dirname: str
545
546
    :param platform: Platform type (i.e. subdirectory of target/product).
547
    :type platform: str
548
    """
549
    if not os.path.exists(dirname):
550
        os.makedirs(dirname)
551
    hostdir = os.path.join(dirname, "host")
552
    os.makedirs(hostdir)
553
    os.makedirs(os.path.join(hostdir, "darwin-x86", "bin"))
554
    os.makedirs(os.path.join(hostdir, "linux-x86", "bin"))
555
    os.makedirs(os.path.join(hostdir, "windows-x86", "bin"))
556
    imgdir = os.path.join(dirname, "img")
557
    os.makedirs(imgdir)
558
    generate_tclloader_script(dirname, bbconstants.FLASHBAT.location, bbconstants.FLASHSH.location)
559
    hdir = os.path.join(localdir, "host")
560
    generate_tclloader_host(hdir, hostdir)
561
    pdir = os.path.join(localdir, "target", "product", platform)
562
    generate_tclloader_img(pdir, imgdir)
563
    sdir = os.path.join(pdir, "sig")
564
    generate_tclloader_sig(sdir, imgdir)
565
    qdir = os.path.join(pdir, "qcbc")
566
    generate_tclloader_mbn(qdir, imgdir)
567