Completed
Push — master ( 031bf5...ff3ed3 )
by John
03:05
created

autolookup_output_sql()   A

Complexity

Conditions 3

Size

Total Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 3

Importance

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