tcl_findprd_centerscan()   A
last analyzed

Complexity

Conditions 1

Size

Total Lines 32
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 5
nop 8
dl 0
loc 32
rs 10
c 0
b 0
f 0
ccs 5
cts 5
cp 1
crap 1

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
#!/usr/bin/env python3
2 5
"""This module contains various utilities for TCL tools."""
3
4 5
import collections  # defaultdict
5 5
import os  # path work
6
7 5
import requests  # session
8 5
from bbarchivist import argutils  # arguments
9 5
from bbarchivist import hashutils  # file hashes
10 5
from bbarchivist import networkutils  # network tools
11 5
from bbarchivist import networkutilstcl  # tcl network tools
12 5
from bbarchivist import utilities  # little things
13 5
from bbarchivist import xmlutilstcl  # xml handling
14
15 5
__author__ = "Thurask"
16 5
__license__ = "WTFPL v2"
17 5
__copyright__ = "2018-2019 Thurask"
18
19
20 5
def tclloader_prep(loaderfile, directory=False):
21
    """
22
    Prepare directory name and OS version.
23
24
    :param loaderfile: Path to input file/folder.
25
    :type loaderfile: str
26
27
    :param directory: If the input file is a folder. Default is False.
28
    :type directory: bool
29
    """
30 5
    loaderdir = loaderfile if directory else loaderfile.replace(".zip", "")
31 5
    osver = loaderdir.split("-")[-1]
32 5
    return loaderdir, osver
33
34
35 5
def tclloader_filename(loaderdir, osver, loadername=None):
36
    """
37
    Prepare platform and filename.
38
39
    :param loaderdir: Path to input folder.
40
    :type loaderdir: str
41
42
    :param osver: OS version.
43
    :type osver: str
44
45
    :param loadername: Name of final autoloader. Default is auto-generated.
46
    :type loadername: str
47
    """
48 5
    platform = os.listdir(os.path.join(loaderdir, "target", "product"))[0]
49 5
    if loadername is None:
50 5
        loadername = "{0}_autoloader_user-all-{1}".format(platform, osver)
51 5
    return loadername, platform
52
53
54 5
def tcl_download(downloadurl, filename, filesize, filehash, verify=True):
55
    """
56
    Download autoloader file, rename, and verify.
57
58
    :param downloadurl: Download URL.
59
    :type downloadurl: str
60
61
    :param filename: Name of autoloader file.
62
    :type filename: str
63
64
    :param filesize: Size of autoloader file.
65
    :type filesize: str
66
67
    :param filehash: SHA-1 hash of autoloader file.
68
    :type filehash: str
69
70
    :param verify: Whether to verify the file after downloading. Default is True.
71
    :type verify: bool
72
    """
73 5
    print("FILENAME: {0}".format(filename))
74 5
    print("LENGTH: {0}".format(utilities.fsizer(filesize)))
75 5
    networkutils.download(downloadurl)
76 5
    print("DOWNLOAD COMPLETE")
77 5
    os.rename(downloadurl.split("/")[-1], filename)
78 5
    if verify:
79 5
        method = hashutils.get_engine("sha1")
80 5
        shahash = hashutils.hashlib_hash(filename, method)
81 5
        if shahash == filehash:
82 5
            print("HASH CHECK OK")
83
        else:
84 5
            print(shahash)
85 5
            print("HASH FAILED!")
86
87
88 5
def tcl_prd_scan(curef, download=False, mode=4, fvver="AAA000", original=True, export=False, verify=True):
89
    """
90
    Scan one PRD and produce download URL and filename.
91
92
    :param curef: PRD of the phone variant to check.
93
    :type curef: str
94
95
    :param download: If we'll download the file that this returns. Default is False.
96
    :type download: bool
97
98
    :param mode: 4 if downloading autoloaders, 2 if downloading OTA deltas.
99
    :type mode: int
100
101
    :param fvver: Initial software version, must be specific if downloading OTA deltas.
102
    :type fvver: str
103
104
    :param original: If we'll download the file with its original filename. Default is True.
105
    :type original: bool
106
107
    :param export: Whether to export XML response to file. Default is False.
108
    :type export: bool
109
110
    :param verify: Whether to verify the file after downloading. Default is True.
111
    :type verify: bool
112
    """
