Completed
Push — master ( 12684e...031bf5 )
by John
02:38
created

archivist_download()   B

Complexity

Conditions 6

Size

Total Lines 31

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
dl 0
loc 31
rs 7.5384
c 0
b 0
f 0
1
#!/usr/bin/env python3
2
"""Download bar files, create autoloaders."""
3
4
import os  # filesystem read
5
import sys  # load arguments
6
import requests  # session
7
from bbarchivist import scriptutils  # script stuff
8
from bbarchivist import utilities  # input validation
9
from bbarchivist import decorators  # timer
10
from bbarchivist import barutils  # file/folder work
11
from bbarchivist import archiveutils  # archive work
12
from bbarchivist import networkutils  # download/lookup
13
from bbarchivist import loadergen  # cap, in Python
14
from bbarchivist import hashutils  # hashes, GPG
15
16
__author__ = "Thurask"
17
__license__ = "WTFPL v2"
18
__copyright__ = "Copyright 2015-2016 Thurask"
19
20
21
@decorators.timer
22
def grab_args():
23
    """
24
    Parse arguments from argparse/questionnaire.
25
26
    Invoke :func:`archivist.archivist_main` with those arguments.
27
    """
28
    if len(sys.argv) > 1:
29
        parser = scriptutils.default_parser("bb-archivist", "Create many autoloaders",
30
                                            ("folder", "osr"))
31
        negategroup = parser.add_argument_group(
32
            "negators",
33
            "Disable program functionality")
34
        negategroup.add_argument(
35
            "-no",
36
            "--no-download",
37
            dest="download",
38
            help="Don't download files",
39
            action="store_false",
40
            default=True)
41
        negategroup.add_argument(
42
            "-ni",
43
            "--no-integrity",
44
            dest="integrity",
45
            help="Don't test bar files after download",
46
            action="store_false",
47
            default=True)
48
        negategroup.add_argument(
49
            "-nx",
50
            "--no-extract",
51
            dest="extract",
52
            help="Don't extract bar files",
53
            action="store_false",
54
            default=True)
55
        negategroup.add_argument(
56
            "-nr",
57
            "--no-radios",
58
            dest="radloaders",
59
            help="Don't make radio autoloaders",
60
            action="store_false",
61
            default=True)
62
        negategroup.add_argument(
63
            "-ns",
64
            "--no-rmsigned",
65
            dest="signed",
66
            help="Don't remove signed files",
67
            action="store_false",
68
            default=True)
69
        negategroup.add_argument(
70
            "-nc",
71
            "--no-compress",
72
            dest="compress",
73
            help="Don't compress loaders",
74
            action="store_false",
75
            default=True)
76
        negategroup.add_argument(
77
            "-nd",
78
            "--no-delete",
79
            dest="delete",
80
            help="Don't delete uncompressed loaders",
81
            action="store_false",
82
            default=True)
83
        negategroup.add_argument(
84
            "-nv",
85
            "--no-verify",
86
            dest="verify",
87
            help="Don't verify created loaders",
88
            action="store_false",
89
            default=True)
90
        if not getattr(sys, 'frozen', False):
91
            parser.add_argument(
92
                "-g",
93
                "--gpg",
94
                dest="gpg",
95
                help="Enable GPG signing. Set up GnuPG.",
96
                action="store_true",
97
                default=False)
98
        parser.add_argument(
99
            "-r",
100
            "--radiosw",
101
            dest="altsw",
102
            metavar="SW",
103
            help="Radio software version; use without software to guess",
104
            nargs="?",
105
            const="checkme",
106
            default=None)
107
        if not getattr(sys, 'frozen', False):
108
            parser.add_argument(
109
                "-m",
110
                "--method",
111
                dest="method",
112
                metavar="METHOD",
113
                help="Compression method",
114
                nargs="?",
115
                type=utilities.valid_method,
116
                default=None)
117
        parser.add_argument(
118
            "-c",
119
            "--core",
120
            dest="core",
121
            help="Make core/radio loaders",
122
            default=False,
123
            action="store_true")
