Completed
Push — master ( 6bbd0e...9b31df )
by John
01:18
created

linkgen()   B

Complexity

Conditions 3

Size

Total Lines 38

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
dl 0
loc 38
rs 8.8571
c 0
b 0
f 0
1
#!/usr/bin/env python3
2
"""This module contains various utilities for the scripts folder."""
3
4
import os  # path work
5
import getpass  # invisible password
6
import argparse  # generic parser
7
import sys  # getattr
8
import shutil  # folder removal
9
import glob  # file lookup
10
from bbarchivist import utilities  # little things
11
from bbarchivist import barutils  # file system work
12
from bbarchivist import archiveutils  # archive support
0 ignored issues
show
Unused Code introduced by
Unused archiveutils imported from bbarchivist
Loading history...
13
from bbarchivist import bbconstants  # constants
14
from bbarchivist import hashutils  # gpg
15
from bbarchivist import networkutils  # network tools
16
from bbarchivist import textgenerator  # writing text to file
17
from bbarchivist import smtputils  # email
18
from bbarchivist import sqlutils  # sql
19
20
__author__ = "Thurask"
21
__license__ = "WTFPL v2"
22
__copyright__ = "Copyright 2015-2016 Thurask"
23
24
25
def shortversion():
26
    """
27
    Get short app version (Git tag).
28
    """
29
    if not getattr(sys, 'frozen', False):
30
        ver = bbconstants.VERSION
31
    else:
32
        verfile = glob.glob(os.path.join(os.getcwd(), "version.txt"))[0]
33
        with open(verfile) as afile:
34
            ver = afile.read()
35
    return ver
36
37
38
def longversion():
39
    """
40
    Get long app version (Git tag + commits + hash).
41
    """
42
    if not getattr(sys, 'frozen', False):
43
        ver = (bbconstants.LONGVERSION, bbconstants.COMMITDATE)
44
    else:
45
        verfile = glob.glob(os.path.join(os.getcwd(), "longversion.txt"))[0]
46
        with open(verfile) as afile:
47
            ver = afile.read().split("\n")
48
    return ver
49
50
51
def default_parser(name=None, desc=None, flags=None, vers=None):
52
    """
53
    A generic form of argparse's ArgumentParser.
54
55
    :param name: App name.
56
    :type name: str
57
58
    :param desc: App description.
59
    :type desc: str
60
61
    :param flags: Tuple of sections to add.
62
    :type flags: tuple(str)
63
64
    :param vers: Versions: [git commit hash, git commit date]
65
    :param vers: list(str)
66
    """
67
    if vers is None:
68
        vers = longversion()
69
    parser = argparse.ArgumentParser(
70
        prog=name,
71
        description=desc,
72
        epilog="https://github.com/thurask/bbarchivist")
73
    parser.add_argument(
74
        "-v",
75
        "--version",
76
        action="version",
77
        version="{0} {1} committed {2}".format(parser.prog, vers[0], vers[1]))
78
    if flags is not None:
79
        if "folder" in flags:
80
            parser.add_argument(
81
                "-f",
82
                "--folder",
83
                dest="folder",
84
                help="Working folder",
85
                default=None,
86
                metavar="DIR",
87
                type=utilities.file_exists)
88
        if "osr" in flags:
89
            parser.add_argument(
90
                "os",
91
                help="OS version, 10.x.y.zzzz")
92
            parser.add_argument(
93
                "radio",
94
                help="Radio version, 10.x.y.zzzz",
95
                nargs="?",
96
                default=None)
97
            parser.add_argument(
98
                "swrelease",
99
                help="Software version, 10.x.y.zzzz",
100
                nargs="?",
101
                default=None)
102
    return parser
103
104
105
def return_radio_version(osversion, radioversion=None):
106
    """
107
    Increment radio version, if need be.
108
109
    :param osversion: OS version.
110
    :type osversion: str
111
112
    :param radioversion: Radio version, None if incremented.
113
    :type radioversion: str
114 View Code Duplication
    """
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
115
    if radioversion is None:
116
        radioversion = utilities.increment(osversion, 1)
117
    return radioversion
118
119
120
def return_sw_checked(softwareversion, osversion):
121
    """
122
    Check software existence, return boolean.
123
124
    :param softwareversion: Software release version.
125
    :type softwareversion: str
126
127
    :param osversion: OS version.
128
    :type osversion: str
129
    """
130
    if softwareversion is None:
131
        serv = bbconstants.SERVERS["p"]
132
        softwareversion = networkutils.sr_lookup(osversion, serv)
133
        if softwareversion == "SR not in system":
134
            print("SOFTWARE RELEASE NOT FOUND")
135
            cont = utilities.s2b(input("INPUT MANUALLY? Y/N: "))
136
            if cont:
137
                softwareversion = input("SOFTWARE RELEASE: ")
138
                swchecked = False
139
            else:
140
                print("\nEXITING...")
141
                raise SystemExit  # bye bye
142
        else:
143 View Code Duplication
            swchecked = True
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
144
    else:
145
        swchecked = True
146
    return softwareversion, swchecked
147
148
149
def return_radio_sw_checked(altsw, radioversion):
150
    """
151
    Check radio software existence, return boolean.
152
153
    :param altsw: Software release version.
154
    :type altsw: str
155
156
    :param radioversion: Radio version.
157
    :type radioversion: str
158
    """
159
    if altsw == "checkme":
160
        serv = bbconstants.SERVERS["p"]
161
        testos = utilities.increment(radioversion, -1)
162
        altsw = networkutils.sr_lookup(testos, serv)
163
        if altsw == "SR not in system":
164
            print("RADIO SOFTWARE RELEASE NOT FOUND")
165
            cont = utilities.s2b(input("INPUT MANUALLY? Y/N: "))
166
            if cont:
167
                altsw = input("SOFTWARE RELEASE: ")
168
                altchecked = False
169
            else:
170
                print("\nEXITING...")
171
                raise SystemExit  # bye bye
172
        else:
173
            altchecked = True
174
    else:
175
        altchecked = True
176
    return altsw, altchecked
177
178
179
def check_sw(baseurl, softwareversion, swchecked):
180
    """
181
    Check existence of software release.
182
183
    :param baseurl: Base URL (from http to hashed SW release).
184
    :type basurl: str
185
186
    :param softwareversion: Software release.
187
    :type softwareversion: str
188
189
    :param swchecked: If we checked the sw release already.
190
    :type swchecked: bool
191
    """
192
    print("CHECKING SOFTWARE RELEASE AVAILABILITY...")
193
    if not swchecked:
194
        avlty = networkutils.availability(baseurl)
195
        if avlty:
196
            print("SOFTWARE RELEASE {0} EXISTS".format(softwareversion))
197
        else:
198
            print("SOFTWARE RELEASE {0} NOT FOUND".format(softwareversion))
199
            cont = utilities.s2b(input("CONTINUE? Y/N: "))
200
            if not cont:
201
                print("\nEXITING...")
202
                raise SystemExit
203
    else:
204
        print("SOFTWARE RELEASE {0} EXISTS".format(softwareversion))
205
206
207
def check_radio_sw(alturl, altsw, altchecked):
208
    """
209
    Check existence of radio software release.
210
211
    :param alturl: Radio base URL (from http to hashed SW release).
212
    :type alturl: str
213
214
    :param altsw: Radio software release.
215
    :type altsw: str
216
217
    :param altchecked: If we checked the sw release already.
218
    :type altchecked: bool
219
    """
220
    print("CHECKING RADIO SOFTWARE RELEASE...")
221
    if not altchecked:
222
        altavlty = networkutils.availability(alturl)
223
        if altavlty:
224
            print("SOFTWARE RELEASE {0} EXISTS".format(altsw))
225
        else:
226
            print("SOFTWARE RELEASE {0} NOT FOUND".format(altsw))
