Completed
Push — master ( 654bda...c0db53 )
by John
03:04
created

generate_individual_loaders()   B

Complexity

Conditions 4

Size

Total Lines 34

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 4

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
c 1
b 0
f 0
dl 0
loc 34
ccs 10
cts 10
cp 1
crap 4
rs 8.5806
1
#!/usr/bin/env python3
2 4
"""This module is used for creation of autoloaders.
3
A higher level interface for :mod:`bbarchivist.pseudocap`."""
4
5 4
import os  # path work
6 4
import glob  # filename matching
7 4
from bbarchivist import exceptions  # exception handling
8 4
from bbarchivist import pseudocap  # implement cap
9 4
from bbarchivist import jsonutils  # json
10
11 4
__author__ = "Thurask"
12 4
__license__ = "WTFPL v2"
13 4
__copyright__ = "Copyright 2015-2016 Thurask"
14
15
16 4
def read_files(localdir, core=False):
17
    """
18
    Read list of signed files, return name assignments.
19
20
    :param localdir: Directory to use.
21
    :type localdir: str
22
23
    :param core: If we're using a core OS image. Default is false.
24
    :type core: bool
25
    """
26 4
    oslist = read_os_files(localdir, core)
27
    # [8960, 8x30, 8974, ti]
28 4
    radlist = read_radio_files(localdir)
29
    # [ti, z10, z10_vzw, q10, z30, z3, 8974]
30 4
    pairdict = {}
31 4
    mapping = {0:3, 1:0, 2:0, 3:0, 4:0, 5:1, 6:2}
32 4
    for idx, rad in enumerate(radlist):
33 4
        pairdict[rad] = oslist[mapping[idx]]
34 4
    filtdict = {k: v for k, v in pairdict.items() if k}  # pop None
35 4
    return filtdict
36
37
38 4
def find_signed_file(match, localdir, title, silent=False):
39
    """
40
    Use pattern matching to find a signed file in a directory.
41
42
    :param match: Match pattern to use.
43
    :type match: str
44
45
    :param localdir: Directory to use.
46
    :type localdir: str
47
48
    :param title: File type, in case it isn't found.
49
    :type title: str
50
51
    :param silent: Don't print that a file wasn't found. Default is False.
52
    :type silent: bool
53
    """
54 4
    try:
55 4
        signedfile = glob.glob(os.path.join(localdir, match))[0]
56 4
    except IndexError:
57 4
        signedfile = None
58 4
        if not silent:
59 4
            print("No {0} found".format(title))
60 4
    return signedfile
61
62
63 4
def read_os_files(localdir, core=False):
64
    """
65
    Read list of OS signed files, return name assignments.
66
67
    :param localdir: Directory to use.
68
    :type localdir: str
69
70
    :param core: If we're using a core OS image. Default is false.
71
    :type core: bool
72
    """
73 4
    if core:
74 4
        fix8960 = "*qc8960.*_sfi.BB*.signed"
75 4
        fixomap_new = "*winchester.*_sfi.BB*.signed"
76 4
        fixomap_old = "*os.factory_sfi.BB*.signed"
77 4
        fix8930 = "*qc8x30.BB*.signed"
78 4
        fix8974_new = "*qc8974.BB*.signed"
79 4
        fix8974_old = "*qc8974.*_sfi.BB*.signed"
80
    else:
81 4
        fix8960 = "*qc8960.*_sfi.desktop.BB*.signed"
82 4
        fixomap_new = "*winchester.*_sfi.desktop.BB*.signed"
83 4
        fixomap_old = "*os.factory_sfi.desktop.BB*.signed"
84 4
        fix8930 = "*qc8x30.desktop.BB*.signed"
85 4
        fix8974_new = "*qc8974.desktop.BB*.signed"
86 4
        fix8974_old = "*qc8974.*_sfi.desktop.BB*.signed"
87
    # 8960
88 4
    os_8960 = find_signed_file(fix8960, localdir, "8960 OS")
89
    # 8x30 (10.3.1 MR+)
90 4
    os_8x30 = find_signed_file(fix8930, localdir, "8x30 OS", True)
91 4
    if os_8x30 is None:
92 4
        os_8x30 = find_signed_file(fix8960, localdir, "8x30 OS")
