Completed
Push — master ( 782a85...d1933a )
by John
02:41
created

autolookup_output()   B

Complexity

Conditions 1

Size

Total Lines 24

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 1

Importance

Changes 2
Bugs 1 Features 0
Metric Value
cc 1
c 2
b 1
f 0
dl 0
loc 24
ccs 6
cts 6
cp 1
crap 1
rs 8.9713
1
#!/usr/bin/env python3
2 4
"""This module contains various utilities for the scripts folder."""
3
4 4
import os  # path work
5 4
import getpass  # invisible password
6 4
import argparse  # generic parser
7 4
import sys  # getattr
8 4
import shutil  # folder removal
9 4
import subprocess  # running cfp/cap
10 4
import glob  # file lookup
11 4
import threading  # run stuff in background
12 4
from bbarchivist import utilities  # little things
13 4
from bbarchivist import barutils  # file system work
14 4
from bbarchivist import archiveutils  # archive support
15 4
from bbarchivist import bbconstants  # constants
16 4
from bbarchivist import hashutils  # gpg
17 4
from bbarchivist import networkutils  # network tools
18 4
from bbarchivist import textgenerator  # writing text to file
19 4
from bbarchivist import smtputils  # email
20 4
from bbarchivist import sqlutils  # sql
21
22 4
__author__ = "Thurask"
23 4
__license__ = "WTFPL v2"
24 4
__copyright__ = "Copyright 2015-2016 Thurask"
25
26
27 4
def shortversion():
28
    """
29
    Get short app version (Git tag).
30
    """
31 4
    if not getattr(sys, 'frozen', False):
32 4
        ver = bbconstants.VERSION
33
    else:
34 4
        verfile = glob.glob(os.path.join(os.getcwd(), "version.txt"))[0]
35 4
        with open(verfile) as afile:
36 4
            ver = afile.read()
37 4
    return ver
38
39
40 4
def longversion():
41
    """
42
    Get long app version (Git tag + commits + hash).
43
    """
44 4
    if not getattr(sys, 'frozen', False):
45 4
        ver = (bbconstants.LONGVERSION, bbconstants.COMMITDATE)
46
    else:
47 4
        verfile = glob.glob(os.path.join(os.getcwd(), "longversion.txt"))[0]
48 4
        with open(verfile) as afile:
49 4
            ver = afile.read().split("\n")
50 4
    return ver
51
52
53 4
def default_parser(name=None, desc=None, flags=None, vers=None):
54
    """
55
    A generic form of argparse's ArgumentParser.
56
57
    :param name: App name.
58
    :type name: str
59
60
    :param desc: App description.
61
    :type desc: str
62
63
    :param flags: Tuple of sections to add.
64
    :type flags: tuple(str)
65
66
    :param vers: Versions: [git commit hash, git commit date]
67
    :param vers: list(str)
68
    """
69 4
    if vers is None:
70 4
        vers = longversion()
71 4
    parser = argparse.ArgumentParser(
72
        prog=name,
73
        description=desc,
74
        epilog="https://github.com/thurask/bbarchivist")
75 4
    parser.add_argument(
76
        "-v",
77
        "--version",
78
        action="version",
79
        version="{0} {1} committed {2}".format(parser.prog, vers[0], vers[1]))
80 4
    if flags is not None:
81 4
        if "folder" in flags:
82 4
            parser.add_argument(
83
                "-f",
84
                "--folder",
85
                dest="folder",
86
                help="Working folder",
87
                default=None,
88
                metavar="DIR",
89
                type=utilities.file_exists)
90 4
        if "osr" in flags:
91 4
            parser.add_argument(
92
                "os",
93
                help="OS version")
94 4
            parser.add_argument(
95
                "radio",
96
                help="Radio version, 10.x.y.zzzz",
97
                nargs="?",
98
                default=None)
99 4
            parser.add_argument(
100
                "swrelease",
101
                help="Software version, 10.x.y.zzzz",
102
                nargs="?",
103
                default=None)
104 4
    return parser
105
106
107 4
def generic_windows_shim(scriptname, scriptdesc, target, version):
108
    """
109
    Generic CFP/CAP runner; Windows only.
110
111
    :param scriptname: Script name, 'bb-something'.
112
    :type scriptname: str
113
114 View Code Duplication
    :param scriptdesc: Script description, i.e. scriptname -h.
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
115
    :type scriptdesc: str
116
117
    :param target: Path to file to execute.
118
    :type target: str
119
120
    :param version: Version of target.
121
    :type version: str
122
    """
123 4
    parser = default_parser(scriptname, scriptdesc)
124 4
    capver = "|{0}".format(version)
125 4
    parser = external_version(parser, capver)
126 4
    parser.parse_known_args(sys.argv[1:])
127 4
    if utilities.is_windows():
128 4
        subprocess.call([target] + sys.argv[1:])
129
    else:
130 4
        print("Sorry, Windows only.")
131
132
133 4
def external_version(parser, addition):
134
    """
135
    Modify the version string of argparse.ArgumentParser, adding something.
136
137
    :param parser: Parser to modify.
138
    :type parser: argparse.ArgumentParser
139
140
    :param addition: What to add.
141
    :type addition: str
142
    """
143 4 View Code Duplication
    verarg = [arg for arg in parser._actions if isinstance(arg, argparse._VersionAction)][0]
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
144 4
    verarg.version = "{1}{0}".format(addition, verarg.version)
145 4
    return parser
146
147
148 4
def return_radio_version(osversion, radioversion=None):
149
    """
150
    Increment radio version, if need be.
151
152
    :param osversion: OS version.
153
    :type osversion: str
154
155
    :param radioversion: Radio version, None if incremented.
156
    :type radioversion: str
157
    """
158 4
    if radioversion is None:
159 4
        radioversion = utilities.increment(osversion, 1)
160 4
    return radioversion
161
162
163 4
def return_sw_checked(softwareversion, osversion):
164
    """
165
    Check software existence, return boolean.
166
167
    :param softwareversion: Software release version.
168
    :type softwareversion: str
169
170
    :param osversion: OS version.
171
    :type osversion: str
172
    """
173 4
    if softwareversion is None:
174 4
        serv = bbconstants.SERVERS["p"]
175 4
        softwareversion = networkutils.sr_lookup(osversion, serv)
176 4
        if softwareversion == "SR not in system":
177 4
            print("SOFTWARE RELEASE NOT FOUND")
178 4
            cont = utilities.s2b(input("INPUT MANUALLY? Y/N: "))
179 4
            if cont:
180 4
                softwareversion = input("SOFTWARE RELEASE: ")
181 4
                swchecked = False
182
            else:
183 4
                print("\nEXITING...")
184 4
                raise SystemExit  # bye bye
185
        else:
186 4
            swchecked = True
187
    else:
188 4
        swchecked = True
189 4
    return softwareversion, swchecked
190
191
192 4
def return_radio_sw_checked(altsw, radioversion):
193
    """
194
    Check radio software existence, return boolean.
195
196
    :param altsw: Software release version.
197
    :type altsw: str
198
199
    :param radioversion: Radio version.
200
    :type radioversion: str
201
    """
202 4
    if altsw == "checkme":
203 4
        serv = bbconstants.SERVERS["p"]
204 4
        testos = utilities.increment(radioversion, -1)
205 4
        altsw = networkutils.sr_lookup(testos, serv)
206 4
        if altsw == "SR not in system":
207 4
            print("RADIO SOFTWARE RELEASE NOT FOUND")
208 4
            cont = utilities.s2b(input("INPUT MANUALLY? Y/N: "))
209 4
            if cont:
210 4
                altsw = input("SOFTWARE RELEASE: ")
211 4
                altchecked = False
212
            else:
213 4
                print("\nEXITING...")
214 4
                raise SystemExit  # bye bye
215
        else:
216 4
            altchecked = True
217
    else:
218 4
        altchecked = True
219 4
    return altsw, altchecked
220
221
222 4
def check_sw(baseurl, softwareversion, swchecked):
223
    """
224
    Check existence of software release.
225
226
    :param baseurl: Base URL (from http to hashed SW release).
227
    :type basurl: str
228
229
    :param softwareversion: Software release.
230
    :type softwareversion: str
231
232
    :param swchecked: If we checked the sw release already.
233
    :type swchecked: bool
234
    """
235 4
    print("CHECKING SOFTWARE RELEASE AVAILABILITY...")
236 4
    if not swchecked:
237 4
        avlty = networkutils.availability(baseurl)
238 4
        if avlty:
239 4
            print("SOFTWARE RELEASE {0} EXISTS".format(softwareversion))
240
        else:
241 4
            print("SOFTWARE RELEASE {0} NOT FOUND".format(softwareversion))
242 4
            cont = utilities.s2b(input("CONTINUE? Y/N: "))
243 4
            if not cont:
244 4
                print("\nEXITING...")
245 4
                raise SystemExit
246
    else:
247 4
        print("SOFTWARE RELEASE {0} EXISTS".format(softwareversion))
248
249
250 4
def check_radio_sw(alturl, altsw, altchecked):
251
    """
252
    Check existence of radio software release.
253
254
    :param alturl: Radio base URL (from http to hashed SW release).
255
    :type alturl: str
256
257
    :param altsw: Radio software release.
258
    :type altsw: str
259
260
    :param altchecked: If we checked the sw release already.
261
    :type altchecked: bool
262
    """
263 4
    print("CHECKING RADIO SOFTWARE RELEASE...")
264 4
    if not altchecked:
265 4
        altavlty = networkutils.availability(alturl)
266 4
        if altavlty:
267 4
            print("SOFTWARE RELEASE {0} EXISTS".format(altsw))
268
        else:
269 4
            print("SOFTWARE RELEASE {0} NOT FOUND".format(altsw))
270 4
            cont = utilities.s2b(input("CONTINUE? Y/N: "))
271 4
            if not cont:
272 4
                print("\nEXITING...")
273 4
                raise SystemExit
274
    else:
275 4
        print("SOFTWARE RELEASE {0} EXISTS".format(altsw))
276
277
278 4
def check_os_single(osurl, osversion, device):
279
    """
280
    Check existence of single OS link.
281
282
    :param radiourl: Radio URL to check.
283
    :type radiourl: str
284
285
    :param radioversion: Radio version.
286
    :type radioversion: str
287
288
    :param device: Device family.
289
    :type device: int
290
    """
291 4
    osav = networkutils.availability(osurl)
292 4
    if not osav:
293 4
        print("{0} NOT AVAILABLE FOR {1}".format(osversion, bbconstants.DEVICES[device]))
294 4
        cont = utilities.s2b(input("CONTINUE? Y/N: "))
295 4
        if not cont:
296 4
            print("\nEXITING...")
297 4
            raise SystemExit
298
299
300 4
def check_os_bulk(osurls):
301
    """
302
    Check existence of list of OS links.
303
304
    :param osurls: OS URLs to check.
305
    :type osurls: list(str)
306
    """
307 4
    for url in osurls:
308 4
        osav = networkutils.availability(url)
309 4
        if osav:
310 4
            break
311
    else:
312 4
        print("OS VERSION NOT FOUND")
313 4
        cont = utilities.s2b(input("CONTINUE? Y/N: "))
314 4
        if not cont:
315 4
            print("\nEXITING...")
316 4
            raise SystemExit
317
318
319 4
def check_radio_single(radiourl, radioversion):
320
    """
321
    Check existence of single radio link.
322
323
    :param radiourl: Radio URL to check.
324
    :type radiourl: str
325
326
    :param radioversion: Radio version.
327
    :type radioversion: str
328
    """
329 4
    radav = networkutils.availability(radiourl)
330 4
    if not radav:
331 4
        print("RADIO VERSION NOT FOUND")
332 4
        cont = utilities.s2b(input("INPUT MANUALLY? Y/N: "))
333 4
        if cont:
334 4
            rad2 = input("RADIO VERSION: ")
335 4
            radiourl = radiourl.replace(radioversion, rad2)
336 4
            radioversion = rad2
337
        else:
338 4
            going = utilities.s2b(input("KEEP GOING? Y/N: "))
339 4
            if not going:
340 4
                print("\nEXITING...")
341 4
                raise SystemExit
342 4
    return radiourl, radioversion
343
344
345 4
def check_radio_bulk(radiourls, radioversion):
346
    """
347
    Check existence of list of radio links.
348
349
    :param radiourls: Radio URLs to check.
350
    :type radiourls: list(str)
351
352
    :param radioversion: Radio version.
353
    :type radioversion: str
354
    """
355 4
    for url in radiourls:
356 4
        radav = networkutils.availability(url)
357 4
        if radav:
358 4
            break
359
    else:
360 4
        print("RADIO VERSION NOT FOUND")
361 4
        cont = utilities.s2b(input("INPUT MANUALLY? Y/N: "))
362 4
        if cont:
363 4
            rad2 = input("RADIO VERSION: ")
364 4
            radiourls = [url.replace(radioversion, rad2) for url in radiourls]
365 4
            radioversion = rad2
366
        else:
367 4
            going = utilities.s2b(input("KEEP GOING? Y/N: "))
368 4
            if not going:
369 4
                print("\nEXITING...")
370 4
                raise SystemExit
371 4
    return radiourls, radioversion
372
373
374 4
def bulk_avail(urllist):
375
    """
376
    Filter 404 links out of URL list.
377
378
    :param urllist: URLs to check.
379
    :type urllist: list(str)
380
    """
381 4
    url2 = [x for x in urllist if networkutils.availability(x)]
382 4
    return url2
383
384
385 4
def get_baseurls(softwareversion, altsw=None):
386
    """
387
    Generate base URLs for bar links.
388
389
    :param softwareversion: Software version.
390
    :type softwareversion: str
391
392
    :param altsw: Radio software version, if necessary.
393
    :type altsw: str
394
    """
395 4
    baseurl = utilities.create_base_url(softwareversion)
396 4
    alturl = utilities.create_base_url(altsw) if altsw else None
397 4
    return baseurl, alturl
398
399
400 4
def get_sz_executable(compmethod):
401
    """
402
    Get 7z executable.
403
404
    :param compmethod: Compression method.
405
    :type compmethod: str
406
    """
407 4
    if compmethod != "7z":
408 4
        szexe = ""
409
    else:
410 4
        print("CHECKING PRESENCE OF 7ZIP...")
411 4
        psz = utilities.prep_seven_zip(True)
412 4
        if psz:
413 4
            print("7ZIP OK")
414 4
            szexe = utilities.get_seven_zip(False)
415
        else:
416 4
            szexe = ""
417 4
            print("7ZIP NOT FOUND")
418 4
            cont = utilities.s2b(input("CONTINUE? Y/N "))
419 4
            if cont:
420 4
                print("FALLING BACK TO ZIP...")
421 4
                compmethod = "zip"
422
            else:
423 4
                print("\nEXITING...")
424 4
                raise SystemExit  # bye bye
425 4
    return compmethod, szexe
426
427
428 4
def test_bar_files(localdir, urllist):
429
    """
430
    Test bar files after download.
431
432
    :param localdir: Directory.
433
    :type localdir: str
434
435
    :param urllist: List of URLs to check.
436
    :type urllist: list(str)
437
    """
438 4
    brokenlist = []
439 4
    print("TESTING BAR FILES...")
440 4
    for file in os.listdir(localdir):
441 4
        if file.endswith(".bar"):
442 4
            print("TESTING: {0}".format(file))
443 4
            thepath = os.path.abspath(os.path.join(localdir, file))
444 4
            brokens = barutils.bar_tester(thepath)
445 4
            if brokens is not None:
446 4
                os.remove(brokens)
447 4
                for url in urllist:
448 4
                    if brokens in url:
449 4
                        brokenlist.append(url)
450 4
    if brokenlist:
451 4
        print("SOME FILES ARE BROKEN!")
452 4
        utilities.lprint(brokenlist)
453 4
        raise SystemExit
454
    else:
455 4
        print("BAR FILES DOWNLOADED OK")
456
457
458 4
def test_signed_files(localdir):
459
    """
460
    Test signed files after extract.
461
462
    :param localdir: Directory.
463
    :type localdir: str
464
    """
465 4
    print("TESTING SIGNED FILES...")
466 4
    for file in os.listdir(localdir):
467 4
        if file.endswith(".bar"):
468 4
            print("TESTING: {0}".format(file))
469 4
            signname, signhash = barutils.retrieve_sha512(os.path.join(localdir, file))
470 4
            sha512ver = barutils.verify_sha512(os.path.join(localdir, signname.decode("utf-8")), signhash)
471 4
            if not sha512ver:
472 4
                print("{0} IS BROKEN".format((file)))
473 4
                break
474
    else:
475 4
        print("ALL FILES EXTRACTED OK")
476
477
478 4
def test_loader_files(localdir):
479
    """
480
    Test loader files after creation.
481
482
    :param localdir: Directory.
483
    :type localdir: str
484
    """
485 4
    if not utilities.is_windows():
486 4
        pass
487
    else:
488 4
        print("TESTING LOADER FILES...")
489 4
        brokens = utilities.verify_bulk_loaders(localdir)
490 4
        if brokens:
491 4
            print("BROKEN FILES:")
492 4
            utilities.lprint(brokens)
493 4
            raise SystemExit
494
        else:
495 4
            print("ALL FILES CREATED OK")
496
497
498 4
def test_single_loader(loaderfile):
499
    """
500
    Test single loader file after creation.
501
502
    :param loaderfile: File to check.
503
    :type loaderfile: str
504
    """
505 4
    if not utilities.is_windows():
506 4
        pass
507
    else:
508 4
        print("TESTING LOADER...")
509 4
        if not utilities.verify_loader_integrity(loaderfile):
510 4
            print("{0} IS BROKEN!".format(os.path.basename(loaderfile)))
511 4
            raise SystemExit
512
        else:
513 4
            print("LOADER CREATED OK")
514
515
516 4
def prod_avail(results, mailer=False, osversion=None, password=None):
517
    """
518
    Clean availability for production lookups for autolookup script.
519
520
    :param results: Result dict.
521
    :type results: dict(str: str)
522
523
    :param mailer: If we're mailing links. Default is false.
524
    :type mailer: bool
525
526
    :param osversion: OS version.
527
    :type osversion: str
528
529
    :param password: Email password.
530
    :type password: str
531
    """
532
    prel = results['p']
533
    if prel != "SR not in system" and prel is not None:
534
        pav = "PD"
535
        baseurl = utilities.create_base_url(prel)
536
        avail = networkutils.availability(baseurl)
537
        is_avail = "Available" if avail else "Unavailable"
538
        if avail and mailer:
539
            sqlutils.prepare_sw_db()
540
            if not sqlutils.check_exists(osversion, prel):
541
                rad = utilities.increment(osversion, 1)
542
                linkgen(osversion, rad, prel, temp=True)
543
                smtputils.prep_email(osversion, prel, password)
544
    else:
545
        pav = "  "
546
        is_avail = "Unavailable"
547
    return prel, pav, is_avail
