Completed
Push — master ( 6984a5...6133d7 )
by John
02:31
created

check_altsw()   A

Complexity

Conditions 3

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 3

Importance

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