Completed
Push — master ( cc3d7d...434f23 )
by srz
01:16
created

create_option_list()   F

Complexity

Conditions 20

Size

Total Lines 34

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 20
c 0
b 0
f 0
dl 0
loc 34
rs 2.6863

1 Method

Rating   Name   Duplication   Size   Complexity  
A filterout_cppver() 0 4 3

How to fix   Complexity   

Complexity

Complex classes like create_option_list() 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 python
2
#
3
# iuwandbox.py
4
#
5
# Copyright (C) 2014-2017, Takazumi Shirayanagi
6
# This software is released under the new BSD License,
7
# see LICENSE
8
#
9
10
import os
11
import sys
12
import re
13
import codecs
14
15
from time import sleep
16
from argparse import ArgumentParser
17
from wandbox import Wandbox
18
from requests.exceptions import HTTPError
19
20
IUTEST_FUSED_SRC = os.path.normpath(os.path.join(os.path.dirname(__file__), '../../fused-src/iutest.min.hpp'))
21
IUTEST_INCLUDE_PATH = os.path.normpath(os.path.join(os.path.dirname(__file__), '../../include'))
22
IUTEST_INCLUDE_REGEX = re.compile(r'^\s*#\s*include\s*".*(iutest|iutest_switch)\.hpp"')
23
EXPAND_INCLUDE_REGEX = re.compile(r'^\s*#\s*include\s*"(.*?)"')
24
IUTEST_INCG_REGEX = re.compile(r'\s*#\s*define[/\s]*(INCG_IRIS_\S*)\s*')
25
26
iutest_incg_list = []
27
28
#
29
# command line option
30
def parse_command_line():
31
    parser = ArgumentParser()
32
    parser.add_argument(
33
        '-v',
34
        '--version',
35
        action='version',
36
        version=u'%(prog)s version 4.5'
37
    )
38
    parser.add_argument(
39
        '--list_compiler',
40
        action='store_true',
41
        help='listup compiler.'
42
    )
43
    parser.add_argument(
44
        '--list_options',
45
        metavar='COMPILER',
46
        help='listup compiler options.'
47
    )
48
    parser.add_argument(
49
        '-c',
50
        '--compiler',
51
        default='gcc-head',
52
        help='compiler select. default: %(default)s'
53
    )
54
    parser.add_argument(
55
        '-x',
56
        '--options',
57
        help='used options for a compiler.'
58
    )
59
    parser.add_argument(
60
        '--default',
61
        action='store_true',
62
        help='it is not work. default options are set by default (deprecated)'
63
    )
64
    parser.add_argument(
65
        '--no-default',
66
        action='store_true',
67
        help='no set default options.'
68
    )
69
    parser.add_argument(
70
        '--std',
71
        metavar='VERSION',
72
        help='set --std options.'
73
    )
74
    parser.add_argument(
75
        '--boost',
76
        metavar='VERSION',
77
        help='set boost options version X.XX or nothing.'
78
    )
79
    parser.add_argument(
80
        '--sprout',
81
        action='store_true',
82
        help='use sprout.'
83
    )
84
    parser.add_argument(
85
        '--msgpack',
86
        action='store_true',
87
        help='use msgpack.'
88
    )
89
    parser.add_argument(
90
        '--stdin',
91
        help='set stdin.'
92
    )
93
    parser.add_argument(
94
        '-f',
95
        '--compiler_option_raw',
96
        metavar='OPTIONS',
97
        action='append',
98
        default=['-D__WANDBOX__'],
99
        help='compile-time any additional options.'
100
    )
101
    parser.add_argument(
102
        '-r',
103
        '--runtime_option_raw',
104
        metavar='OPTIONS',
105
        action='append',
106
        help='runtime-time any additional options.'
107
    )
108
    parser.add_argument(
109
        '-s',
110
        '--save',
111
        action='store_true',
112
        help='generate permanent link.'
113
    )
114
    parser.add_argument(
115
        '--permlink',
116
        metavar='ID',
117
        help='get permanent link.'
118
    )
119
    parser.add_argument(
120
        '-o',
121
        '--output',
122
        metavar='FILE',
123
        help='output source code.'
124
    )
125
    parser.add_argument(
126
        '--xml',
127
        metavar='FILE',
128
        help='output result xml.'
129
    )
130
    parser.add_argument(
131
        '--junit',
132
        metavar='FILE',
133
        help='output result junit xml.'
134
    )
135
    parser.add_argument(
136
        '--stderr',
137
        action='store_true',
138
        help='output stderr.'
139
    )
140
    parser.add_argument(
141
        '--encoding',
142
        help='set encoding.'
143
    )
144
    parser.add_argument(
145
        '--expand_include',
146
        action='store_true',
147
        help='expand include file.'
148
    )