548
549
550 4
def linkgen(osversion, radioversion=None, softwareversion=None, altsw=None, temp=False, sdk=False):
551
    """
552
    Generate debrick/core/radio links for given OS, radio, software release.
553
554
    :param osversion: OS version, 10.x.y.zzzz.
555
    :type osversion: str
556
557
    :param radioversion: Radio version, 10.x.y.zzzz. Can be guessed.
558
    :type radioversion: str
559
560
    :param softwareversion: Software version, 10.x.y.zzzz. Can be guessed.
561
    :type softwareversion: str
562
563
    :param altsw: Radio software release, if not the same as OS.
564
    :type altsw: str
565
566
    :param temp: If file we write to is temporary. Default is False.
567
    :type temp: bool
568
569
    :param sdk: If we specifically want SDK images. Default is False.
570
    :type sdk: bool
571
    """
572 4
    radioversion = return_radio_version(osversion, radioversion)
573 4
    softwareversion, swc = return_sw_checked(softwareversion, osversion)
574 4
    del swc
575 4
    if altsw is not None:
576 4
        altsw, aswc = return_radio_sw_checked(altsw, radioversion)
577 4
        del aswc
578 4
    baseurl = utilities.create_base_url(softwareversion)
579 4
    oses, cores, radios = textgenerator.url_gen(osversion, radioversion, softwareversion)
580 4
    if altsw is not None:
581 4
        del radios
582 4
        dbks, cors, radios = textgenerator.url_gen(osversion, radioversion, altsw)
583 4
        del dbks
584 4
        del cors
585 4
    avlty = networkutils.availability(baseurl)
586 4
    if sdk:
587 4
        oses2 = {key: val.replace("factory_sfi", "sdk") for key, val in oses.items()}
588 4
        cores2 = {key: val.replace("factory_sfi", "sdk") for key, val in cores.items()}
589 4
        oses = {key: val.replace("verizon_sfi", "sdk") for key, val in oses2.items()}
590 4
        cores = {key: val.replace("verizon_sfi", "sdk") for key, val in cores2.items()}
591 4
    prargs = (softwareversion, osversion, radioversion, oses, cores, radios, avlty, False, None, temp, altsw)
592 4
    lthr = threading.Thread(target=textgenerator.write_links, args=prargs)
593 4
    lthr.start()
594
595
596 4
def clean_swrel(swrelset):
597
    """
598
    Clean a list of software release lookups.
599
600
    :param swrelset: List of software releases.
601
    :type swrelset: set(str)
602
    """
603 4
    for i in swrelset:
604 4
        if i != "SR not in system" and i is not None:
605 4
            swrelease = i
606 4
            break
607
    else:
608 4
        swrelease = ""
609 4
    return swrelease
610
611
612 4
def autolookup_logger(record, out):
613
    """
614
    Write autolookup results to file.
615
616
    :param record: The file to log to.
617
    :type record: str
618
619
    :param out: Output block.
620
    :type out: str
621
    """
622 4
    with open(record, "a") as rec:
623 4
        rec.write("{0}\n".format(out))
624
625
626 4
def autolookup_printer(out, avail, log=False, quiet=False, record=None):
627
    """
628
    Print autolookup results, logging if specified.
629
630
    :param out: Output block.
631
    :type out: str
632
633
    :param avail: Availability. Can be "Available" or "Unavailable".
634
    :type avail: str
635
636
    :param log: If we're logging to file.
637
    :type log: bool
638
639
    :param quiet: If we only note available entries.
640
    :type quiet: bool
641
642
    :param record: If we're logging, the file to log to.
643
    :type record: str
644
    """
645 4
    if not quiet:
646 4
        avail = "Available"  # force things
647 4
    if avail.lower() == "available":
648 4
        if log:
649 4
            lthr = threading.Thread(target=autolookup_logger, args=(record, out))
650 4
            lthr.start()
651 4
        print(out)
652
653
654 4
def autolookup_output_sql(osversion, swrelease, avail, sql=False):
655
    """
656
    Add OS to SQL database.
657
658
    :param osversion: OS version.
659
    :type osversion: str
660
661
    :param swrelease: Software release.
662
    :type swrelease: str
663
664
    :param avail: "Unavailable" or "Available".
665
    :type avail: str
666
667
    :param sql: If we're adding this to our SQL database.
668
    :type sql: bool
669
    """
670 4
    if sql:
671
        sqlutils.prepare_sw_db()
672
        if not sqlutils.check_exists(osversion, swrelease):
673
            sqlutils.insert(osversion, swrelease, avail.lower())