113 5
    sess = requests.Session()
114 5
    ctext = networkutilstcl.tcl_check(curef, sess, mode, fvver, export)
115 5
    if ctext is None:
116 5
        raise SystemExit
117 5
    tvver, firmwareid, filename, filesize, filehash = xmlutilstcl.parse_tcl_check(ctext)
118 5
    salt = networkutilstcl.tcl_salt()
119 5
    vkhsh = networkutilstcl.vkhash(curef, tvver, firmwareid, salt, mode, fvver)
120 5
    updatetext = networkutilstcl.tcl_download_request(curef, tvver, firmwareid, salt, vkhsh, sess, mode, fvver, export)
121 5
    downloadurl, encslave = xmlutilstcl.parse_tcl_download_request(updatetext)
122 5
    statcode = networkutils.getcode(downloadurl, sess)
123 5
    filename = tcl_delta_filename(curef, fvver, tvver, filename, original)
124 5
    tcl_prd_print(tvver, downloadurl, filename, statcode, encslave, sess)
125 5
    if statcode == 200 and download:
126 5
        tcl_download(downloadurl, filename, filesize, filehash, verify)
127
128
129 5
def tcl_delta_filename(curef, fvver, tvver, filename, original=True):
130
    """
131
    Generate compatible filenames for deltas, if needed.
132
133
    :param curef: PRD of the phone variant to check.
134
    :type curef: str
135
136
    :param fvver: Initial software version.
137
    :type fvver: str
138
139
    :param tvver: Target software version.
140
    :type tvver: str
141
142
    :param filename: File name from download URL, passed through if not changing filename.
143
    :type filename: str
144
145
    :param original: If we'll download the file with its original filename. Default is True.
146
    :type original: bool
147
    """
148 5
    if not original:
149 5
        prdver = curef.split("-")[1]
150 5
        filename = "JSU_PRD-{0}-{1}to{2}.zip".format(prdver, fvver, tvver)
151 5
    return filename
152
153
154 5
def tcl_prd_print(tvver, downloadurl, filename, statcode, encslave, session):
155
    """
156
    Print output from PRD scanning.
157
158
    :param tvver: Target software version.
159
    :type tvver: str
160
161
    :param downloadurl: File to download.
162
    :type downloadurl: str
163
164
    :param filename: File name from download URL.
165
    :type filename: str
166
167
    :param statcode: Status code of download URL.
168
    :type statcode: int
169
170
    :param encslave: Server hosting header script.
171
    :type encslave: str
172
173
    :param session: Session object.
174
    :type session: requests.Session
175
    """
176 5
    print("OS: {0}".format(tvver))
177 5
    print("{0}: HTTP {1}".format(filename, statcode))
178 5
    print(downloadurl)
179 5
    if encslave is not None:
180 5
        address = "/{0}".format(downloadurl.split("/", 3)[3:][0])
181 5
        print("CHECKING HEADER...")
182 5
        sentinel = networkutilstcl.encrypt_header(address, encslave, session)
183 5
        if sentinel is not None:
184 5
            print(sentinel)
185
186
187 5
def tcl_prep_otaver(ota=None):
188
    """
189
    Prepare variables for OTA versus full check.
190
191
    :param ota: The starting version if OTA, None if not. Default is None.
192
    :type ota: str
193
    """
194 5
    if ota is not None:
195 5
        mode = 2
196 5
        fvver = ota
197
    else:
198 5
        mode = 4
199 5
        fvver = "AAA000"
200 5
    return mode, fvver
201
202
203 5
def tcl_delta_remote(curef):
204
    """
205
    Prepare remote version for delta scanning.
206
207
    :param curef: PRD of the phone variant to check.
208
    :type curef: str
209
    """
210 5
    remotedict = networkutilstcl.remote_prd_info()
211 5
    fvver = remotedict.get(curef, "AAA000")
212 5
    if fvver == "AAA000":
213 5
        print("NO REMOTE VERSION FOUND!")
214 5
        raise SystemExit
215 5
    return fvver
216
217
218 5
def tcl_mainscan_preamble(ota=None):
219
    """
220
    Prepare preamble for TCL scanning.
221
222
    :param ota: The starting version if OTA, None if not. Default is None.
223
    :type ota: str
224
    """