227
            cont = utilities.s2b(input("CONTINUE? Y/N: "))
228
            if not cont:
229
                print("\nEXITING...")
230
                raise SystemExit
231
    else:
232
        print("SOFTWARE RELEASE {0} EXISTS".format(altsw))
233
234
235
def check_os_single(osurl, osversion, device):
236
    """
237
    Check existence of single OS link.
238
239
    :param radiourl: Radio URL to check.
240
    :type radiourl: str
241
242
    :param radioversion: Radio version.
243
    :type radioversion: str
244
245
    :param device: Device family.
246
    :type device: int
247
    """
248
    osav = networkutils.availability(osurl)
249
    if not osav:
250
        print("{0} NOT AVAILABLE FOR {1}".format(osversion, bbconstants.DEVICES[device]))
251
        cont = utilities.s2b(input("CONTINUE? Y/N: "))
252
        if not cont:
253
            print("\nEXITING...")
254
            raise SystemExit
255
256
257
def check_os_bulk(osurls):
258
    """
259
    Check existence of list of OS links.
260
261
    :param osurls: OS URLs to check.
262
    :type osurls: list(str)
263
    """
264
    for url in osurls:
265
        osav = networkutils.availability(url)
266
        if osav:
267
            break
268
    else:
269
        print("OS VERSION NOT FOUND")
270
        cont = utilities.s2b(input("CONTINUE? Y/N: "))
271
        if not cont:
272
            print("\nEXITING...")
273
            raise SystemExit
274
275
276
def check_radio_single(radiourl, radioversion):
277
    """
278
    Check existence of single radio link.
279
280
    :param radiourl: Radio URL to check.
281
    :type radiourl: str
282
283
    :param radioversion: Radio version.
284
    :type radioversion: str
285
    """
286
    radav = networkutils.availability(radiourl)
287
    if not radav:
288
        print("RADIO VERSION NOT FOUND")
289
        cont = utilities.s2b(input("INPUT MANUALLY? Y/N: "))
290
        if cont:
291
            rad2 = input("RADIO VERSION: ")
292
            radiourl = radiourl.replace(radioversion, rad2)
293
            radioversion = rad2
294
        else:
295
            going = utilities.s2b(input("KEEP GOING? Y/N: "))
296
            if not going:
297
                print("\nEXITING...")
298
                raise SystemExit
299
    return radiourl, radioversion
300
301
302
def check_radio_bulk(radiourls, radioversion):
303
    """
304
    Check existence of list of radio links.
305
306
    :param radiourls: Radio URLs to check.
307
    :type radiourls: list(str)
308
309
    :param radioversion: Radio version.
310
    :type radioversion: str
311
    """
312
    for url in radiourls:
313
        radav = networkutils.availability(url)
314
        if radav:
315
            break
316
    else:
317
        print("RADIO VERSION NOT FOUND")
318
        cont = utilities.s2b(input("INPUT MANUALLY? Y/N: "))
319
        if cont:
320
            rad2 = input("RADIO VERSION: ")
321
            radiourls = [url.replace(radioversion, rad2) for url in radiourls]
322
            radioversion = rad2
323
        else:
324
            going = utilities.s2b(input("KEEP GOING? Y/N: "))
325
            if not going:
326
                print("\nEXITING...")
327
                raise SystemExit
328
    return radiourls, radioversion
329
330
331
def get_baseurls(softwareversion, altsw=None):
332
    """
333
    Generate base URLs for bar links.
334
335
    :param softwareversion: Software version.
336
    :type softwareversion: str
337
338
    :param altsw: Radio software version, if necessary.
339
    :type altsw: str
340
    """
341
    baseurl = networkutils.create_base_url(softwareversion)
342
    alturl = networkutils.create_base_url(altsw) if altsw else None
343
    return baseurl, alturl
344
345
346
def get_sz_executable(compmethod):
347
    """
348
    Get 7z executable.
349
350
    :param compmethod: Compression method.
351
    :type compmethod: str
352
    """