674
675
676 4
def autolookup_output(osversion, swrelease, avail, avpack, sql=False):
677
    """
678
    Prepare autolookup block, and add to SQL database.
679
680
    :param osversion: OS version.
681
    :type osversion: str
682
683
    :param swrelease: Software release.
684
    :type swrelease: str
685
686
    :param avail: "Unavailable" or "Available".
687
    :type avail: str
688
689
    :param avpack: Availabilities: alpha 1 and 2, beta 1 and 2, production.
690
    :type avpack: list(str)
691
692
    :param sql: If we're adding this to our SQL database.
693
    :type sql: bool
694
    """
695 4
    othr = threading.Thread(target=autolookup_output_sql, args=(osversion, swrelease, avail, sql))
696 4
    othr.start()
697 4
    avblok = "[{0}|{1}|{2}|{3}|{4}]".format(*avpack)
698 4
    out = "OS {0} - SR {1} - {2} - {3}".format(osversion, swrelease, avblok, avail)
699 4
    return out
700
701
702 4
def export_cchecker(files, npc, hwid, osv, radv, swv, upgrade=False, forced=None):
703
    """
704
    Write carrierchecker lookup links to file.
705
706
    :param files: List of file URLs.
707
    :type files: list(str)
708
709
    :param npc: MCC + MNC (ex. 302220).
710
    :type npc: int
711
712
    :param hwid: Device hardware ID.
713
    :type hwid: str
714
715
    :param osv: OS version.
716
    :type osv: str
717
718
    :param radv: Radio version.
719
    :type radv: str
720
721
    :param swv: Software release.
722
    :type swv: str
723
724
    :param upgrade: Whether or not to use upgrade files. Default is false.
725
    :type upgrade: bool
726
727
    :param forced: Force a software release. None to go for latest.
728
    :type forced: str
729
    """
730 4
    if files:
731 4
        if not upgrade:
732 4
            newfiles = networkutils.carrier_query(npc, hwid, True, False, forced)
733 4
            cleanfiles = newfiles[3]
734
        else:
735 4
            cleanfiles = files
736 4
        osurls, coreurls, radiourls = textgenerator.url_gen(osv, radv, swv)
737 4
        stoppers = ["8960", "8930", "8974", "m5730", "winchester"]
738 4
        finals = [link for link in cleanfiles if all(word not in link for word in stoppers)]
739 4
        textgenerator.write_links(swv, osv, radv, osurls, coreurls, radiourls, True, True, finals)
740 4
        print("\nFINISHED!!!")
741
    else:
742 4
        print("CANNOT EXPORT, NO SOFTWARE RELEASE")
743
744
745 4
def generate_blitz_links(files, osv, radv, swv):
746
    """
747
    Generate blitz URLs (i.e. all OS and radio links).
748
    :param files: List of file URLs.
749
    :type files: list(str)
750
751
    :param osv: OS version.
752
    :type osv: str
753
754
    :param radv: Radio version.
755
    :type radv: str
756
757
    :param swv: Software release.
758
    :type swv: str
759
    """
760 4
    coreurls = [
761
        utilities.create_bar_url(swv, "winchester.factory_sfi", osv),
762
        utilities.create_bar_url(swv, "qc8960.factory_sfi", osv),
763
        utilities.create_bar_url(swv, "qc8960.factory_sfi", osv),
764
        utilities.create_bar_url(swv, "qc8980.factory_sfi_hybrid_qc8974", osv)
765
    ]
766 4
    radiourls = [
767
        utilities.create_bar_url(swv, "m5730", radv),
768
        utilities.create_bar_url(swv, "qc8960", radv),
769
        utilities.create_bar_url(swv, "qc8960.wtr", radv),
770
        utilities.create_bar_url(swv, "qc8960.wtr5", radv),
771
        utilities.create_bar_url(swv, "qc8930.wtr5", radv),
772
        utilities.create_bar_url(swv, "qc8974.wtr2", radv)
773
    ]
774 4
    return files + coreurls + radiourls
775
776
777 4
def package_blitz(bardir, swv):
778
    """
779
    Package and verify a blitz package.
780
781
    :param bardir: Path to folder containing bar files.
782
    :type bardir: str
783
784
    :param swv: Software version.
785
    :type swv: str
786
    """
787
    print("\nCREATING BLITZ...")
788
    barutils.create_blitz(bardir, swv)
789
    print("\nTESTING BLITZ...")
790
    zipver = archiveutils.zip_verify("Blitz-{0}.zip".format(swv))
791
    if not zipver:
792
        print("BLITZ FILE IS BROKEN")
793
        raise SystemExit
794
    else:
795
        shutil.rmtree(bardir)
796
797
798 4
def purge_dross(files, craplist):
799
    """
800
    Get rid of Nuance/retaildemo apps in a list of apps.
801
802
    :param files: List of URLs to clean.
803
    :type files: list(str)
804
805
    :param craplist: List of fragments to check for and remove.
806
    :type craplist: list(str)
807
    """
808 4
    files2 = [file for file in files if all(word not in file for word in craplist)]
809 4
    return files2