225 5
    argutils.slim_preamble("TCLSCAN")
226 5
    if ota is not None:
227 5
        print("PRDs with OTA from OS {0}".format(ota.upper()))
228
229
230 5
def tcl_mainscan_printer(curef, tvver, ota=None):
231
    """
232
    Print output of TCL scanning.
233
234
    :param curef: PRD of the phone variant to check.
235
    :type curef: str
236
237
    :param tvver: Target software version.
238
    :type tvver: str
239
240
    :param ota: The starting version if OTA, None if not. Default is None.
241
    :type ota: str
242
    """
243 5
    if ota is not None:
244 5
        print("{0}: {2} to {1}".format(curef, tvver, ota.upper()))
245
    else:
246 5
        print("{0}: {1}".format(curef, tvver))
247
248
249 5
def tcl_findprd_prepd_start(prddict):
250
    """
251
    Collect list of PRD entries.
252
253
    :param prddict: Device:PRD dictionary.
254
    :type prddict: dict(str: list)
255
    """
256 5
    prda = []
257 5
    for item in prddict.values():
258 5
        prda.extend(item)
259 5
    return prda
260
261
262 5
def tcl_findprd_prepd_middle(prda):
263
    """
264
    Convert PRD entries to list of center:end entries.
265
266
    :param prda: List of PRD-xxxxx-yyy entries.
267
    :type prda: list(str)
268
    """
269 5
    prds = [x.split(" ")[0].replace("PRD-", "").replace("APBI-PRD", "").replace("-", "") for x in prda]
270 5
    prdx = list({x[0:5]: x[5:]} for x in prds)
271 5
    return prdx
272
273
274 5
def tcl_findprd_prepd_end(prdx):
275
    """
276
    Convert list of center:end entries to final center:[ends] dict.
277
278
    :param prdx: List of center:end dict entries.
279
    :type prdx: list(dict(str: str))
280
    """
281 5
    prdf = collections.defaultdict(list)
282 5
    for prdc in prdx:
283 5
        for key, value in prdc.items():
284 5
            prdf[key].append(value)
285 5
    return prdf
286
287
288 5
def tcl_findprd_prepdict(prddict):
289
    """
290
    Prepare dict of center:[ends] entries.
291
292
    :param prddict: Device:PRD dictionary.
293
    :type prddict: dict(str: list)
294
    """
295 5
    prda = tcl_findprd_prepd_start(prddict)
296 5
    prdx = tcl_findprd_prepd_middle(prda)
297 5
    prdfinal = tcl_findprd_prepd_end(prdx)
298 5
    return prdfinal
299
300
301 5
def tcl_findprd_checkfilter(prddict, tocheck=None):
302
    """
303
    Filter PRD dict if needed.
304
305
    :param prddict: PRD center:[ends] dictionary.
306
    :type prddict: collections.defaultdict(str: list)
307
308
    :param tocheck: Specific PRD(s) to check, None if all will be checked. Default is None.
309
    :type tocheck: list(str)
310
    """
311 5
    prddict2 = prddict
312 5
    if tocheck is not None:
313 5
        prddict2 = collections.defaultdict(list)
314 5
        for toch in tocheck:
315 5
            toch = toch.replace("PRD-", "").replace("APBI-PRD", "")
316 5
            prddict2[toch] = prddict[toch]
317 5
    return prddict2
318
319
320 5
def tcl_findprd_centerscan(center, prddict, session, floor=0, ceiling=999, export=False, noprefix=False, key2mode=False):
321
    """
322
    Individual scanning for the center of a PRD.
323
324
    :param center: PRD-center-end.
325
    :type center: str
326
327
    :param prddict: PRD center:[ends] dictionary.
328
    :type prddict: collections.defaultdict(str: list)
329
330
    :param session: Session object.
331
    :type session: requests.Session
332
333
    :param floor: When to start. Default is 0.
334
    :type floor: int
335
336
    :param ceiling: When to stop. Default is 999.
337
    :type ceiling: int
338
339
    :param export: Whether to export XML response to file. Default is False.
340
    :type export: bool
341
342
    :param noprefix: Whether to skip adding "PRD-" prefix. Default is False.
343
    :type noprefix: bool
344
345
    :param key2mode: Whether to use new-style prefix. Default is False.
346
    :type key2mode: bool
347
    """