149
    parser.add_argument(
150
        '--check_config',
151
        action='store_true',
152
        help='check config.'
153
    )
154
    parser.add_argument(
155
        '--verbose',
156
        action='store_true',
157
        help='verbose.'
158
    )
159
    parser.add_argument(
160
        '--dryrun',
161
        action='store_true',
162
        help='dryrun.'
163
    )
164
    parser.add_argument(
165
        'code',
166
        metavar='CODE',
167
        nargs='*',
168
        help='source code file'
169
    )
170
    options = parser.parse_args()
171
    return options, parser
172
173
174
# file open
175
def file_open(path, mode, encoding):
176
    if encoding:
177
        file = codecs.open(path, mode, encoding)
178
    else:
179
        file = open(path, mode)
180
    return file
181
182
183
# make include filename
184
def make_include_filename(path, includes, included_files):
185
    if path in included_files:
186
        return included_files[path]
187
    else:
188
        include_dir, include_filename = os.path.split(path)
189
        while include_filename in includes:
190
            include_dir, dirname = os.path.split(include_dir)
191
            include_filename = dirname + '__' + include_filename
192
        included_files[path] = include_filename
193
        return include_filename
194
195
196
# 
197
def is_iutest_included_file(filepath):
198
    if os.path.abspath(filepath).startswith(IUTEST_INCLUDE_PATH):
199
        incg = 'INCG_IRIS_' + os.path.basename(filepath).upper().replace('.', '_')
200
        for included_incg in iutest_incg_list:
201
            if included_incg.startswith(incg):
202
                return True
203
    return False
204
205
206
# make code
207
def make_code(path, encoding, expand, includes, included_files):
208
    code = ''
209
    file = file_open(path, 'r', encoding)
210
    for line in file:
211
        m = IUTEST_INCLUDE_REGEX.match(line)
212
        if m:
213
            code += '#include "iutest.hpp"\n'
214
            code += '//origin>> ' + line
215
            if 'iutest.hpp' not in includes:
216
                try:
217
                    f = codecs.open(IUTEST_FUSED_SRC, 'r', 'utf-8-sig')
218
                    iutest_src = f.read()
219
                    f.close()
220
                    includes['iutest.hpp'] = iutest_src
221
                    global iutest_incg_list
222
                    iutest_incg_list = IUTEST_INCG_REGEX.findall(iutest_src)
223
                except:
224
                    print('{0} is not found...'.format(IUTEST_FUSED_SRC))
225
                    print('please try \"make fused\"')
226
                    exit(1)
227
        else:
228
            m = EXPAND_INCLUDE_REGEX.match(line)
229
            if m:
230
                include_path = os.path.normpath(os.path.join(os.path.dirname(path), m.group(1)))
231
                if is_iutest_included_file(include_path):
232
                    code += '//origin>> '
233
                elif os.path.exists(include_path):
234
                    if expand:
235
                        expand_include_file_code = make_code(
236
                            include_path, encoding, expand, includes, included_files)
237
                        code += expand_include_file_code
238
                        code += '//origin>> '
239
                    else:
240
                        include_abspath = os.path.abspath(include_path)
241
                        include_filename = make_include_filename(
242
                            include_abspath, includes, included_files)
243
                        if not include_filename == include_path:
244
                            code += '#include "' + include_filename + '"\n'
245
                            code += '//origin>> '
246
                        if include_filename not in includes:
247
                            includes[include_filename] = ''
248
                            expand_include_file_code = make_code(
249
                                include_path, encoding, expand, includes, included_files)
250
                            includes[include_filename] = expand_include_file_code
251
            code += line
252
    file.close()
253
    return code
254
255
256
# check config
257
def check_config(options):
258
    has_error = False
259
    if not find_compiler(options.compiler):
260
        print('Wandbox is not supported compiler [' + options.compiler + ']')
261
        listup_compiler()
262
        has_error = True
263
    if options.options or options.std:
264
        opt = get_options(options.compiler)
265
        if options.options:
266
            for o in options.options.split(','):
267
                if o not in opt:
268
                    print('Wandbox is not supported option [{0}] ({1})'.format(o, options.compiler))
269
                    has_error = True
270
        if options.std:
271
            if options.std not in opt:
272
                print('Wandbox is not supported option [{0}] ({1})'.format(options.std, options.compiler))
273
                has_error = True
274
        if has_error:
275
            listup_options(options.compiler)
276
    if has_error:
277
        sys.exit(1)
278
    if options.default:
279
        print('--default option is not work. default options are set by default (deprecated)')
280
281
282
# setup additional files
283
def add_files(w, fileinfos):
284
    for filename, code in fileinfos.items():
285
        w.add_file(filename, code)
286
287
288
# create opt list
289
def create_option_list(options):
290
    def filterout_cppver(opt):
291
        tmp = list(filter(lambda s: s.find('c++') == -1, opt))
