Completed
Push — master ( a6073f...55356b )
by John
03:36
created

generate_os_fixes()   A

Complexity

Conditions 2

Size

Total Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 2

Importance

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