Completed
Push — master ( dd2253...97c371 )
by John
02:20
created

generate_google_host()   A

Complexity

Conditions 3

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
dl 0
loc 14
ccs 5
cts 5
cp 1
crap 3
rs 9.4285
c 0
b 0
f 0
1
#!/usr/bin/env python3
2 5
"""This module is used for creation of autoloaders.
3
A higher level interface for :mod:`bbarchivist.pseudocap`."""
4
5 5
import os  # path work
6 5
import glob  # filename matching
7 5
import shutil  # file copying
8 5
from bbarchivist import bbconstants  # versions/constants
9 5
from bbarchivist import exceptions  # exception handling
10 5
from bbarchivist import pseudocap  # implement cap
11 5
from bbarchivist import utilities  # directory handler
12 5
from bbarchivist import jsonutils  # json
13
14 5
__author__ = "Thurask"
15 5
__license__ = "WTFPL v2"
16 5
__copyright__ = "2015-2017 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 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 5
    shutil.copy(batchfile, os.path.join(dirname, "flashall.bat"))
463 5
    shutil.copy(shfile, os.path.join(dirname, "flashall.sh"))
464
465
466 5
def generate_google_host(hostin, hostout):
467
    """
468
    Generate host directory from Google platform tools, 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 5
    platforms = ["linux", "windows", "darwin"]
477 5
    inouts = {os.path.join(hostin, plat, "platform-tools"): os.path.join(hostout, "{0}-x86".format(plat), "bin") for plat in platforms}
478 5
    for infile, outfile in inouts.items():
479 5
        shutil.copytree(infile, outfile)        
0 ignored issues
show
Coding Style introduced by
Trailing whitespace
Loading history...
480
481
482 5
def generate_tclloader_host(hostin, hostout):
483
    """
484
    Generate host directory from autoloader template, i.e. fastboot.
485
486
    :param hostin: Directory containing files to copy.
487
    :type hostin: str
488
489
    :param hostout: Directory that files are to be copied to.
490
    :type hostout: str
491
    """
492 5
    os.makedirs(os.path.join(hostout, "darwin-x86", "bin"))
493 5
    os.makedirs(os.path.join(hostout, "linux-x86", "bin"))
494 5
    os.makedirs(os.path.join(hostout, "windows-x86", "bin"))
495 5
    macfile = os.path.join("darwin-x86", "bin", "fastboot")
496 5
    linfile = os.path.join("linux-x86", "bin", "fastboot")
497 5
    winx = ["AdbWinApi.dll", "AdbWinUsbApi.dll", "fastboot.exe"]
498 5
    winfiles = [os.path.join("windows-x86", "bin", x) for x in winx]
499 5
    shutil.copy(os.path.join(hostin, macfile), os.path.join(hostout, macfile))
500 5
    shutil.copy(os.path.join(hostin, linfile), os.path.join(hostout, linfile))
501 5
    for file in winfiles:
502 5
        shutil.copy(os.path.join(hostin, file), os.path.join(hostout, file))
503
504
505 5
def generate_tclloader_sig(sigin, sigout):
506
    """
507
    Generate signature files.
508
509
    :param sigin: Directory containing files to copy.
510
    :type sigin: str
511
512
    :param sigout: Directory that files are to be copied to.
513
    :type sigout: str
514
    """
515 5
    shutil.copy(os.path.join(sigin, "boot.img.production.sig"), os.path.join(sigout, "boot.img.sig"))
516 5
    shutil.copy(os.path.join(sigin, "recovery.img.production.sig"), os.path.join(sigout, "recovery.img.sig"))
517
518
519 5
def generate_tclloader_mbn(mdnin, mdnout):
520
    """
521
    Generate mbn files.
522
523
    :param mdnin: Directory containing files to copy.
524
    :type mdnin: str
525
526
    :param mdnout: Directory that files are to be copied to.
527
    :type mdnout: str
528
    """
529 5
    files = ["devcfg.mbn", "devcfg_cn.mbn", "rpm.mbn", "tz.mbn"]
530 5
    for file in files:
531 5
        shutil.copy(os.path.join(mdnin, file), os.path.join(mdnout, file))
532
533
534 5
def generate_tclloader_img(imgin, imgout):
535
    """
536
    Generate partition images and radios.
537
538
    :param imgin: Directory containing files to copy.
539
    :type imgin: str
540
541
    :param imgout: Directory that files are to be copied to.
542
    :type imgout: str
543
    """
544 5
    imgs = ["oem_att", "oem_china", "oem_common", "oem_sprint", "oem_vzw", "recovery", "system", "userdata", "cache", "boot"]
545 5
    for img in imgs:
546 5
        shutil.copy(os.path.join(imgin, "{0}.img".format(img)), os.path.join(imgout, "{0}.img".format(img)))
547 5
    radios = ["china", "emea", "global", "india", "japan", "usa"]
548 5
    for rad in radios:
549 5
        shutil.copy(os.path.join(imgin, "NON-HLOS-{0}.bin".format(rad)), os.path.join(imgout, "NON-HLOS-{0}.bin".format(rad)))
550 5
    others = ["adspso.bin", "emmc_appsboot.mbn", "sbl1_signed.mbn"]
551 5
    for file in others:
552 5
        shutil.copy(os.path.join(imgin, file), os.path.join(imgout, file))
553
554
555 5
def generate_tclloader(localdir, dirname, platform, localtools=False):
556
    """
557
    Generate Android loader from extracted template files.
558
559
    :param localdir: Directory containing extracted template files.
560
    :type localdir: str
561
562
    :param dirname: Name for final directory and loader.
563
    :type dirname: str
564
565
    :param platform: Platform type (i.e. subdirectory of target/product).
566
    :type platform: str
567
568
    :param localtools: If host files will be copied from a template rather than a download. Default is False.
569
    :type localtools: bool
570
    """
571 5
    if not os.path.exists(dirname):
572 5
        os.makedirs(dirname)
573 5
    hostdir = os.path.join(dirname, "host")
574 5
    os.makedirs(hostdir)
575 5
    imgdir = os.path.join(dirname, "img")
576 5
    os.makedirs(imgdir)
577 5
    generate_tclloader_script(dirname, bbconstants.FLASHBAT.location, bbconstants.FLASHSH.location)
578 5
    if localtools:
579 5
        hdir = os.path.join(localdir, "host")
580 5
        generate_tclloader_host(hdir, hostdir)
581
    else:
582 5
        platdir = "plattools"
583 5
        generate_google_host(platdir, hostdir)
584 5
    pdir = os.path.join(localdir, "target", "product", platform)
585 5
    generate_tclloader_img(pdir, imgdir)
586 5
    sdir = os.path.join(pdir, "sig")
587 5
    generate_tclloader_sig(sdir, imgdir)
588 5
    qdir = os.path.join(pdir, "qcbc")
589
    generate_tclloader_mbn(qdir, imgdir)
590