353
    if compmethod != "7z":
354
        szexe = ""
355
    else:
356
        print("CHECKING PRESENCE OF 7ZIP...")
357
        psz = utilities.prep_seven_zip(True)
358
        if psz:
359
            print("7ZIP OK")
360
            szexe = utilities.get_seven_zip(False)
361
        else:
362
            szexe = ""
363
            print("7ZIP NOT FOUND")
364
            cont = utilities.s2b(input("CONTINUE? Y/N "))
365
            if cont:
366
                print("FALLING BACK TO ZIP...")
367
                compmethod = "zip"
368
            else:
369
                print("\nEXITING...")
370
                raise SystemExit  # bye bye
371
    return compmethod, szexe
372
373
374
def test_bar_files(localdir, urllist):
375
    """
376
    Test bar files after download.
377
378
    :param localdir: Directory.
379
    :type localdir: str
380
381
    :param urllist: List of URLs to check.
382
    :type urllist: list(str)
383
    """
384
    brokenlist = []
385
    print("TESTING BAR FILES...")
386
    for file in os.listdir(localdir):
387
        if file.endswith(".bar"):
388
            print("TESTING: {0}".format(file))
389
            thepath = os.path.abspath(os.path.join(localdir, file))
390
            brokens = barutils.bar_tester(thepath)
391
            if brokens is not None:
392
                os.remove(brokens)
393
                for url in urllist:
394
                    if brokens in url:
395
                        brokenlist.append(url)
396
    if brokenlist:
397
        print("SOME FILES ARE BROKEN!")
398
        lprint(brokenlist)
399
        raise SystemExit
400
    else:
401
        print("BAR FILES DOWNLOADED OK")
402
403
404
def test_signed_files(localdir):
405
    """
406
    Test signed files after extract.
407
408
    :param localdir: Directory.
409
    :type localdir: str
410
    """
411
    print("TESTING SIGNED FILES...")
412
    for file in os.listdir(localdir):
413
        if file.endswith(".bar"):
414
            print("TESTING: {0}".format(file))
415
            signname, signhash = barutils.retrieve_sha512(file)
416
            sha512ver = barutils.verify_sha512(signname, signhash)
417
            if not sha512ver:
418
                print("{0} IS BROKEN".format((file)))
419
                break
420
    else:
421
        print("ALL FILES EXTRACTED OK")
422
423
424
def test_loader_files(localdir):
425
    """
426
    Test loader files after creation.
427
428
    :param localdir: Directory.
429
    :type localdir: str
430
    """
431
    if not utilities.is_windows():
432
        pass
433
    else:
434
        print("TESTING LOADER FILES...")
435
        brokens = utilities.verify_bulk_loaders(localdir)
436
        if brokens:
437
            print("BROKEN FILES:")
438
            lprint(brokens)
439
            raise SystemExit
440
        else:
441
            print("ALL FILES CREATED OK")
442
443
444
def test_single_loader(loaderfile):
445
    """
446
    Test single loader file after creation.
447
448
    :param loaderfile: File to check.
449
    :type loaderfile: str
450
    """
451
    if not utilities.is_windows():
452
        pass
453
    else:
454
        print("TESTING LOADER...")
455
        if not utilities.verify_loader_integrity(loaderfile):
456
            print("{0} IS BROKEN!".format(os.path.basename(loaderfile)))
457
            raise SystemExit
458
        else:
459
            print("LOADER CREATED OK")
460
461
462
def enter_to_exit(checkfreeze=True):
463
    """
464
    Press enter to exit a script.
465
466
    :param checkfreeze: If this triggers only in frozen executables. Default is true.
467
    :type checkfreeze: bool
468
    """
469
    greenlight = bool(getattr(sys, 'frozen', False)) if checkfreeze else True
470
    if greenlight:
471
        print("")
472
        smeg = input("Press Enter to exit")
473
        if smeg or not smeg:
474
            raise SystemExit