124
        parser.add_argument(
125
            "-o",
126
            "--old-style",
127
            dest="oldstyle",
128
            help="Make old-style checksum files",
129
            default=False,
130
            action="store_true")
131
        parser.set_defaults(compmethod="7z")
132
        args = parser.parse_args(sys.argv[1:])
133
        if args.folder is None:
134
            args.folder = os.getcwd()
135
        elif args.folder is not None and not os.path.exists(args.folder):
136
            os.makedirs(args.folder)
137
        if getattr(sys, 'frozen', False):
138
            args.gpg = False
139
            hashdict = hashutils.verifier_config_loader(os.getcwd())
140
            args.method = "7z"
141
        else:
142
            hashdict = hashutils.verifier_config_loader()
143
        hashutils.verifier_config_writer(hashdict)
144
        if args.method is None:
145
            compmethod = archiveutils.compress_config_loader()
146
            archiveutils.compress_config_writer(compmethod)
147
        else:
148
            compmethod = args.method
149
        archivist_main(args.os, args.radio, args.swrelease,
150
                       os.path.abspath(args.folder), args.radloaders,
151
                       args.compress, args.delete, args.verify,
152
                       hashdict, args.download,
153
                       args.extract, args.signed, compmethod, args.gpg,
154
                       args.integrity, args.altsw, args.core, args.oldstyle)
155
    else:
156
        questionnaire()
157
158
159
def questionnaire():
160
    """
161
    Questions to ask if no arguments given.
162
    """
163
    localdir = os.getcwd()
164
    osversion = input("OS VERSION (REQUIRED): ")
165
    radioversion = input("RADIO VERSION (PRESS ENTER TO GUESS): ")
166
    radioversion = None if not radioversion else radioversion
167
    softwareversion = input("OS SOFTWARE RELEASE (PRESS ENTER TO GUESS): ")
168
    softwareversion = None if not softwareversion else softwareversion
169
    altcheck = utilities.s2b(input("USING ALTERNATE RADIO (Y/N)?: "))
170
    if altcheck:
171
        altsw = input("RADIO SOFTWARE RELEASE (PRESS ENTER TO GUESS): ")
172
        if not altsw:
173
            altsw = "checkme"
174
    else:
175
        altsw = None
176
    radios = utilities.s2b(input("CREATE RADIO LOADERS (Y/N)?: "))
177
    compressed = utilities.s2b(input("COMPRESS LOADERS (Y/N)?: "))
178
    deleted = utilities.s2b(input("DELETE UNCOMPRESSED LOADERS (Y/N)?: ")) if compressed else False
179
    hashed = utilities.s2b(input("GENERATE HASHES (Y/N)?: "))
180
    if getattr(sys, 'frozen', False):
181
        hashdict = hashutils.verifier_config_loader(os.getcwd())
182
        compmethod = "7z"
183
    else:
184
        hashdict = hashutils.verifier_config_loader()
185
        hashutils.verifier_config_writer(hashdict)
186
        compmethod = archiveutils.compress_config_loader()
187
    print(" ")
188
    archivist_main(osversion, radioversion, softwareversion,
189
                   localdir, radios, compressed, deleted, hashed,
190
                   hashdict, download=True, extract=True, signed=True,
191
                   compmethod=compmethod, gpg=False, integrity=True,
192
                   altsw=None, core=False, oldstyle=False)
193
194
195
def archivist_checksw(baseurl, softwareversion, swchecked):
196
    """
197
    Check availability of software releases.
198
199
    :param baseurl: Base URL for download links.
200
    :type baseurl: str
201
202
    :param softwareversion: Software release, 10.x.y.zzzz. Can be guessed.
203
    :type softwareversion: str
204
205
    :param swchecked: If we checked the sw release already.
206
    :type swchecked: bool
207
    """
208
    scriptutils.check_sw(baseurl, softwareversion, swchecked)