292
        tmp = list(filter(lambda s: s.find('gnu++') == -1, tmp))
293
        return tmp
294
    opt = []
295
    if not options.no_default:
296
        opt = get_default_options(options.compiler)
297
    if options.options:
298
        for o in options.options.split(','):
299
            if o not in opt:
300
                if (o.find('c++') == 0) or (o.find('gnu++') == 0):
301
                    opt = filterout_cppver(opt)
302
                opt.append(o)
303
    # std
304
    if options.std:
305
        opt = filterout_cppver(opt)
306
        opt.append(options.std)
307
    # boost
308
    if options.compiler in ["clang-3.4"]:
309
        if not options.boost:
310
            options.boost = 'nothing'
311
    if options.boost:
312
        if options.compiler not in options.boost:
313
            options.boost = options.boost + '-' + options.compiler
314
        opt = list(filter(lambda s: s.find('boost') == -1, opt))
315
        opt.append('boost-' + str(options.boost))
316
    # sprout
317
    if options.sprout and 'sprout' not in opt:
318
        opt.append('sprout')
319
    # msgpack
320
    if options.msgpack and 'msgpack' not in opt:
321
        opt.append('msgpack')
322
    return opt
323
324
325
# run wandbox
326
def run_wandbox(code, includes, impliments, options):
327
    w = Wandbox()
328
    w.compiler(options.compiler)
329
    w.options(','.join(create_option_list(options)))
330
    if options.stdin:
331
        w.stdin(options.stdin)
332
    co = ''
333
    if options.compiler_option_raw:
334
        co = '\n'.join(options.compiler_option_raw)
335
        co = co.replace('\\n', '\n')
336
#    if options.compiler in ["clang-3.4"]:
337
#        co += "\n-DIUTEST_HAS_HDR_CXXABI=0"
338
    if options.compiler in ["clang-3.3", "clang-3.2", "clang-3.1", "clang-3.0"]:
339
        co += "\n-Qunused-arguments"
340
#    if options.compiler in ["clang-3.4", "clang-3.3"]:
341
#        co += "\n-fno-rtti"
342
    if len(co) > 0:
343
        w.compiler_options(co)
344
    if options.runtime_option_raw:
345
        ro = ''
346
        for opt in options.runtime_option_raw:
347
            ro += opt + '\n'
348
        ro = ro.replace('\\n', '\n')
349
        w.runtime_options(ro)
350
    if options.save:
351
        w.permanent_link(options.save)
352
    for filename in impliments.keys():
353
        w.add_compiler_options(filename)
354
    if options.verbose:
355
        w.dump()
356
    w.code(code)
357
    add_files(w, impliments)
358
    add_files(w, includes)
359
    if options.dryrun:
360
        sys.exit(0)
361
362
    def run(retries):
363
        try:
364
            return w.run()
365
        except HTTPError as e:
366
            if e.response.status_code == 504 and retries > 0:
367
                try:
368
                    print(e.message)
369
                except:
370
                    pass
371
                print("wait 30sec...")
372
                sleep(30)
373
                return run(retries - 1)
374
            else:
375
                raise
376
        except:
377
            raise
378
    return run(3)
379
380
381
# show result
382
def show_result(r, options):
383
    if 'error' in r:
384
        print(r['error'])
385
        sys.exit(1)
386
    if options.stderr:
387
        if 'compiler_output' in r:
388
            print('compiler_output:')
389
            print(r['compiler_output'].encode('utf_8'))
390
        if 'compiler_error' in r:
391
            sys.stderr.write(r['compiler_error'].encode('utf_8'))
392
        if 'program_output' in r:
393
            print('program_output:')
394
            print(r['program_output'].encode('utf_8'))
395
        if options.xml is None and options.junit is None and 'program_error' in r:
396
            sys.stderr.write(r['program_error'].encode('utf_8'))
397
    else:
398
        if 'compiler_message' in r:
399
            print('compiler_message:')
400
            print(r['compiler_message'].encode('utf_8'))
401
        if 'program_message' in r:
402
            print('program_message:')
403
            print(r['program_message'].encode('utf_8'))
404
    if 'url' in r:
405
        print('permlink: ' + r['permlink'])
406
        print('url: ' + r['url'])
407
    if 'signal' in r:
408
        print('signal: ' + r['signal'])
409
    if 'status' in r:
410
        return int(r['status'])
411
    return 1
412
413
414
# show parameter
415
def show_parameter(r):
416
    if 'compiler' in r:
417
        print('compiler:' + r['compiler'])
418
    if 'options' in r:
419
        print('options:' + r['options'])
420
    if 'compiler-option-raw' in r:
421
        print('compiler-option-raw:' + r['compiler-option-raw'])
422
    if 'runtime-option-raw' in r:
423
        print('runtime-option-raw' + r['runtime-option-raw'])
424
    if 'created-at' in r:
425
        print(r['created-at'])
426
427
428
def set_output_xml(options, t, xml):
429
    options.stderr = True
430
    if options.runtime_option_raw:
431
        options.runtime_option_raw.append("--iutest_output=" + t + ":" + xml)
432
    else:
433
        options.runtime_option_raw = ["--iutest_output=" + t + ":" + xml]
434
435
436
def run(options):
437
    main_filepath = options.code[0].strip()
438
    if not os.path.exists(main_filepath):
439
        sys.exit(1)
440
    includes = {}
441
    included_files = {}
442
    impliments = {}
443
    code = make_code(main_filepath, options.encoding, options.expand_include, includes, included_files)
444
    
445
    for filepath_ in options.code[1:]:
446
        filepath = filepath_.strip()
447
        impliments[os.path.basename(filepath)] = make_code(filepath, options.encoding, options.expand_include, includes, included_files)
448
449
    if options.output:
450
        f = file_open(options.output, 'w', options.encoding)
451
        f.write(code)
452
        f.close()
453
    xml = None
454
    if options.xml:
455
        xml = options.xml
456
        set_output_xml(options, 'xml', xml)
457
    if options.junit:
458
        xml = options.junit
459
        set_output_xml(options, 'junit', xml)
460
    r = run_wandbox(code, includes, impliments, options)
461
    b = show_result(r, options)
462
    if xml and 'program_error' in r:
463
        f = file_open(xml, 'w', options.encoding)
464
        f.write(r['program_error'])
465
        f.close()
466
    sys.exit(b)
467
468
469
# listup compiler
470
def listup_compiler(verbose):
471
    w = Wandbox()
472
    r = w.get_compiler_list()
473
    for d in r:
474
        if d['language'] == 'C++':
475
            if verbose:
476
                print(d['name'] + ' (' + d['version'] + ')')
477
            else:
478
                print(d['name'])
479
480
481
# find compiler
482
def find_compiler(c):
483
    w = Wandbox()
484
    r = w.get_compiler_list()
485
    for d in r:
486
        if d['language'] == 'C++' and d['name'] == c:
487
            return True
488
    return False
489
490
491
# listup options
492
def listup_options(compiler):
493
    w = Wandbox()
494
    r = w.get_compiler_list()
495
    for d in r:
496
        if d['name'] == compiler:
497
            print('# ' + compiler)
498
            if 'switches' in d:
499
                switches = d['switches']
500
                for s in switches:
501
                    if 'name' in s:
502
                        if s['default']:
503
                            print(s['name'] + ' (default)')
504
                        else:
505
                            print(s['name'])
506
                    elif 'options' in s:
507
                        print(s['default'] + ' (default)')
508
                        for o in s['options']:
509
                            print('  ' + o['name'])
510
511
512 View Code Duplication
def get_options(compiler):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
513
    w = Wandbox()
514
    r = w.get_compiler_list()
515
    opt = []
516
    for d in r:
517
        if d['name'] == compiler:
518
            if 'switches' in d:
519
                switches = d['switches']
520
                for s in switches:
521
                    if 'name' in s:
522
                        opt.append(s['name'])
523
                    elif 'options' in s:
524
                        opt.append(s['default'])
525
                        for o in s['options']:
526
                            opt.append(o['name'])
527
    return opt
528
529
530
# get default options
531 View Code Duplication
def get_default_options(compiler):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
532
    w = Wandbox()
533
    r = w.get_compiler_list()
534
    opt = []
535
    for d in r:
536
        if d['name'] == compiler:
537
            if 'switches' in d:
538
                switches = d['switches']
539
                for s in switches:
540
                    if 'name' in s:
541
                        if s['default']:
542
                            opt.append(s['name'])
543
                    elif 'options' in s:
544
                        opt.append(s['default'])
545
    return opt
546
547
548
# get permlink
549
def get_permlink(options):
550
    w = Wandbox()
551
    r = w.get_permlink(options.permlink)
552
    p = r['parameter']
553
    show_parameter(p)
554
    print('result:')
555
    b = show_result(r['result'], options)
556
    if options.output:
557
        f = open(options.output, 'w')
558
        f.write(p['code'])
559
        f.close()
560
    sys.exit(b)
561
562
563
def main():
564
    options, parser = parse_command_line()
565
    if options.list_compiler:
566
        listup_compiler(options.verbose)
567
    elif options.list_options:
568
        listup_options(options.list_options)
569
    elif options.permlink:
570
        get_permlink(options)
571
    else:
572
        if options.check_config:
573
            check_config(options)
574
        elif len(options.code) == 0:
575
            parser.print_help()
576
            sys.exit(1)
577
        run(options)
578
579
if __name__ == '__main__':
580
    main()
581