bbarchivist.scripts.carrierchecker   A
last analyzed

Complexity

Total Complexity 40

Size/Duplication

Total Lines 498
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 222
dl 0
loc 498
rs 9.2
c 0
b 0
f 0
wmc 40

15 Functions

Rating   Name   Duplication   Size   Complexity  
A carrierchecker_nobundles() 0 46 1
A carrierchecker_selective() 0 14 2
A forced_args() 0 14 3
A carrierchecker_main() 0 50 2
A carrierchecker_jsonprepare() 0 17 1
A carrierchecker_argfilter() 0 24 3
A carrierchecker_export() 0 38 2
A questionnaire_3digit() 0 12 5
A forced_avail() 0 10 2
A execute_args() 0 18 3
A carrierchecker_bundles() 0 14 1
A questionnaire() 0 21 5
A carrierchecker_download_prep() 0 32 4
A carrierchecker_download() 0 39 3
B grab_args() 0 95 3

How to fix   Complexity   

Complexity

Complex classes like bbarchivist.scripts.carrierchecker often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
#!/usr/bin/env python3
2
"""Checks a carrier for an OS version, can download."""
3
4
import os  # file/path operations
5
import sys  # load arguments
6
import webbrowser  # code list
7
8
import requests  # session
9
from bbarchivist import argutils  # arguments
10
from bbarchivist import bbconstants  # versions/constants
11
from bbarchivist import decorators  # enter to exit
12
from bbarchivist import jsonutils  # json
13
from bbarchivist import networkutils  # check function
14
from bbarchivist import scriptutils  # default parser
15
from bbarchivist import utilities  # input validation
16
17
__author__ = "Thurask"
18
__license__ = "WTFPL v2"
19
__copyright__ = "2015-2019 Thurask"
20
21
22
def grab_args():
23
    """
24
    Parse arguments from argparse/questionnaire.
25
26
    Invoke :func:`carrierchecker.carrierchecker_main` with those arguments.
27
    """
28
    if len(sys.argv) > 1:
29
        parser = argutils.default_parser("bb-cchecker", "Carrier info checking")
30
        parser.add_argument(
31
            "mcc",
32
            help="1-3 digit country code",
33
            type=argutils.valid_carrier,
34
            nargs="?",
35
            default=None)
36
        parser.add_argument(
37
            "mnc",
38
            help="1-3 digit carrier code",
39
            type=argutils.valid_carrier,
40
            nargs="?",
41
            default=None)
42
        parser.add_argument(
43
            "device",
44
            help="'STL100-1', 'SQW100-3', etc.",
45
            nargs="?",
46
            default=None)
47
        parser.add_argument(
48
            "-c", "--codes",
49
            dest="codes",
50
            help="Open browser for MCC/MNC list",
51
            action="store_true",
52
            default=False)
53
        parser.add_argument(
54
            "-a", "--available-bundles",
55
            dest="bundles",
56
            help="Check available bundles",
57
            action="store_true",
58
            default=False)
59
        parser.add_argument(
60
            "-d", "--download",
61
            dest="download",
62
            help="Download files after checking",
63
            action="store_true",
64
            default=False)
65
        parser.add_argument(
66
            "-e", "--export",
67
            dest="export",
68
            help="Export links to files",
69
            action="store_true",
70
            default=False)
71
        parser.add_argument(
72
            "-r", "--repair",
73
            dest="upgrade",
74
            help="Debrick instead of upgrade bars",
75
            action="store_false",
76
            default=True)
77
        parser.add_argument(
78
            "-f", "--folder",
79
            dest="folder",
80
            help="Working folder",
81
            default=None,
82
            metavar="DIR")
83
        parser.add_argument(
84
            "-b", "--blitz",
85
            dest="blitz",
86
            help="Create blitz package",
87
            action="store_true",
88
            default=False)
89
        parser.add_argument(
90
            "--selective",
91
            dest="selective",
92
            help="Skip Nuance/retaildemo",
93
            action="store_true",
94
            default=False)
95
        fgroup = parser.add_mutually_exclusive_group()
96
        fgroup.add_argument(
97
            "-s", "--software-release",
98
            dest="forcedsw",
99
            help="Force SW release (check bundles first!)",
100
            default=None,
101
            metavar="SWRELEASE")
102
        fgroup.add_argument(
103
            "-o", "--os",
104
            dest="forcedos",
105
            help="Force OS (check bundles first!)",
106
            default=None,
107
            metavar="OS")
108
        parser.set_defaults()