209
210
211
def archivist_download(download, osurls, radiourls, localdir, session, dirs):
212
    """
213
    Download function.
214
215
    :param download: Whether to download bar files. True by default.
216
    :type download: bool
217
218
    :param osurls: OS file list.
219
    :type osurls: list(str)
220
221
    :param radiourls: Radio file list.
222
    :type radiourls: list(str)
223
224
    :param localdir: Working directory. Local by default.
225
    :type localdir: str
226
227
    :param session: Requests session object, default is created on the fly.
228
    :type session: requests.Session()
229
230
    :param dirs: List of generated bar/loader/zip directories.
231
    :type dirs: list(str)
232
    """
233
    osfiles = [os.path.join(localdir, dirs[0], os.path.basename(x)) for x in osurls]
234
    radiofiles = [os.path.join(localdir, dirs[1], os.path.basename(x)) for x in radiourls]
235
    if download:
236
        print("BEGIN DOWNLOADING...")
237
        networkutils.download_bootstrap(radiourls + osurls, localdir, 3, session)
238
        print("ALL FILES DOWNLOADED")
239
    elif all(os.path.exists(x) for x in osfiles+radiofiles):
240
        print("USING CACHED OS/RADIO FILES...")
241
        barutils.replace_bars_bulk(os.path.abspath(localdir), osfiles+radiofiles)
242
243
244
def archivist_integritybars(integrity, osurls, radiourls, localdir):
245
    """
246
    Check integrity of bar files, redownload if necessary.
247
248
    :param integrity: Whether to test downloaded files. True by default.
249
    :type integrity: bool
250
251
    :param osurls: OS file list.
252
    :type osurls: list(str)
253
254
    :param radiourls: Radio file list.
255
    :type radiourls: list(str)
256
    """
257
    if integrity:
258
        urllist = osurls + radiourls
259
        scriptutils.test_bar_files(localdir, urllist)
260
261
262
def archivist_extractbars(extract, localdir):
263
    """
264
    Extract signed files from bar files.
265
266
    :param extract: Whether to extract bar files. True by default.
267
    :type extract: bool
268
269
    :param localdir: Working directory. Local by default.
270
    :type localdir: str
271
    """
272
    if extract:
273
        print("EXTRACTING...")
274
        barutils.extract_bars(localdir)
275
276
277
def archivist_integritysigned(integrity, localdir):
278
    """
279
    Check integrity of signed files.
280
281
    :param integrity: Whether to test downloaded files. True by default.
282
    :type integrity: bool
283
284
    :param localdir: Working directory. Local by default.
285
    :type localdir: str
286
    """
287
    if integrity:
288
        scriptutils.test_signed_files(localdir)
289
290
291
def archivist_movebars(dirs, localdir):
292
    """
293
    Move bar files.
294
295
    :param dirs: List of OS/radio bar/loader/zipped folders.
296
    :type dirs: list(str)
297
298
    :param localdir: Working directory. Local by default.
299
    :type localdir: str
300
    """
301
    print("MOVING BAR FILES...")
302
    barutils.move_bars(localdir, dirs[0], dirs[1])
303
304
305
def archivist_generateloaders(osversion, radioversion, radios, localdir, altsw, core):
306
    """
307
    Generate loaders.
308
309
    :param osversion: OS version, 10.x.y.zzzz. Required.
310
    :type osversion: str
311
312
    :param radioversion: Radio version, 10.x.y.zzzz. Can be guessed.
313
    :type radioversion: str
314
315
    :param radios: Whether to create radio autoloaders. True by default.
316
    :type radios: bool
317
318
    :param localdir: Working directory. Local by default.
319
    :type localdir: str
320
321
    :param altsw: Radio software release, if not the same as OS.
322
    :type altsw: str
323
324
    :param core: Whether to create a core/radio loader. Default is false.
325
    :type core: bool
326
    """
327
    print("GENERATING LOADERS...")
328
    altradio = altsw is not None
329
    loadergen.generate_loaders(osversion, radioversion, radios, localdir, altradio, core)