348 5
    tails = [int(i) for i in prddict[center]]
349 5
    safes = [g for g in range(floor, ceiling) if g not in tails]
350 5
    print("SCANNING ROOT: {0}{1}".format(center, " "*12))
351 5
    tcl_findprd_safescan(safes, center, session, export, noprefix, key2mode)
352
353
354 5
def tcl_findprd_prepcuref(center, tail, noprefix=False, key2mode=False):
355
    """
356
    Prepare candidate PRD.
357
358
    :param center: PRD-center-tail.
359
    :type center: str
360
361
    :param tail: PRD-center-tail.
362
    :type tail: int
363
364
    :param noprefix: Whether to skip adding "PRD-" prefix. Default is False.
365
    :type noprefix: bool
366
367
    :param key2mode: Whether to use new-style prefix. Default is False.
368
    :type key2mode: bool
369
    """
370 5
    if key2mode:
371 5
        curef = "APBI-PRD{0}{1:03}".format(center, tail)
372
    else:
373 5
        prefix = "" if noprefix else "PRD-"
374 5
        curef = "{2}{0}-{1:03}".format(center, tail, prefix)
375 5
    return curef
376
377
378 5
def tcl_findprd_safescan(safes, center, session, export=False, noprefix=False, key2mode=False):
379
    """
380
    Scan for PRDs known not to be in database.
381
382
    :param safes: List of ends within given range that aren't in database.
383
    :type safes: list(int)
384
385
    :param center: PRD-center-end.
386
    :type center: str
387
388
    :param session: Session object.
389
    :type session: requests.Session
390
391
    :param export: Whether to export XML response to file. Default is False.
392
    :type export: bool
393
394
    :param noprefix: Whether to skip adding "PRD-" prefix. Default is False.
395
    :type noprefix: bool
396
397
    :param key2mode: Whether to use new-style prefix. Default is False.
398
    :type key2mode: bool
399
    """
400 5
    for j in safes:
401 5
        curef = tcl_findprd_prepcuref(center, j, noprefix, key2mode)
402 5
        print("NOW SCANNING: {0}".format(curef), end="\r")
403 5
        checktext = networkutilstcl.tcl_check(curef, session, export)
404 5
        if checktext is None:
405 5
            continue
406
        else:
407 5
            tcl_findprd_safehandle(curef, checktext)
408
409
410 5
def tcl_findprd_safehandle(curef, checktext):
411
    """
412
    Parse API output and print the relevant bits.
413
414
    :param curef: PRD of the phone variant to check.
415
    :type curef: str
416
417
    :param checktext: The XML formatted data returned from the first stage API check.
418
    :type checktext: str
419
    """
420 5
    tvver, firmwareid, filename, fsize, fhash = xmlutilstcl.parse_tcl_check(checktext)
421 5
    del firmwareid, filename, fsize, fhash
422 5
    tvver2 = "{0}{1}".format(tvver, " "*12)
423 5
    tcl_mainscan_printer(curef, tvver2)
424
425
426 5
def tcl_findprd(prddict, floor=0, ceiling=999, export=False, noprefix=False, key2mode=False):
427
    """
428
    Check for new PRDs based on PRD database.
429
430
    :param prddict: PRD center:[ends] dictionary.
431
    :type prddict: collections.defaultdict(str: list)
432
433
    :param floor: When to start. Default is 0.
434
    :type floor: int
435
436
    :param ceiling: When to stop. Default is 999.
437
    :type ceiling: int
438
439
    :param export: Whether to export XML response to file. Default is False.
440
    :type export: bool
441
442
    :param noprefix: Whether to skip adding "PRD-" prefix. Default is False.
443
    :type noprefix: bool
444
445
    :param key2mode: Whether to use new-style prefix. Default is False.
446
    :type key2mode: bool
447
    """
448 5
    sess = requests.Session()
449 5
    for center in sorted(prddict.keys()):
450
        tcl_findprd_centerscan(center, prddict, sess, floor, ceiling, export, noprefix, key2mode)
451