475
476
477
def prod_avail(results, mailer=False, osversion=None, password=None):
478
    """
479
    Clean availability for production lookups for autolookup script.
480
481
    :param results: Result dict.
482
    :type results: dict(str: str)
483
484
    :param mailer: If we're mailing links. Default is false.
485
    :type mailer: bool
486
487
    :param osversion: OS version.
488
    :type osversion: str
489
490
    :param password: Email password.
491
    :type password: str
492
    """
493
    prel = results['p']
494
    if prel != "SR not in system" and prel is not None:
495
        pav = "PD"
496
        baseurl = networkutils.create_base_url(prel)
497
        avail = networkutils.availability(baseurl)
498
        is_avail = "Available" if avail else "Unavailable"
499
        if avail and mailer:
500
            sqlutils.prepare_sw_db()
501
            if not sqlutils.check_exists(osversion, prel):
502
                rad = utilities.increment(osversion, 1)
503
                linkgen(osversion, rad, prel, temp=True)
504
                smtputils.prep_email(osversion, prel, password)
505
    else:
506
        pav = "  "
507
        is_avail = "Unavailable"
508
    return prel, pav, is_avail
509
510
511
def linkgen(osversion, radioversion=None, softwareversion=None, altsw=None, temp=False):
512
    """
513
    Generate debrick/core/radio links for given OS, radio, software release.
514
515
    :param osversion: OS version, 10.x.y.zzzz.
516
    :type osversion: str
517
518
    :param radioversion: Radio version, 10.x.y.zzzz. Can be guessed.
519
    :type radioversion: str
520
521
    :param softwareversion: Software version, 10.x.y.zzzz. Can be guessed.
522
    :type softwareversion: str
523
524
    :param altsw: Radio software release, if not the same as OS.
525
    :type altsw: str
526
527
    :param temp: If file we write to is temporary.
528
    :type temp: bool
529
    """
530
    radioversion = return_radio_version(osversion, radioversion)
531
    softwareversion, swc = return_sw_checked(softwareversion, osversion)
532
    del swc
533
    if altsw is not None:
534
        altsw, aswc = return_radio_sw_checked(altsw, radioversion)
535
        del aswc
536
    baseurl = networkutils.create_base_url(softwareversion)
537
538
    # List of debrick urls
539
    oses, cores, radios = textgenerator.url_gen(osversion, radioversion, softwareversion)
540
    if altsw is not None:
541
        del radios
542
        dbks, cors, radios = textgenerator.url_gen(osversion, radioversion, altsw)
543
        del dbks
544
        del cors
545
546
    avlty = networkutils.availability(baseurl)
547
    textgenerator.write_links(softwareversion, osversion, radioversion, oses, cores, radios,
548
                              avlty, False, None, temp, altsw)
549
550
551
def clean_swrel(swrelset):
552
    """
553
    Clean a list of software release lookups.
554
555
    :param swrelset: List of software releases.
556
    :type swrelset: set(str)
557
    """
558
    for i in swrelset:
559
        if i != "SR not in system" and i is not None:
560
            swrelease = i
561
            break
562
    else:
563
        swrelease = ""
564
    return swrelease
565
566
567
def autolookup_printer(out, avail, log=False, quiet=False, record=None):
568
    """
569
    Print autolookup results, logging if specified.
570
571
    :param out: Output block.
572
    :type out: str
573
574
    :param avail: Availability. Can be "Available" or "Unavailable".
575
    :type avail: str
576
577
    :param log: If we're logging to file.
578
    :type log: bool
579
580
    :param quiet: If we only note available entries.
581
    :type quiet: bool
582
583
    :param record: If we're logging, the file to log to.
584
    :type record: str
585
    """
586
    if not quiet:
587
        avail = "Available"  # force things
588
    if avail == "Available":
589
        if log:
590
            with open(record, "a") as rec:
591
                rec.write("{0}\n".format(out))
592
        print(out)