330
331
332
def archivist_integrityloaders(integrity, localdir):
333
    """
334
    Check integrity of build loaders.
335
336
    :param integrity: Whether to test downloaded files. True by default.
337
    :type integrity: bool
338
339
    :param localdir: Working directory. Local by default.
340
    :type localdir: str
341
    """
342
    if integrity:
343
        scriptutils.test_loader_files(localdir)
344
345
346
def archivist_removesigned(signed, localdir):
347
    """
348
    Remove signed files.
349
350
    :param signed: Whether to delete signed files. True by default.
351
    :type signed: bool
352
353
    :param localdir: Working directory. Local by default.
354
    :type localdir: str
355
    """
356
    if signed:
357
        print("REMOVING SIGNED FILES...")
358
        barutils.remove_signed_files(localdir)
359
360
361
def archivist_compressor(compressed, integrity, localdir, compmethod, szexe):
362
    """
363
    Compress and optionally verify loaders.
364
365
    :param compressed: Whether to compress files. True by default.
366
    :type compressed: bool
367
368
    :param integrity: Whether to test downloaded files. True by default.
369
    :type integrity: bool
370
371
    :param localdir: Working directory. Local by default.
372
    :type localdir: str
373
374
    :param compmethod: Compression method. Default is "7z", fallback "zip".
375
    :type compmethod: str
376
377
    :param szexe: Path to 7z executable.
378
    :type szexe: str
379
    """
380
    if compressed:
381
        print("COMPRESSING...")
382
        archiveutils.compress(localdir, compmethod, szexe, True)
383
        if integrity:
384
            print("TESTING ARCHIVES...")
385
            archiveutils.verify(localdir, compmethod, szexe, True)
386
387
388
def archivist_moveloaders(dirs, localdir):
389
    """
390
    Move loaders.
391
392
    :param dirs: List of OS/radio bar/loader/zipped folders.
393
    :type dirs: list(str)
394
395
    :param localdir: Working directory. Local by default.
396
    :type localdir: str
397
    """
398
    print("MOVING LOADERS...")
399
    barutils.move_loaders(localdir, dirs[2], dirs[3], dirs[4], dirs[5])
400
401
402
def archivist_gethashes(dirs, hashed, compressed, deleted, radios, osversion, radioversion, softwareversion, oldstyle):
403
    """
404
    Make new-style info files.
405
406
    :param dirs: List of OS/radio bar/loader/zipped folders.
407
    :type dirs: list(str)
408
409
    :param hashed: Whether to hash files. True by default.
410
    :type hashed: bool
411
412
    :param compressed: Whether to compress files. True by default.
413
    :type compressed: bool
414
415
    :param deleted: Whether to delete uncompressed files. True by default.
416
    :type deleted: bool
417
418
    :param radios: Whether to create radio autoloaders. True by default.
419
    :type radios: bool
420
421
    :param osversion: OS version, 10.x.y.zzzz. Required.
422
    :type osversion: str
423
424
    :param radioversion: Radio version, 10.x.y.zzzz. Can be guessed.
425
    :type radioversion: str
426
427
    :param softwareversion: Software release, 10.x.y.zzzz. Can be guessed.
428
    :type softwareversion: str
429
430
    :param oldstyle: Whether to make old-style checksum files. Default is false.
431
    :type oldstyle: bool
432
    """
433
    if hashed and not oldstyle:
434
        scriptutils.bulk_info(dirs, osversion, compressed, deleted, radios,
435
                                  radioversion, softwareversion)
436
437
def archivist_getoldhashes(dirs, hashed, compressed, deleted, radios, hashdict, oldstyle):
438
    """
439
    Make old-style checksum files.
440
441
    :param dirs: List of OS/radio bar/loader/zipped folders.
442
    :type dirs: list(str)
443
444
    :param hashed: Whether to hash files. True by default.
445
    :type hashed: bool
446
447
    :param compressed: Whether to compress files. True by default.
448
    :type compressed: bool
449
450
    :param deleted: Whether to delete uncompressed files. True by default.
451
    :type deleted: bool
452
453
    :param radios: Whether to create radio autoloaders. True by default.
454
    :type radios: bool
455
456
    :param hashdict: Dictionary of hash rules, in ~\bbarchivist.ini.
457
    :type hashdict: dict({str: bool})
458
459
    :param oldstyle: Whether to make old-style checksum files. Default is false.
460
    :type oldstyle: bool
461
    """