109
        args = parser.parse_args(sys.argv[1:])
110
        if args.codes:
111
            webbrowser.open("https://en.wikipedia.org/wiki/Mobile_country_code")
112
        else:
113
            execute_args(args)
114
    else:
115
        questionnaire()
116
    decorators.enter_to_exit(True)
117
118
119
def forced_avail(args):
120
    """
121
    Determine the forced argument after availability checking.
122
123
    :param args: Arguments.
124
    :type args: argparse.Namespace
125
    """
126
    avail = networkutils.sr_lookup(args.forcedos, bbconstants.SERVERS['p'])
127
    forced = avail if avail != "SR not in system" else None
128
    return forced
129
130
131
def forced_args(args):
132
    """
133
    Determine the forced argument.
134
135
    :param args: Arguments.
136
    :type args: argparse.Namespace
137
    """
138
    if utilities.one_and_none(args.forcedsw, args.forcedos):
139
        forced = forced_avail(args)
140
    elif utilities.one_and_none(args.forcedos, args.forcedsw):
141
        forced = args.forcedsw
142
    else:
143
        forced = None
144
    return forced
145
146
147
def execute_args(args):
148
    """
149
    Get args and decide what to do with them.
150
151
    :param args: Arguments.
152
    :type args: argparse.Namespace
153
    """
154
    args.folder = utilities.dirhandler(args.folder, os.getcwd())
155
    if args.blitz:
156
        args.download = True
157
        args.upgrade = True  # blitz takes precedence
158
    if args.bundles:
159
        args.download = False
160
        args.upgrade = False
161
        args.export = False
162
        args.blitz = False
163
    forced = forced_args(args)
164
    carrierchecker_main(args.mcc, args.mnc, args.device, args.download, args.upgrade, args.folder, args.export, args.blitz, args.bundles, forced, args.selective)
165
166
167
def questionnaire_3digit(message):
168
    """
169
    Get MCC/MNC from questionnaire.
170
    """
171
    while True:
172
        try:
173
            trip = int(input("{0}: ".format(message)))
174
        except ValueError:
175
            continue
176
        else:
177
            if trip == argutils.valid_carrier(trip):
178
                return trip
179
180
181
def questionnaire():
182
    """
183
    Questions to ask if no arguments given.
184
    """
185
    mcc = questionnaire_3digit("MCC")
186
    mnc = questionnaire_3digit("MNC")
187
    device = scriptutils.questionnaire_device()
188
    bundles = utilities.i2b("CHECK BUNDLES?: ")
189
    if bundles:
190
        download = False
191
        upgrade = False
192
        export = False
193
        blitz = False
194
    else:
195
        export = utilities.i2b("EXPORT TO FILE?: ")
196
        download = utilities.i2b("DOWNLOAD?: ")
197
        upgrade = False if not download else utilities.i2b("Y=UPGRADE BARS, N=DEBRICK BARS?: ")
198
        blitz = False if not download else (utilities.i2b("CREATE BLITZ?: ") if upgrade else False)
199
    directory = os.getcwd()
200
    print(" ")
201
    carrierchecker_main(mcc, mnc, device, download, upgrade, directory, export, blitz, bundles, None, False)
202
203
204
def carrierchecker_argfilter(mcc, mnc, device, directory):
205
    """
206
    Filter arguments.
207
208
    :param mcc: Country code.
209
    :type mcc: int
210
211
    :param mnc: Network code.
212
    :type mnc: int
213
214
    :param device: Device ID (XXX100-#)
215
    :type device: str
216
217
    :param directory: Where to store files. Default is local directory.
218
    :type directory: str
219
    """
220
    targdir = {"MCC": mcc, "MNC": mnc, "DEVICE": device}
221
    for key, value in targdir.items():
222
        if value is None:
223
            print("INVALID {0}!".format(key))
224
            raise SystemExit
225
    device = device.upper()
226
    directory = utilities.dirhandler(directory, os.getcwd())
227
    return device, directory
228
229
230
def carrierchecker_jsonprepare(mcc, mnc, device):
231
    """
232
    Prepare JSON data.
233
234
    :param mcc: Country code.
235
    :type mcc: int
236
237
    :param mnc: Network code.
238
    :type mnc: int
239
240
    :param device: Device ID (XXX100-#).
241
    :type device: str
242
    """
243
    data = jsonutils.load_json("devices")
244
    model, family, hwid = jsonutils.certchecker_prep(data, device)