593
594
595
def autolookup_output(osversion, swrelease, avail, avpack, sql=False):
596
    """
597
    Prepare autolookup block, and add to SQL database.
598
599
    :param osversion: OS version.
600
    :type osversion: str
601
602
    :param swrelease: Software release.
603
    :type swrelease: str
604
605
    :param avail: "Unavailable" or "Available".
606
    :type avail: str
607
608
    :param avpack: Availabilities: alpha 1 and 2, beta 1 and 2, production.
609
    :type avpack: list(str)
610
611
    :param sql: If we're adding this to our SQL database.
612
    :type sql: bool
613
    """
614
    if sql:
615
        sqlutils.prepare_sw_db()
616
        if not sqlutils.check_exists(osversion, swrelease):
617
            sqlutils.insert(osversion, swrelease, avail.lower())
618
    avblok = "[{0}|{1}|{2}|{3}|{4}]".format(*avpack)
1 ignored issue
show
Coding Style introduced by
Usage of * or ** arguments should usually be done with care.

Generally, there is nothing wrong with usage of * or ** arguments. For readability of the code base, we suggest to not over-use these language constructs though.

For more information, we can recommend this blog post from Ned Batchelder including its comments which also touches this aspect.

Loading history...
619
    out = "OS {0} - SR {1} - {2} - {3}".format(osversion, swrelease, avblok, avail)
620
    return out
621
622
623
def export_cchecker(files, npc, hwid, osv, radv, swv, upgrade=False, forced=None):
624
    """
625
    Write carrierchecker lookup links to file.
626
627
    :param files: List of file URLs.
628
    :type files: list(str)
629
630
    :param npc: MCC + MNC (ex. 302220).
631
    :type npc: int
632
633
    :param hwid: Device hardware ID.
634
    :type hwid: str
635
636
    :param osv: OS version.
637
    :type osv: str
638
639
    :param radv: Radio version.
640
    :type radv: str
641
642
    :param swv: Software release.
643
    :type swv: str
644
645
    :param upgrade: Whether or not to use upgrade files. Default is false.
646
    :type upgrade: bool
647
648
    :param forced: Force a software release. None to go for latest.
649
    :type forced: str
650
    """
651
    if files:
652
        if not upgrade:
653
            newfiles = networkutils.carrier_query(npc, hwid, True, False, forced)
654
            cleanfiles = newfiles[3]
655
        else:
656
            cleanfiles = files
657
        osurls, coreurls, radiourls = textgenerator.url_gen(osv, radv, swv)
658
        stoppers = ["8960", "8930", "8974", "m5730", "winchester"]
659
        finals = [link for link in cleanfiles if all(word not in link for word in stoppers)]
660
        textgenerator.write_links(swv, osv, radv, osurls, coreurls, radiourls, True, True, finals)
661
        print("\nFINISHED!!!")
662
    else:
663
        print("CANNOT EXPORT, NO SOFTWARE RELEASE")
664
665
666
def generate_blitz_links(files, osv, radv, swv):
667
    """
668
    Generate blitz URLs (i.e. all OS and radio links).
669
    :param files: List of file URLs.
670
    :type files: list(str)
671
672
    :param osv: OS version.
673
    :type osv: str
674
675
    :param radv: Radio version.
676
    :type radv: str
677
678
    :param swv: Software release.
679
    :type swv: str
680
    """
681
    baseurl = networkutils.create_base_url(swv)
682
    suffix = "nto+armle-v7+signed.bar"
683
    coreurls = [
684
        "{0}/winchester.factory_sfi-{1}-{2}".format(baseurl, osv, suffix),
685
        "{0}/qc8960.factory_sfi-{1}-{2}".format(baseurl, osv, suffix),
686
        "{0}/qc8960.factory_sfi_hybrid_qc8x30-{1}-{2}".format(baseurl, osv, suffix),
687
        "{0}/qc8974.factory_sfi_hybrid_qc8974-{1}-{2}".format(baseurl, osv, suffix)
688
    ]