462
    if hashed and oldstyle:
463
        scriptutils.bulk_hash(dirs, compressed, deleted, radios, hashdict)
464
465
466
def archivist_gpg(gpg, dirs, compressed, deleted, radios):
467
    """
468
    GPG-sign everything.
469
470
    :param gpg: Whether to use GnuPG verification. False by default.
471
    :type gpg: bool
472
473
    :param dirs: List of OS/radio bar/loader/zipped folders.
474
    :type dirs: list(str)
475
476
    :param compressed: Whether to compress files. True by default.
477
    :type compressed: bool
478
479
    :param deleted: Whether to delete uncompressed files. True by default.
480
    :type deleted: bool
481
482
    :param radios: Whether to create radio autoloaders. True by default.
483
    :type radios: bool
484
    """
485
    if gpg:
486
        scriptutils.bulk_verify(dirs, compressed, deleted, radios)
487
488
489
def archivist_deleteuncompressed(dirs, deleted, radios):
490
    """
491
    Delete uncompressed loaders.
492
493
    :param dirs: List of OS/radio bar/loader/zipped folders.
494
    :type dirs: list(str)
495
496
    :param deleted: Whether to delete uncompressed files. True by default.
497
    :type deleted: bool
498
499
    :param radios: Whether to create radio autoloaders. True by default.
500
    :type radios: bool
501
    """
502
    if deleted:
503
        print("DELETING UNCOMPRESSED LOADERS...")
504
        barutils.remove_unpacked_loaders(dirs[2], dirs[3], radios)
505
506
507
def archivist_removeemptyfolders(localdir):
508
    """
509
    Delete empty folders.
510
511
    :param localdir: Working directory. Local by default.
512
    :type localdir: str
513
    """
514
    print("REMOVING EMPTY FOLDERS...")
515
    barutils.remove_empty_folders(localdir)
516
517
518
def archivist_main(osversion, radioversion=None, softwareversion=None,
519
                   localdir=None, radios=True, compressed=True, deleted=True,
520
                   hashed=True, hashdict=None, download=True,
521
                   extract=True, signed=True, compmethod="7z",
522
                   gpg=False, integrity=True, altsw=None,
523
                   core=False, oldstyle=False):
524
    """
525
    Wrap around multi-autoloader creation code.
526
    Some combination of creating, downloading, hashing,
527
    compressing and moving autoloaders.
528
529
    :param osversion: OS version, 10.x.y.zzzz. Required.
530
    :type osversion: str
531
532
    :param radioversion: Radio version, 10.x.y.zzzz. Can be guessed.
533
    :type radioversion: str
534
535
    :param softwareversion: Software release, 10.x.y.zzzz. Can be guessed.
536
    :type softwareversion: str
537
538
    :param localdir: Working directory. Local by default.
539
    :type localdir: str
540
541
    :param radios: Whether to create radio autoloaders. True by default.
542
    :type radios: bool
543
544
    :param compressed: Whether to compress files. True by default.
545
    :type compressed: bool
546
547
    :param deleted: Whether to delete uncompressed files. True by default.
548
    :type deleted: bool
549
550
    :param hashed: Whether to hash files. True by default.
551
    :type hashed: bool
552
553
    :param hashdict: Dictionary of hash rules, in ~\bbarchivist.ini.
554
    :type hashdict: dict({str: bool})
555
556
    :param download: Whether to download bar files. True by default.
557
    :type download: bool
558
559
    :param extract: Whether to extract bar files. True by default.
560
    :type extract: bool
561
562
    :param signed: Whether to delete signed files. True by default.
563
    :type signed: bool
564
565
    :param compmethod: Compression method. Default is "7z", fallback "zip".
566
    :type compmethod: str
567
568
    :param gpg: Whether to use GnuPG verification. False by default.
569
    :type gpg: bool
570
571
    :param integrity: Whether to test downloaded files. True by default.
572
    :type integrity: bool
573
574
    :param altsw: Radio software release, if not the same as OS.
575
    :type altsw: str
576
577
    :param core: Whether to create a core/radio loader. Default is false.
578
    :type core: bool
579
580
    :param oldstyle: Whether to make old-style checksum files. Default is false.
581
    :type oldstyle: bool
582
    """