245
    country, carrier = networkutils.carrier_checker(mcc, mnc)
246
    return model, family, hwid, country, carrier
247
248
249
def carrierchecker_bundles(mcc, mnc, hwid):
250
    """
251
    :param mcc: Country code.
252
    :type mcc: int
253
254
    :param mnc: Network code.
255
    :type mnc: int
256
257
    :param hwid: Device hardware ID.
258
    :type hwid: str
259
    """
260
    releases = networkutils.available_bundle_lookup(mcc, mnc, hwid)
261
    print("\nAVAILABLE BUNDLES:")
262
    utilities.lprint(releases)
263
264
265
def carrierchecker_selective(files, selective=False):
266
    """
267
    Filter useless bar files.
268
269
    :param files: List of files.
270
    :type files: list(str)
271
272
    :param selective: Whether or not to exclude Nuance/other dross. Default is false.
273
    :type selective: bool
274
    """
275
    if selective:
276
        craplist = jsonutils.load_json("apps_to_remove")
277
        files = scriptutils.clean_barlist(files, craplist)
278
    return files
279
280
281
def carrierchecker_export(mcc, mnc, files, hwid, osv, radv, swv, export=False, upgrade=False, forced=None):
282
    """
283
    Export files to file.
284
285
    :param mcc: Country code.
286
    :type mcc: int
287
288
    :param mnc: Network code.
289
    :type mnc: int
290
291
    :param files: List of files.
292
    :type files: list(str)
293
294
    :param hwid: Device hardware ID.
295
    :type hwid: str
296
297
    :param osv: OS version, 10.x.y.zzzz.
298
    :type osv: str
299
300
    :param radv: Radio version, 10.x.y.zzzz.
301
    :type radv: str
302
303
    :param swv: Software release, 10.x.y.zzzz.
304
    :type swv: str
305
306
    :param export: Whether or not to write URLs to a file. Default is false.
307
    :type export: bool
308
309
    :param upgrade: Whether or not to use upgrade files. Default is false.
310
    :type upgrade: bool
311
312
    :param forced: Force a software release. None to go for latest.
313
    :type forced: str
314
    """
315
    if export:
316
        print("\nEXPORTING...")
317
        npc = networkutils.return_npc(mcc, mnc)
318
        scriptutils.export_cchecker(files, npc, hwid, osv, radv, swv, upgrade, forced)
319
320
321
def carrierchecker_download_prep(files, directory, osv, radv, swv, family, blitz=False):
322
    """
323
    Prepare for downloading files.
324
325
    :param files: List of files.
326
    :type files: list(str)
327
328
    :param directory: Where to store files. Default is local directory.
329
    :type directory: str
330
331
    :param osv: OS version, 10.x.y.zzzz.
332
    :type osv: str
333
334
    :param radv: Radio version, 10.x.y.zzzz.
335
    :type radv: str
336
337
    :param swv: Software release, 10.x.y.zzzz.
338
    :type swv: str
339
340
    :param family: Device family.
341
    :type family: str
342
343
    :param blitz: Whether or not to create a blitz package. Default is false.
344
    :type blitz: bool
345
    """
346
    suffix = "-BLITZ" if blitz else "-{0}".format(family)
347
    bardir = os.path.join(directory, "{0}{1}".format(swv, suffix))
348
    if not os.path.exists(bardir):
349
        os.makedirs(bardir)
350
    if blitz:
351
        files = scriptutils.generate_blitz_links(files, osv, radv, swv)
352
    return bardir, files
353
354
355
def carrierchecker_download(files, directory, osv, radv, swv, family, download=False, blitz=False, session=None):
356
    """
357
    Download files, create blitz if specified.
358
359
    :param files: List of files.
360
    :type files: list(str)
361
362
    :param directory: Where to store files. Default is local directory.
363
    :type directory: str
364
365
    :param osv: OS version, 10.x.y.zzzz.
366
    :type osv: str
367
368
    :param radv: Radio version, 10.x.y.zzzz.
369
    :type radv: str
370
371
    :param swv: Software release, 10.x.y.zzzz.
372
    :type swv: str
373
374
    :param family: Device family.
375
    :type family: str
376
377
    :param download: Whether or not to download. Default is false.
378
    :type download: bool
379
380
    :param blitz: Whether or not to create a blitz package. Default is false.
381
    :type blitz: bool
382
383
    :param session: Requests session object, default is created on the fly.
384
    :type session: requests.Session()
385
    """
386
    if download:
387
        bardir, files = carrierchecker_download_prep(files, directory, osv, radv, swv, family, blitz)
388
        print("\nDOWNLOADING...")
389
        networkutils.download_bootstrap(files, outdir=bardir, session=session)
390
        scriptutils.test_bar_files(bardir, files)
391
        if blitz:
392
            scriptutils.package_blitz(bardir, swv)
393
        print("\nFINISHED!!!")
394
395
396
def carrierchecker_nobundles(mcc, mnc, hwid, family, download=False, upgrade=True, directory=None, export=False, blitz=False, forced=None, selective=False):
397
    """
398
    Wrap around :mod:`bbarchivist.networkutils` carrier checking.
399
400
    :param mcc: Country code.
401
    :type mcc: int
402
403
    :param mnc: Network code.
404
    :type mnc: int
405
406
    :param hwid: Device hardware ID.
407
    :type hwid: str
408
409
    :param family: Device family.
410
    :type family: str
411
412
    :param download: Whether or not to download. Default is false.
413
    :type download: bool
414
415
    :param upgrade: Whether or not to use upgrade files. Default is false.
416
    :type upgrade: bool
417
418
    :param directory: Where to store files. Default is local directory.
419
    :type directory: str
420
421
    :param export: Whether or not to write URLs to a file. Default is false.
422
    :type export: bool
423
424
    :param blitz: Whether or not to create a blitz package. Default is false.
425
    :type blitz: bool
426
427
    :param forced: Force a software release. None to go for latest.
428
    :type forced: str
429
430
    :param selective: Whether or not to exclude Nuance/other dross. Default is false.
431
    :type selective: bool
432
    """
433
    npc = networkutils.return_npc(mcc, mnc)
434
    swv, osv, radv, files = networkutils.carrier_query(npc, hwid, upgrade, blitz, forced)
435
    print("SOFTWARE RELEASE: {0}".format(swv))
436
    print("OS VERSION: {0}".format(osv))
437
    print("RADIO VERSION: {0}".format(radv))
438
    files = carrierchecker_selective(files, selective)
439
    carrierchecker_export(mcc, mnc, files, hwid, osv, radv, swv, export, upgrade, forced)
440
    sess = requests.Session()
441
    carrierchecker_download(files, directory, osv, radv, swv, family, download, blitz, sess)
442
443
444
def carrierchecker_main(mcc, mnc, device, download=False, upgrade=True, directory=None, export=False, blitz=False, bundles=False, forced=None, selective=False):
445
    """
446
    Wrap around :mod:`bbarchivist.networkutils` carrier checking.
447
448
    :param mcc: Country code.
449
    :type mcc: int
450
451
    :param mnc: Network code.
452
    :type mnc: int
453
454
    :param device: Device ID (XXX100-#).
455
    :type device: str
456
457
    :param download: Whether or not to download. Default is false.
458
    :type download: bool
459
460
    :param upgrade: Whether or not to use upgrade files. Default is false.
461
    :type upgrade: bool
462
463
    :param directory: Where to store files. Default is local directory.
464
    :type directory: str
465
466
    :param export: Whether or not to write URLs to a file. Default is false.
467
    :type export: bool
468
469
    :param blitz: Whether or not to create a blitz package. Default is false.
470
    :type blitz: bool
471
472
    :param bundles: Whether or not to check software bundles. Default is false.
473
    :type bundles: bool
474
475
    :param forced: Force a software release. None to go for latest.
476
    :type forced: str
477
478
    :param selective: Whether or not to exclude Nuance/other dross. Default is false.
479
    :type selective: bool
480
    """
481
    device, directory = carrierchecker_argfilter(mcc, mnc, device, directory)
482
    model, family, hwid, country, carrier = carrierchecker_jsonprepare(mcc, mnc, device)
483
    argutils.slim_preamble("CARRIERCHECKER")
484
    print("COUNTRY: {0}".format(country.upper()))
485
    print("CARRIER: {0}".format(carrier.upper()))
486
    print("DEVICE: {0}".format(model.upper()))
487
    print("VARIANT: {0}".format(device.upper()))
488
    print("HARDWARE ID: {0}".format(hwid.upper()))
489
    print("\nCHECKING CARRIER...")
490
    if bundles:
491
        carrierchecker_bundles(mcc, mnc, hwid)
492
    else:
493
        carrierchecker_nobundles(mcc, mnc, hwid, family, download, upgrade, directory, export, blitz, forced, selective)
494
495
496
if __name__ == "__main__":
497
    grab_args()
498