93
    # 8974
94 4
    os_8974 = find_signed_file(fix8974_new, localdir, "8974 OS", True)
95 4
    if os_8974 is None:
96 4
        os_8974 = find_signed_file(fix8974_old, localdir, "8974 OS")
97
    # OMAP
98 4
    os_ti = find_signed_file(fixomap_new, localdir, "OMAP OS", True)
99 4
    if os_ti is None:
100 4
        os_ti = find_signed_file(fixomap_old, localdir, "OMAP OS")
101 4
    return [os_8960, os_8x30, os_8974, os_ti]
102
103
104 4
def read_radio_files(localdir):
105
    """
106
    Read list of radio signed files, return name assignments.
107
108
    :param localdir: Directory to use.
109
    :type localdir: str
110
    """
111
    # STL100-1
112 4
    radio_ti = find_signed_file("*radio.m5730*.signed", localdir, "OMAP radio")
113
    # STL100-X
114 4
    radio_z10 = find_signed_file("*radio.qc8960.BB*.signed", localdir, "8960 radio")
115
    # STL100-4
116 4
    radio_z10_vzw = find_signed_file("*radio.qc8960*omadm*.signed", localdir, "VZW 8960 radio")
117
    # Q10/Q5
118 4
    radio_q10 = find_signed_file("*radio.qc8960*wtr.*signed", localdir, "Q10/Q5 radio")
119
    # Z30/Classic
120 4
    radio_z30 = find_signed_file("*radio.qc8960*wtr5*.signed", localdir, "Z30/Classic radio")
121
    # Z3
122 4
    radio_z3 = find_signed_file("*radio.qc8930*wtr5*.signed", localdir, "Z3 radio")
123
    # Passport
124 4
    radio_8974 = find_signed_file("*radio.qc8974*wtr2*.signed", localdir, "Passport radio")
125 4
    return [radio_ti, radio_z10, radio_z10_vzw, radio_q10, radio_z30, radio_z3, radio_8974]
126
127
128 4
def zeropad(splitver, idx, padlen):
129
    """
130
    Zero-pad an element of an OS/radio version to a certain length.
131
132
    :param splitver: OS/radio version, but split into quarters.
133
    :type splitver: list(str)
134
135
    :param idx: Index of splitver which must be checked.
136
    :type idx: int
137
138
    :param padlen: Length to pad to.
139
    :type padlen: int
140
    """
141 4
    if len(splitver[idx]) < padlen:
142 4
        splitver[idx] = splitver[idx].rjust(padlen, "0")
143 4
    return splitver
144
145
146 4
def versionpad(splitver):
147
    """
148
    Properly pad an OS/radio version.
149
150
    :param splitver: OS/radio version, but split into quarters.
151
    :type splitver: list(str)
152
    """
153 4
    splitver = zeropad(splitver, 2, 2)
154 4
    splitver = zeropad(splitver, 3, 4)
155 4
    return splitver
156
157
158 4
def pretty_formatter(osversion, radioversion):
159
    """
160
    Format OS/radio versions to cope with systems with poor sorting.
161
162
    :param osversion: OS version, 10.x.y.zzzz.
163
    :type osversion: str
164
165
    :param radioversion: Radio version, 10.x.y.zzzz.
166
    :type radioversion: str
167
    """
168
    # 10.x.y.zzz becomes 10.x.0y.0zzz
169 4
    splitos = osversion.split(".")
170 4
    splitos = versionpad(splitos)
171 4
    the_os = ".".join(splitos)
172 4
    splitrad = radioversion.split(".")
173 4
    splitrad = versionpad(splitrad)
174 4
    the_radio = ".".join(splitrad)
175 4
    return the_os, the_radio
176
177
178 4
def format_suffix(altradio=None, radioversion=None, core=False):
179
    """
180
    Formulate suffix for hybrid autoloaders.
181
182
    :param altradio: If a hybrid autoloader is being made.
183
    :type altradio: bool
184
185
    :param radioversion: The hybrid radio version, if applicable.
186
    :type radioversion: str
187
188
    :param core: If we're using a core OS image. Default is false.
189
    :type core: bool
190
    """
191 4
    suffix = "_R{0}".format(radioversion) if altradio and radioversion else ""