810
811
812 4
def slim_preamble(appname):
813
    """
814
    Standard app name header.
815
816
    :param appname: Name of app.
817
    :type appname: str
818
    """
819 4
    print("~~~{0} VERSION {1}~~~".format(appname.upper(), shortversion()))
820
821
822 4
def standard_preamble(appname, osversion, softwareversion, radioversion, altsw=None):
823
    """
824
    Standard app name, OS, radio and software (plus optional radio software) print block.
825
826
    :param appname: Name of app.
827
    :type appname: str
828
829
    :param osversion: OS version, 10.x.y.zzzz. Required.
830
    :type osversion: str
831
832
    :param radioversion: Radio version, 10.x.y.zzzz. Can be guessed.
833
    :type radioversion: str
834
835
    :param softwareversion: Software release, 10.x.y.zzzz. Can be guessed.
836
    :type softwareversion: str
837
838
    :param altsw: Radio software release, if not the same as OS.
839
    :type altsw: str
840
    """
841 4
    slim_preamble(appname)
842 4
    print("OS VERSION: {0}".format(osversion))
843 4
    print("OS SOFTWARE VERSION: {0}".format(softwareversion))
844 4
    print("RADIO VERSION: {0}".format(radioversion))
845 4
    if altsw is not None:
846 4
        print("RADIO SOFTWARE VERSION: {0}".format(altsw))
847
848
849 4
def verify_gpg_credentials():
850
    """
851
    Read GPG key/pass from file, verify if incomplete.
852
    """
853 4
    gpgkey, gpgpass = hashutils.gpg_config_loader()
854 4
    if gpgkey is None or gpgpass is None:
855 4
        print("NO PGP KEY/PASS FOUND")
856 4
        cont = utilities.s2b(input("CONTINUE (Y/N)?: "))
857 4
        if cont:
858 4
            if gpgkey is None:
859 4
                gpgkey = input("PGP KEY (0x12345678): ")
860 4
                if not gpgkey.startswith("0x"):
861 4
                    gpgkey = "0x{0}".format(gpgkey)   # add preceding 0x
862 4
            if gpgpass is None:
863 4
                gpgpass = getpass.getpass(prompt="PGP PASSPHRASE: ")
864 4
                writebool = utilities.s2b(input("SAVE PASSPHRASE (Y/N)?:"))
865
            else:
866 4
                writebool = False
867 4
            gpgpass2 = gpgpass if writebool else None
868 4
            hashutils.gpg_config_writer(gpgkey, gpgpass2)
869
        else:
870 4
            gpgkey = None
871 4
    return gpgkey, gpgpass
872
873
874 4
def bulk_hash(dirs, compressed=True, deleted=True, radios=True, hashdict=None):
875
    """
876
    Hash files in several folders based on flags.
877
878
    :param dirs: Folders: [OS_bars, radio_bars, OS_exes, radio_exes, OS_zips, radio_zips]
879
    :type dirs: list(str)
880
881
    :param compressed: Whether to hash compressed files. True by default.
882
    :type compressed: bool
883
884
    :param deleted: Whether to delete uncompressed files. True by default.
885
    :type deleted: bool
886
887
    :param radios: Whether to hash radio autoloaders. True by default.
888
    :type radios: bool
889
890
    :param hashdict: Dictionary of hash rules, in ~\bbarchivist.ini.
891
    :type hashdict: dict({str: bool})
892
    """
893 4
    print("HASHING LOADERS...")
894 4
    if compressed:
895 4
        hashutils.verifier(dirs[4], hashdict)
896 4
        if radios:
897 4
            hashutils.verifier(dirs[5], hashdict)
898 4
    if not deleted:
899 4
        hashutils.verifier(dirs[2], hashdict)
900 4
        if radios:
901 4
            hashutils.verifier(dirs[3], hashdict)
902
903
904 4
def bulk_verify(dirs, compressed=True, deleted=True, radios=True):
905
    """
906
    Verify files in several folders based on flags.
907
908
    :param dirs: Folders: [OS_bars, radio_bars, OS_exes, radio_exes, OS_zips, radio_zips]
909
    :type dirs: list(str)
910
911
    :param compressed: Whether to hash compressed files. True by default.
912
    :type compressed: bool
913
914
    :param deleted: Whether to delete uncompressed files. True by default.
915
    :type deleted: bool
916
917
    :param radios: Whether to hash radio autoloaders. True by default.
918
    :type radios: bool
919
    """
920 4
    gpgkey, gpgpass = verify_gpg_credentials()
921 4
    if gpgpass is not None and gpgkey is not None:
922 4
        print("VERIFYING LOADERS...")
923 4
        print("KEY: {0}".format(gpgkey))
924 4
        if compressed:
925 4
            hashutils.gpgrunner(dirs[4], gpgkey, gpgpass, True)
926 4
            if radios:
927 4
                hashutils.gpgrunner(dirs[5], gpgkey, gpgpass, True)