689
    radiourls = [
690
        "{0}/m5730-{1}-{2}".format(baseurl, radv, suffix),
691
        "{0}/qc8960-{1}-{2}".format(baseurl, radv, suffix),
692
        "{0}/qc8960.wtr-{1}-{2}".format(baseurl, radv, suffix),
693
        "{0}/qc8960.wtr5-{1}-{2}".format(baseurl, radv, suffix),
694
        "{0}/qc8930.wtr5-{1}-{2}".format(baseurl, radv, suffix),
695
        "{0}/qc8974.wtr2-{1}-{2}".format(baseurl, radv, suffix)
696
    ]
697
    return files + coreurls + radiourls
698
699
700
def package_blitz(bardir, swv):
701
    """
702
    Package and verify a blitz package.
703
704
    :param bardir: Path to folder containing bar files.
705
    :type bardir: str
706
707
    :param swv: Software version.
708
    :type swv: str
709
    """
710
    print("\nCREATING BLITZ...")
711
    barutils.create_blitz(bardir, swv)
712
    print("\nTESTING BLITZ...")
713
    zipver = barutils.zip_verify("Blitz-{0}.zip".format(swv))
0 ignored issues
show
Bug introduced by
The Module bbarchivist.barutils does not seem to have a member named zip_verify.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
714
    if not zipver:
715
        print("BLITZ FILE IS BROKEN")
716
        raise SystemExit
717
    else:
718
        shutil.rmtree(bardir)
719
720
721
def purge_dross(files):
722
    """
723
    Get rid of Nuance/retaildemo apps in a list of apps.
724
725
    :param files: List of URLs.
726
    :type files: list(str)
727
    """
728
    crap = [
729
        "sin_ji",
730
        "common",
731
        "xander",
732
        "kate",
733
        "ava",
734
        "amelie",
735
        "thomas",
736
        "anna",
737
        "alice",
738
        "kyoko",
739
        "sora",
740
        "li_li",
741
        "mei_jia",
742
        "nora",
743
        "zosia",
744
        "luciana",
745
        "joana",
746
        "milena",
747
        "marisol",
748
        "angelica",
749
        "arw",
750
        "bgb",
751
        "cah",
752
        "czc",
753
        "dad",
754
        "dun",
755
        "ena",
756
        "eni",
757
        "fif",
758
        "frc",
759
        "frf",
760
        "ged",
761
        "grg",
762
        "iti",
763
        "jpj",
764
        "kok",
765
        "mnc",
766
        "mnt",
767
        "non",
768
        "plp",
769
        "ptb",
770
        "ptp",
771
        "rur",
772
        "spe",
773
        "spm",
774
        "sws",
775
        "trt",
776
        "retaildemo"]
777
    files2 = [file for file in files if all(word not in file for word in crap)]
778
    return files2
779
780
781
def slim_preamble(appname):
782
    """
783
    Standard app name header.
784
785
    :param appname: Name of app.
786
    :type appname: str
787
    """
788
    print("~~~{0} VERSION {1}~~~".format(appname.upper(), shortversion()))
789
790
791
def lprint(iterable):
792
    """
793
    A oneliner for 'for item in x: print item'.
794
795
    :param iterable: Iterable to print.
796
    :type iterable: list/tuple
797
    """
798
    for item in iterable:
799
        print(item)
800
801
802
def standard_preamble(appname, osversion, softwareversion, radioversion, altsw=None):
803
    """
804
    Standard app name, OS, radio and software (plus optional radio software) print block.
805
806
    :param appname: Name of app.
807
    :type appname: str
808
809
    :param osversion: OS version, 10.x.y.zzzz. Required.
810
    :type osversion: str
811
812
    :param radioversion: Radio version, 10.x.y.zzzz. Can be guessed.
813
    :type radioversion: str
814
815
    :param softwareversion: Software release, 10.x.y.zzzz. Can be guessed.
816
    :type softwareversion: str
817
818
    :param altsw: Radio software release, if not the same as OS.
819
    :type altsw: str
820
    """