192 4
    if core:
193 4
        suffix += "_CORE"
194 4
    return suffix
195
196
197 4
def generate_loaders(osversion, radioversion, radios=True, localdir=None, altradio=False, core=False):
198
    """
199
    Create and label autoloaders for :mod:`bbarchivist.scripts.archivist`.
200
201
    :param osversion: OS version, 10.x.y.zzzz.
202
    :type osversion: str
203
204
    :param radioversion: Radio version, 10.x.y.zzzz.
205
    :type radioversion: str
206
207
    :param radios: Whether to make radios or not. True by default.
208
    :type radios: bool
209
210
    :param localdir: Working path. Default is local dir.
211
    :type localdir: str
212
213
    :param altradio: If we're using an alternate radio. Default is false.
214
    :type altradio: bool
215
216
    :param core: If we're using a core OS image. Default is false.
217
    :type core: bool
218
    """
219
    # default parsing
220 4
    localdir = os.getcwd() if localdir is None else localdir
221 4
    print("GETTING FILENAMES...")
222 4
    filedict = read_files(localdir, core)
223 4
    osversion, radioversion = pretty_formatter(osversion, radioversion)
224 4
    suffix = format_suffix(altradio, radioversion, core)
225
    # Generate loaders
226 4
    print("CREATING LOADERS...")
227 4
    filtrad = [rad for rad in filedict.keys() if rad]  # pop None
228 4
    generate_individual_loaders(filtrad, osversion, radioversion, suffix, filedict, radios, localdir)
229
230
231 4
def generate_individual_loaders(filtrad, osversion, radioversion, suffix, filedict, radios, localdir):
232
    """
233
    Generate individual loaders when generating several at once.
234
235
    :param filtrad: List of radio files, if they exist.
236
    :type filtrad: list(str)
237
238
    :param osversion: OS version, 10.x.y.zzzz.
239
    :type osversion: str
240
241
    :param radioversion: Radio version, 10.x.y.zzzz.
242
    :type radioversion: str
243
244
    :param suffix: Alternate radio, or blank.
245
    :type suffix: str
246
247
    :param filedict: Dictionary of radio:OS pairs.
248
    :type filedict: dict(str: str)
249
250
    :param radios: Whether to make radios or not. True by default.
251
    :type radios: bool
252
253
    :param localdir: Working path. Default is local dir.
254
    :type localdir: str
255
    """
256 4
    for radval in filtrad:
257 4
        device = generate_device(radval)
258 4
        osname = generate_filename(device, osversion, suffix)
259 4
        osfile = filedict[radval]
260 4
        if osfile is not None:
261 4
            wrap_pseudocap(osname, localdir, osfile, radval)
262 4
        if radios:
263 4
            radname = generate_filename(device, radioversion, "")
264 4
            wrap_pseudocap(radname, localdir, radval)
265
266
267
268 4
def wrap_pseudocap(filename, folder, first, second=None):
269
    """
270
    A filtered, excepting wrapper for pseudocap.
271
272
    :param filename: The title of the new loader.
273
    :type filename: str
274
275
    :param folder: The folder to create the loader in.
276
    :type folder: str
277
278
    :param first: The first signed file, required.
279
    :type first: str
280
281
    :param second: The second signed file, optional.
282
    :type second: str
283
    """
284 4
    if first is None:
285 4
        print("No OS!")
286 4
        raise SystemError
287 4
    try:
288 4
        pseudocap.make_autoloader(filename, [first, second], folder=folder)
289 4
    except (OSError, IndexError, SystemError) as exc:
290 4
        msg = "Could not create {0}".format(filename)
291 4
        exceptions.handle_exception(exc, msg, None)
292
293
294 4
def generate_skeletons():
295
    """
296
    Read JSON to get a dict of all filename components.
297
    """
298 4
    namelist = {0: None, 1: None, 2: None, 3: None, 4: None, 5: None, 6: None}
299 4
    data = jsonutils.load_json('integermap')
300 4
    for key in data:
301 4
        if key['id'] in namelist:
302 4
            namelist[key['id']] = (key['parts'])
303 4
            namelist[key['id']].append(".exe")
304 4
    return namelist