583
    radioversion = scriptutils.return_radio_version(osversion, radioversion)
584
    softwareversion, swchecked = scriptutils.return_sw_checked(softwareversion, osversion)
585
    if altsw == "checkme":
586
        altsw, altchecked = scriptutils.return_radio_sw_checked(altsw, radioversion)
587
    if localdir is None:
588
        localdir = os.getcwd()
589
    if hashed and hashdict is None:
590
        hashdict = hashutils.verifier_config_loader()
591
        hashutils.verifier_config_writer(hashdict)
592
    scriptutils.standard_preamble("archivist", osversion, softwareversion, radioversion, altsw)
593
    # Generate download URLs
594
    baseurl, alturl = scriptutils.get_baseurls(softwareversion, altsw)
595
    osurls, radiourls, cores = utilities.generate_urls(softwareversion, osversion, radioversion, True)
596
    osurls = cores if core else osurls
597
    for idx, url in enumerate(osurls):
598
        if "qc8960.factory_sfi" in url:
599
            vzwurl = url
600
            vzwindex = idx
601
            break
602
    if not networkutils.availability(vzwurl):
603
        osurls[vzwindex] = osurls[vzwindex].replace("qc8960.factory_sfi", "qc8960.verizon_sfi")
604
    osurls = list(set(osurls))  # pop duplicates
605
    if altsw:
606
        radiourls2 = [x.replace(baseurl, alturl) for x in radiourls]
607
        radiourls = radiourls2
608
        del radiourls2
609
    archivist_checksw(baseurl, softwareversion, swchecked)
610
    if altsw:
611
        scriptutils.check_radio_sw(alturl, altsw, altchecked)
612
    # Check availability of OS, radio
613
    scriptutils.check_os_bulk(osurls)
614
    radiourls, radioversion = scriptutils.check_radio_bulk(radiourls, radioversion)
615
    # Get 7z executable
616
    compmethod, szexe = scriptutils.get_sz_executable(compmethod)
617
    # Make dirs: bd_o, bd_r, ld_o, ld_r, zd_o, zd_r
618
    dirs = barutils.make_dirs(localdir, osversion, radioversion)
619
    osurls = scriptutils.bulk_avail(osurls)
620
    radiourls = scriptutils.bulk_avail(radiourls)
621
    sess = requests.Session()
622
    archivist_download(download, osurls, radiourls, localdir, sess, dirs)
623
    archivist_integritybars(integrity, osurls, radiourls, localdir)
624
    archivist_extractbars(extract, localdir)
625
    archivist_integritysigned(extract, localdir)
626
    archivist_movebars(dirs, localdir)
627
    archivist_generateloaders(osversion, radioversion, radios, localdir, altsw, core)
628
    archivist_integrityloaders(integrity, localdir)
629
    archivist_removesigned(signed, localdir)
630
    archivist_compressor(compressed, integrity, localdir, compmethod, szexe)
631
    archivist_moveloaders(dirs, localdir)
632
    archivist_gethashes(dirs, hashed, compressed, deleted, radios, osversion, radioversion, softwareversion, oldstyle)
633
    archivist_getoldhashes(dirs, hashed, compressed, deleted, radios, hashdict, oldstyle)
634
    archivist_gpg(gpg, dirs, compressed, deleted, radios)
635
    archivist_deleteuncompressed(dirs, deleted, radios)
636
    archivist_removeemptyfolders(localdir)
637
    print("\nFINISHED!")
638
639
640
if __name__ == "__main__":
641
    grab_args()
642
    decorators.enter_to_exit(False)
643