821
    slim_preamble(appname)
822
    print("OS VERSION: {0}".format(osversion))
823
    print("OS SOFTWARE VERSION: {0}".format(softwareversion))
824
    print("RADIO VERSION: {0}".format(radioversion))
825
    if altsw is not None:
826
        print("RADIO SOFTWARE VERSION: {0}".format(altsw))
827
828
829
def verify_gpg_credentials():
830
    """
831
    Read GPG key/pass from file, verify if incomplete.
832
    """
833
    gpgkey, gpgpass = hashutils.gpg_config_loader()
834
    if gpgkey is None or gpgpass is None:
835
        print("NO PGP KEY/PASS FOUND")
836
        cont = utilities.s2b(input("CONTINUE (Y/N)?: "))
837
        if cont:
838
            if gpgkey is None:
839
                gpgkey = input("PGP KEY (0x12345678): ")
840
                if not gpgkey.startswith("0x"):
841
                    gpgkey = "0x{0}".format(gpgkey)   # add preceding 0x
842
            if gpgpass is None:
843
                gpgpass = getpass.getpass(prompt="PGP PASSPHRASE: ")
844
                writebool = utilities.s2b(input("SAVE PASSPHRASE (Y/N)?:"))
845
            else:
846
                writebool = False
847
            gpgpass2 = gpgpass if writebool else None
848
            hashutils.gpg_config_writer(gpgkey, gpgpass2)
849
        else:
850
            gpgkey = None
851
    return gpgkey, gpgpass
852
853
854
def bulk_hash(dirs, compressed=True, deleted=True, radios=True, hashdict=None):
855
    """
856
    Hash files in several folders based on flags.
857
858
    :param dirs: Folders: [OS_bars, radio_bars, OS_exes, radio_exes, OS_zips, radio_zips]
859
    :type dirs: list(str)
860
861
    :param compressed: Whether to hash compressed files. True by default.
862
    :type compressed: bool
863
864
    :param deleted: Whether to delete uncompressed files. True by default.
865
    :type deleted: bool
866
867
    :param radios: Whether to hash radio autoloaders. True by default.
868
    :type radios: bool
869
870
    :param hashdict: Dictionary of hash rules, in ~\bbarchivist.ini.
871
    :type hashdict: dict({str: bool})
872
    """
873
    print("HASHING LOADERS...")
874
    if compressed:
875
        hashutils.verifier(dirs[4], hashdict)
876
        if radios:
877
            hashutils.verifier(dirs[5], hashdict)
878
    if not deleted:
879
        hashutils.verifier(dirs[2], hashdict)
880
        if radios:
881
            hashutils.verifier(dirs[3], hashdict)
882
883
884
def bulk_verify(dirs, compressed=True, deleted=True, radios=True):
885
    """
886
    Verify files in several folders based on flags.
887
888
    :param dirs: Folders: [OS_bars, radio_bars, OS_exes, radio_exes, OS_zips, radio_zips]
889
    :type dirs: list(str)
890
891
    :param compressed: Whether to hash compressed files. True by default.
892
    :type compressed: bool
893
894
    :param deleted: Whether to delete uncompressed files. True by default.
895
    :type deleted: bool
896
897
    :param radios: Whether to hash radio autoloaders. True by default.
898
    :type radios: bool
899
    """
900
    gpgkey, gpgpass = verify_gpg_credentials()
901
    if gpgpass is not None and gpgkey is not None:
902
        print("VERIFYING LOADERS...")
903
        print("KEY: {0}".format(gpgkey))
904
        if compressed:
905
            hashutils.gpgrunner(dirs[4], gpgkey, gpgpass, True)
906
            if radios:
907
                hashutils.gpgrunner(dirs[5], gpgkey, gpgpass, True)
908
        if not deleted:
909
            hashutils.gpgrunner(dirs[2], gpgkey, gpgpass, True)
910
            if radios:
911
                hashutils.gpgrunner(dirs[3], gpgkey, gpgpass, True)
912