305
306
307 4
def generate_device(radio):
308
    """
309
    Read JSON to get the device integer ID from device radio.
310
311
    :param radio: The radio filename to look up.
312
    :type radio: str
313
    """
314 4
    data = jsonutils.load_json('integermap')
315 4
    for key in data:
316 4
        if key['radtype'] in radio:
317 4
            idx = int(key['id'])
318 4
            break
319 4
    return idx
320
321
322 4
def generate_filename(device, version, suffix=None):
323
    """
324
    Use skeleton dict to create loader filenames.
325
326
    :param device: Device to use.
327
    :type device: int
328
329
    :param version: OS or radio version.
330
    :type version: str
331
332
    :param suffix: Alternate radio, or blank.
333
    :type suffix: str
334
    """
335 4
    thed = generate_skeletons()
336 4
    if device < 0:
337 4
        return None
338 4
    dev = thed[device]
339 4
    if suffix is None:
340 4
        suffix = ""
341 4
    return "{0}{1}{2}{3}{4}".format(dev[0], version, suffix, dev[1], dev[2])
342
343
344 4
def generate_lazy_loader(
345
        osversion, device,
346
        localdir=None, altradio=None, core=False):
347
    """
348
    Create and label autoloaders for :mod:`bbarchivist.scripts.lazyloader`.
349
    :func:`generate_loaders`, but for making one OS/radio loader.
350
351
    :param osversion: OS version, 10.x.y.zzzz.
352
    :type osversion: str
353
354
    :param device: Selected device, from
355
    :type device: int
356
357
    :param localdir: Working path. Default is local dir.
358
    :type localdir: str
359
360
    :param altradio: The alternate radio in use, if there is one.
361
    :type altradio: str
362
363
    :param core: If we're using a core OS image. Default is false.
364
    :type core: bool
365
    """
366
    # default parsing
367 4
    localdir = os.getcwd() if localdir is None else localdir
368 4
    print("CREATING LOADER...")
369 4
    suffix = format_suffix(bool(altradio), altradio, core)
370 4
    osfile = None
371 4
    absoglob = "{0}{1}".format(localdir, os.sep)
372 4
    try:
373 4
        osfile = str(glob.glob("{0}*_sfi*.signed".format(absoglob))[0])
374 4
    except IndexError:
375 4
        print("No OS found")
376
    else:
377 4
        generate_lazy_set(osversion, device, osfile, suffix, absoglob, localdir)
378
379
380 4
def generate_lazy_set(osversion, device, osfile, suffix, absoglob, localdir=None):
381
    """
382
    Get radio file and then generate autoloader.
383
384
    :param osversion: OS version, 10.x.y.zzzz.
385
    :type osversion: str
386
387
    :param device: Selected device, from
388
    :type device: int
389
390
    :param osfile: OS signed filename.
391
    :type osfile: str
392
393
    :param suffix: Loader name suffix.
394
    :type suffix: str
395
396
    :param absoglob: Local path + path separator.
397
    :type absoglob: str
398
399
    :param localdir: Working path. Default is local dir.
400
    :type localdir: str
401
    """
402 4
    radiofile = None
403 4
    try:
404 4
        sset = set(glob.glob("{0}*.signed".format(absoglob)))
405 4
        rset = sset - set(glob.glob("{0}*_sfi*.signed".format(absoglob)))
406 4
        radiofile = str(list(rset)[0])
407 4
    except IndexError:
408 4
        print("No radio found")
409
    else:
410 4
        loadername = generate_lazy_filename(osversion, suffix, device)
411 4
        wrap_pseudocap(loadername, localdir, osfile, radiofile)
412
413
414 4
def generate_lazy_filename(osversion, suffix, device):
415
    """
416
    Read JSON to formulate a single filename.
417
418
    :param osversion: OS version.
419
    :type osversion: str
420
421
    :param suffix: Alternate radio, or just blank.
422
    :type suffix: str
423
424
    :param device: Device to use.
425
    :type device: int
426
    """
427 4
    data = jsonutils.load_json('integermap')
428 4
    for key in data:
429 4
        if key['id'] == device:
430 4
            fname = key['parts']
431 4
            break
432
    return "{0}{1}{2}{3}.exe".format(fname[0], osversion, suffix, fname[1])
433