928 4
        if not deleted:
929 4
            hashutils.gpgrunner(dirs[2], gpgkey, gpgpass, True)
930 4
            if radios:
931 4
                hashutils.gpgrunner(dirs[3], gpgkey, gpgpass, True)
932
933
934 4
def enn_ayy(quant):
935
    """
936
    Cheeky way to put a N/A placeholder for a string.
937
938
    :param quant: What to check if it's None.
939
    :type quant: str
940
    """
941 4
    return "N/A" if quant is None else quant
942
943
944 4
def info_header(afile, osver, radio=None, software=None, device=None):
945
    """
946
    Write header for info file.
947
948
    :param afile: Open file to write to.
949
    :type afile: File object
950
951
    :param osver: OS version, required for both types.
952
    :type osver: str
953
954
    :param radio: Radio version, required for QNX.
955
    :type radio: str
956
957
    :param software: Software release, required for QNX.
958
    :type software: str
959
960
    :param device: Device type, required for Android.
961
    :type device: str
962
    """
963 4
    afile.write("OS: {0}\n".format(osver))
964 4
    if device:
965 4
        afile.write("Device: {0}\n".format(enn_ayy(device)))
966
    else:
967 4
        afile.write("Radio: {0}\n".format(enn_ayy(radio)))
968 4
        afile.write("Software: {0}\n".format(enn_ayy(software)))
969 4
    afile.write("{0}\n".format("~"*40))
970
971
972 4
def make_info(filepath, osver, radio=None, software=None, device=None):
973
    """
974
    Create a new-style info (names, sizes and hashes) file.
975
976
    :param filepath: Path to folder to analyze.
977
    :type filepath: str
978
979
    :param osver: OS version, required for both types.
980
    :type osver: str
981
982
    :param radio: Radio version, required for QNX.
983
    :type radio: str
984
985
    :param software: Software release, required for QNX.
986
    :type software: str
987
988
    :param device: Device type, required for Android.
989
    :type device: str
990
    """
991 4
    fileext = ".zip" if device else ".7z"
992 4
    files = os.listdir(filepath)
993 4
    absfiles = [os.path.join(filepath, x) for x in files if x.endswith((fileext, ".exe"))]
994 4
    fname = os.path.join(filepath, "!{0}_OSINFO!.txt".format(osver))
995 4
    with open(fname, "w") as afile:
996 4
        info_header(afile, osver, radio, software, device)
997 4
        for indx, file in enumerate(absfiles):
998 4
            fsize = os.stat(file).st_size
999 4
            afile.write("File: {0}\n".format(os.path.basename(file)))
1000 4
            afile.write("\tSize: {0} ({1})\n".format(fsize, utilities.fsizer(fsize)))
1001 4
            afile.write("\tHashes:\n")
1002 4
            afile.write("\t\tMD5: {0}\n".format(hashutils.hm5(file).upper()))
1003 4
            afile.write("\t\tSHA1: {0}\n".format(hashutils.hs1(file).upper()))
1004 4
            afile.write("\t\tSHA256: {0}\n".format(hashutils.hs256(file).upper()))
1005 4
            afile.write("\t\tSHA512: {0}\n".format(hashutils.hs512(file).upper()))
1006 4
            if indx != len(absfiles) - 1:
1007 4
                afile.write("\n")
1008
1009
1010 4
def bulk_info(dirs, osv, compressed=True, deleted=True, radios=True, rad=None, swv=None, dev=None):
1011
    """
1012
    Generate info files in several folders based on flags.
1013
1014
    :param dirs: Folders: [OS_bars, radio_bars, OS_exes, radio_exes, OS_zips, radio_zips]
1015
    :type dirs: list(str)
1016
1017
    :param osver: OS version, required for both types.
1018
    :type osver: str
1019
1020
    :param compressed: Whether to hash compressed files. True by default.
1021
    :type compressed: bool
1022
1023
    :param deleted: Whether to delete uncompressed files. True by default.
1024
    :type deleted: bool
1025
1026
    :param radios: Whether to hash radio autoloaders. True by default.
1027
    :type radios: bool
1028
1029
    :param rad: Radio version, required for QNX.
1030
    :type rad: str
1031
1032
    :param swv: Software release, required for QNX.
1033
    :type swv: str
1034
1035
    :param dev: Device type, required for Android.
1036
    :type dev: str
1037
    """
1038 4
    print("GENERATING INFO FILES...")
1039 4
    if compressed:
1040 4
        make_info(dirs[4], osv, rad, swv, dev)
1041 4
        if radios:
1042 4
            make_info(dirs[5], osv, rad, swv, dev)
1043 4
    if not deleted:
1044 4
        make_info(dirs[2], osv, rad, swv, dev)
1045 4
        if radios:
1046
            make_info(dirs[3], osv, rad, swv, dev)
1047