Test Failed
Branch master (2700dd)
by srz
01:28
created

print_undefined_option()   A

Complexity

Conditions 1

Size

Total Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
c 0
b 0
f 0
dl 0
loc 2
rs 10
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
import argparse
15
16
from time import sleep
17
from argparse import ArgumentParser
18
from wandbox import Wandbox
19
from requests.exceptions import HTTPError
20
21
IUTEST_FUSED_SRC = os.path.normpath(os.path.join(os.path.dirname(__file__), '../../fused-src/iutest.min.hpp'))
22
IUTEST_INCLUDE_PATH = os.path.normpath(os.path.join(os.path.dirname(__file__), '../../include'))
23
IUTEST_INCLUDE_REGEX = re.compile(r'^\s*#\s*include\s*".*(iutest|iutest_switch)\.hpp"')
24
EXPAND_INCLUDE_REGEX = re.compile(r'^\s*#\s*include\s*"(.*?)"')
25
IUTEST_INCG_REGEX = re.compile(r'\s*#\s*define[/\s]*(INCG_IRIS_\S*)\s*')
26
27
iutest_incg_list = []
28
workaround = True
29
30
#
31
# command line option
32
def parse_command_line():
33
    parser = ArgumentParser()
34
    parser.add_argument(
35
        '-v',
36
        '--version',
37
        action='version',
38
        version=u'%(prog)s version 5.3'
39
    )
40
    parser.add_argument(
41
        '--list_compiler',
42
        '--list-compiler',
43
        action='store_true',
44
        help='listup compiler.'
45
    )
46
    parser.add_argument(
47
        '--list_options',
48
        '--list-options',
49
        metavar='COMPILER',
50
        help='listup compiler options.'
51
    )
52
    parser.add_argument(
53
        '-c',
54
        '--compiler',
55
        default='gcc-head',
56
        help='compiler select. default: %(default)s'
57
    )
58
    parser.add_argument(
59
        '-x',
60
        '--options',
61
        help='used options for a compiler.'
62
    )
63
    parser.add_argument(
64
        '--default',
65
        action='store_true',
66
        help='it is not work. default options are set by default (deprecated)'
67
    )
68
    parser.add_argument(
69
        '--no-default',
70
        action='store_true',
71
        help='no set default options.'
72
    )
73
    parser.add_argument(
74
        '--std',
75
        metavar='VERSION',
76
        help='set --std options.'
77
    )
78
    parser.add_argument(
79
        '--boost',
80
        metavar='VERSION',
81
        help='set boost options version X.XX or nothing.'
82
    )
83
    parser.add_argument(
84
        '--optimize',
85
        action='store_true',
86
        help='use optimization.'
87
    )
88
    parser.add_argument(
89
        '--cpp-verbose',
90
        action='store_true',
91
        help='use cpp-verbose.'
92
    )
93
    parser.add_argument(
94
        '--sprout',
95
        action='store_true',
96
        help='use sprout.'
97
    )
98
    parser.add_argument(
99
        '--msgpack',
100
        action='store_true',
101
        help='use msgpack.'
102
    )
103
    parser.add_argument(
104
        '--stdin',
105
        help='set stdin.'
106
    )
107
    parser.add_argument(
108
        '-f',
109
        '--compiler_option_raw',
110
        '--compiler-option-raw',
111
        metavar='OPTIONS',
112
        action='append',
113
        default=['-D__WANDBOX__'],
114
        help='compile-time any additional options.'
115
    )
116
    parser.add_argument(
117
        '-r',
118
        '--runtime_option_raw',
119
        '--runtime-option-raw',
120
        metavar='OPTIONS',
121
        action='append',
122
        help='runtime-time any additional options.'
123
    )
124
    parser.add_argument(
125
        '-s',
126
        '--save',
127
        action='store_true',
128
        help='generate permanent link.'
129
    )
130
    parser.add_argument(
131
        '--permlink',
132
        metavar='ID',
133
        help='get permanent link.'
134
    )
135
    parser.add_argument(
136
        '-o',
137
        '--output',
138
        metavar='FILE',
139
        help='output source code.'
140
    )
141
    parser.add_argument(
142
        '--xml',
143
        metavar='FILE',
144
        help='output result xml.'
145
    )
146
    parser.add_argument(
147
        '--junit',
148
        metavar='FILE',
149
        help='output result junit xml.'
150
    )
151
    parser.add_argument(
152
        '--stderr',
153
        action='store_true',
154
        help='output stderr.'
155
    )
156
    parser.add_argument(
157
        '--encoding',
158
        help='set encoding.'
159
    )
160
    parser.add_argument(
161
        '--expand_include',
162
        '--expand-include',
163
        action='store_true',
164
        help='expand include file.'
165
    )
166
    parser.add_argument(
167
        '--make',
168
        action='store_true',
169
        help=argparse.SUPPRESS
170
    )
171
    parser.add_argument(
172
        '--check_config',
173
        '--check-config',
174
        action='store_true',
175
        help='check config.'
176
    )
177
    parser.add_argument(
178
        '--verbose',
179
        action='store_true',
180
        help='verbose.'
181
    )
182
    parser.add_argument(
183
        '--dryrun',
184
        action='store_true',
185
        help='dryrun.'
186
    )
187
    parser.add_argument(
188
        'code',
189
        metavar='CODE',
190
        nargs='*',
191
        help='source code file'
192
    )
193
    options = parser.parse_args()
194
    return options, parser
195
196
197
# file open
198
def file_open(path, mode, encoding):
199
    if encoding:
200
        file = codecs.open(path, mode, encoding)
201
    else:
202
        file = open(path, mode)
203
    return file
204
205
206
# make include filename
207
def make_include_filename(path, includes, included_files):
208
    if path in included_files:
209
        return included_files[path]
210
    else:
211
        include_dir, include_filename = os.path.split(path)
212
        while include_filename in includes:
213
            include_dir, dirname = os.path.split(include_dir)
214
            include_filename = dirname + '__' + include_filename
215
        included_files[path] = include_filename
216
        return include_filename
217
218
219
# 
220
def is_iutest_included_file(filepath):
221
    if os.path.abspath(filepath).startswith(IUTEST_INCLUDE_PATH):
222
        incg = 'INCG_IRIS_' + os.path.basename(filepath).upper().replace('.', '_')
223
        for included_incg in iutest_incg_list:
224
            if included_incg.startswith(incg):
225
                return True
226
    return False
227
228
229
# make code
230
def make_code(path, encoding, expand, includes, included_files):
231
    code = ''
232
    file = file_open(path, 'r', encoding)
233
    for line in file:
234
        m = IUTEST_INCLUDE_REGEX.match(line)
235
        if m:
236
            code += '#include "iutest.hpp"\n'
237
            code += '//origin>> ' + line
238
            if 'iutest.hpp' not in includes:
239
                try:
240
                    f = codecs.open(IUTEST_FUSED_SRC, 'r', 'utf-8-sig')
241
                    iutest_src = f.read()
242
                    f.close()
243
                    includes['iutest.hpp'] = iutest_src
244
                    global iutest_incg_list
245
                    iutest_incg_list = IUTEST_INCG_REGEX.findall(iutest_src)
246
                except:
247
                    print('{0} is not found...'.format(IUTEST_FUSED_SRC))
248
                    print('please try \"make fused\"')
249
                    exit(1)
250
        else:
251
            m = EXPAND_INCLUDE_REGEX.match(line)
252
            if m:
253
                include_path = os.path.normpath(os.path.join(os.path.dirname(path), m.group(1)))
254
                if is_iutest_included_file(include_path):
255
                    code += '//origin>> '
256
                elif os.path.exists(include_path):
257
                    if expand:
258
                        expand_include_file_code = make_code(
259
                            include_path, encoding, expand, includes, included_files)
260
                        code += expand_include_file_code
261
                        code += '//origin>> '
262
                    else:
263
                        include_abspath = os.path.abspath(include_path)
264
                        include_filename = make_include_filename(
265
                            include_abspath, includes, included_files)
266
                        if not include_filename == include_path:
267
                            code += '#include "' + include_filename + '"\n'
268
                            code += '//origin>> '
269
                        if include_filename not in includes:
270
                            includes[include_filename] = ''
271
                            expand_include_file_code = make_code(
272
                                include_path, encoding, expand, includes, included_files)
273
                            includes[include_filename] = expand_include_file_code
274
            code += line
275
    file.close()
276
    return code
277
278
279
def print_undefined_option(option, compiler):
280
    print('Wandbox is not supported option [{0}] ({1})'.format(opt, compiler))
281
282
283
# check config
284
def check_config(options):
285
    has_error = False
286
    if not find_compiler(options.compiler):
287
        print('Wandbox is not supported compiler [' + options.compiler + ']')
288
        listup_compiler()
289
        has_error = True
290
    if options.options or options.std:
291
        opt = get_options(options.compiler)
292
        if options.options:
293
            for o in options.options.split(','):
294
                if o not in opt:
295
                    print_undefined_option(o, options.compiler)
296
                    has_error = True
297
        if options.std:
298
            if options.std not in opt:
299
                print_undefined_option(options.std, options.compiler)
300
                has_error = True
301
        if has_error:
302
            listup_options(options.compiler)
303
    if has_error:
304
        sys.exit(1)
305
    if options.default:
306
        print('--default option is not work. default options are set by default (deprecated)')
307
308
309
# setup additional files
310
def add_files(w, fileinfos):
311
    for filename, code in fileinfos.items():
312
        w.add_file(filename, code)
313
314
315
# create opt list
316
def create_option_list(options):
317
    def filterout_cppver(opt):
318
        tmp = list(filter(lambda s: s.find('c++') == -1, opt))
319
        tmp = list(filter(lambda s: s.find('gnu++') == -1, tmp))
320
        return tmp
321
    opt = []
322
    if not options.no_default:
323
        opt = get_default_options(options.compiler)
324
    if options.options:
325
        for o in options.options.split(','):
326
            if o not in opt:
327
                if (o.find('c++') == 0) or (o.find('gnu++') == 0):
328
                    opt = filterout_cppver(opt)
329
                opt.append(o)
330
    # std
331
    if options.std:
332
        opt = filterout_cppver(opt)
333
        opt.append(options.std)
334
    # optimize
335
    if options.optimize and ('optimize' not in opt):
336
        opt.append('optimize')
337
    # cpp-verbose
338
    if options.cpp_verbose and ('cpp-verbose' not in opt):
339
        opt.append('cpp-verbose')
340
    # boost
341
    if workaround:
342
        pass
343
#        if options.compiler in ['clang-3.4', 'clang-3.3']:
344
#            if not options.boost:
345
#                options.boost = 'nothing'
346
    if options.boost:
347
        if options.compiler not in options.boost:
348
            options.boost = options.boost + '-' + options.compiler
349
        opt = list(filter(lambda s: s.find('boost') == -1, opt))
350
        opt.append('boost-' + str(options.boost))
351
    # sprout
352
    if options.sprout and ('sprout' not in opt):
353
        opt.append('sprout')
354
    # msgpack
355
    if options.msgpack and ('msgpack' not in opt):
356
        opt.append('msgpack')
357
    return opt
358
359
360
def expand_wandbox_options(w, compiler, options):
361
    colist = []
362
    defs = {}
363
    for d in w.get_compiler_list():
364
        if d['name'] == compiler:
365
            if 'switches' in d:
366
                switches = d['switches']
367
                for s in switches:
368
                    if ('name' in s) and ('display-flags' in s):
369
                        defs[s['name']] = s['display-flags']
370
                    elif 'options' in s:
371
                        for o in s['options']:
372
                            if ('name' in o) and ('display-flags' in o):
373
                                defs[o['name']] = o['display-flags']
374
    for opt in options:
375
        if opt in defs:
376
            colist.extend(defs[opt].split())
377
    return colist
378
379
380
def run_wandbox_impl(w, options, retries):
381
    if options.dryrun:
382
        sys.exit(0)
383
    def run(retries):
384
        try:
385
            return w.run()
386
        except HTTPError as e:
387
            if e.response.status_code == 504 and retries > 0:
388
                try:
389
                    print(e.message)
390
                except:
391
                    pass
392
                print('wait 30sec...')
393
                sleep(30)
394
                return run(retries - 1)
395
            else:
396
                raise
397
        except:
398
            raise
399
    return run(retries)
400
401
402
def create_compiler_raw_option_list(options):
403
    colist = []
404
    if options.compiler_option_raw:
405
        raw_options = options.compiler_option_raw
406
        for x in raw_options:
407
            colist.extend(re.split('\s(?=-)', x.strip('"')))
408
    return colist
409
410
411
# run wandbox (makefile)
412
def run_wandbox_make(main_filepath, code, includes, impliments, options):
413
    w = Wandbox()
414
    w.compiler('bash')
415
    woptions = create_option_list(options)
416
    if options.stdin:
417
        w.stdin(options.stdin)
418
    impliments[os.path.basename(main_filepath)] = code
419
420
    colist = create_compiler_raw_option_list(options)
421
    colist.extend(expand_wandbox_options(w, options.compiler, woptions))
422
423
    rolist = []
424
    if options.runtime_option_raw:
425
        for opt in options.runtime_option_raw:
426
            rolist.extend(opt.split())
427
428
    makefile = '#!/bin/make\n# generate makefile by iuwandbox.py\n'
429
    makefile += '\nCXXFLAGS+='
430
    for opt in colist:
431
        makefile += opt + ' '
432
    makefile += '\nOBJS='
433
    for filename in impliments.keys():
434
        makefile += os.path.splitext(filename)[0] + '.o '
435
436
    makefile += '\n\
437
prog: $(OBJS)\n\
438
\t$(CXX) -o $@ $^ $(CXXFLAGS) $(LDFLAGS)\n\
439
'
440
441
    impliments['Makefile'] = makefile
442
443
    bashscript = 'make -j 4\n'
444
    bashscript += './prog '
445
    for opt in rolist:
446
        bashscript += opt + ' '
447
    bashscript += '\n'
448
    w.code(bashscript)
449
    
450
    if options.save:
451
        w.permanent_link(options.save)
452
    if options.verbose:
453
        w.dump()
454
    add_files(w, impliments)
455
    add_files(w, includes)
456
457
    return run_wandbox_impl(w, options, 3)
458
459
460
# run wandbox (cxx)
461
def run_wandbox_cxx(code, includes, impliments, options):
462
    w = Wandbox()
463
    w.compiler(options.compiler)
464
    w.options(','.join(create_option_list(options)))
465
    if options.stdin:
466
        w.stdin(options.stdin)
467
    colist = create_compiler_raw_option_list(options)
468
469
    if workaround:
470
        if options.compiler in ['clang-3.2']:
471
            colist.append('-ftemplate-depth=1024')
472
#        if options.compiler in ['clang-3.4']:
473
#            colist.append('-DIUTEST_HAS_HDR_CXXABI=0')
474
#        if options.compiler in ['clang-3.3', 'clang-3.2', 'clang-3.1', 'clang-3.0']:
475
#            colist.append('-Qunused-arguments')
476
#        if options.compiler in ['clang-3.4', 'clang-3.3']:
477
#            colist.append('-fno-exceptions')
478
#            colist.append('-fno-rtti')
479
        pass
480
    if len(colist) > 0:
481
        co = '\n'.join(colist)
482
        co = co.replace('\\n', '\n')
483
        w.compiler_options(co)
484
    if options.runtime_option_raw:
485
        rolist = []
486
        for opt in options.runtime_option_raw:
487
            rolist.extend(opt.split())
488
        ro = '\n'.join(rolist)
489
        ro = ro.replace('\\n', '\n')
490
        w.runtime_options(ro)
491
    if options.save:
492
        w.permanent_link(options.save)
493
    for filename in impliments.keys():
494
        w.add_compiler_options(filename)
495
    if options.verbose:
496
        w.dump()
497
    w.code(code)
498
    add_files(w, impliments)
499
    add_files(w, includes)
500
501
    return run_wandbox_impl(w, options, 3)
502
503
504
# run wandbox
505
def run_wandbox(main_filepath, code, includes, impliments, options):
506
    if options.make:
507
        return run_wandbox_make(main_filepath, code, includes, impliments, options)
508
    else:
509
        return run_wandbox_cxx(code, includes, impliments, options)
510
511
512 View Code Duplication
def wandbox_hint(r):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
513
    if 'compiler_error' in r:
514
        if 'undefined reference to `init_unit_test_suite' in r['compiler_error']:
515
            print('hint:')
516
            print('  If you do not use boost test, please specify the file with the main function first.')
517
518
519
def text_transform(value):
520
    try:
521
        if isinstance(value, str):
522
            return value.decode()
523
        elif isinstance(value, unicode):
524
            return value.encode('utf_8')
525
    except:
526
        pass
527
    return value
528
529
530
# show result
531 View Code Duplication
def show_result(r, options):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
532
    if 'error' in r:
533
        print(r['error'])
534
        sys.exit(1)
535
    if options.stderr:
536
        if 'compiler_output' in r:
537
            print('compiler_output:')
538
            print(text_transform(r['compiler_output']))
539
        if 'compiler_error' in r:
540
            sys.stderr.write(text_transform(r['compiler_error']))
541
        if 'program_output' in r:
542
            print('program_output:')
543
            print(text_transform(r['program_output']))
544
        if options.xml is None and options.junit is None and 'program_error' in r:
545
            sys.stderr.write(text_transform(r['program_error']))
546
    else:
547
        if 'compiler_message' in r:
548
            print('compiler_message:')
549 View Code Duplication
            print(text_transform(r['compiler_message']))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
550
        if 'program_message' in r:
551
            print('program_message:')
552
            print(text_transform(r['program_message']))
553
    if 'url' in r:
554
        print('permlink: ' + r['permlink'])
555
        print('url: ' + r['url'])
556
    if 'signal' in r:
557
        print('signal: ' + r['signal'])
558
    wandbox_hint(r)
559
560
    if 'status' in r:
561
        return int(r['status'])
562
    return 1
563
564
565
# show parameter
566
def show_parameter(r):
567
    if 'compiler' in r:
568 View Code Duplication
        print('compiler:' + r['compiler'])
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
569
    if 'options' in r:
570
        print('options:' + r['options'])
571
    if 'compiler-option-raw' in r:
572
        print('compiler-option-raw:' + r['compiler-option-raw'])
573
    if 'runtime-option-raw' in r:
574
        print('runtime-option-raw' + r['runtime-option-raw'])
575
    if 'created-at' in r:
576
        print(r['created-at'])
577
578
579
def set_output_xml(options, t, xml):
580
    options.stderr = True
581
    if options.runtime_option_raw:
582
        options.runtime_option_raw.append('--iutest_output=' + t + ':' + xml)
583
    else:
584
        options.runtime_option_raw = ['--iutest_output=' + t + ':' + xml]
585
586
587
def run(options):
588
    main_filepath = options.code[0].strip()
589
    if not os.path.exists(main_filepath):
590
        sys.exit(1)
591
    includes = {}
592
    included_files = {}
593
    impliments = {}
594
    code = make_code(main_filepath, options.encoding, options.expand_include, includes, included_files)
595
    
596
    for filepath_ in options.code[1:]:
597
        filepath = filepath_.strip()
598
        impliments[os.path.basename(filepath)] = make_code(filepath, options.encoding, options.expand_include, includes, included_files)
599
600
    if options.output:
601
        f = file_open(options.output, 'w', options.encoding)
602
        f.write(code)
603
        f.close()
604
    xml = None
605
    if options.xml:
606
        xml = options.xml
607
        set_output_xml(options, 'xml', xml)
608
    if options.junit:
609
        xml = options.junit
610
        set_output_xml(options, 'junit', xml)
611
    r = run_wandbox(main_filepath, code, includes, impliments, options)
612
    b = show_result(r, options)
613
    if xml and 'program_error' in r:
614
        f = file_open(xml, 'w', options.encoding)
615
        f.write(r['program_error'])
616
        f.close()
617
    sys.exit(b)
618
619
620
# listup compiler
621
def listup_compiler(verbose):
622
    w = Wandbox()
623
    r = w.get_compiler_list()
624
    for d in r:
625
        if d['language'] == 'C++':
626
            if verbose:
627
                print(d['name'] + ' (' + d['version'] + ')')
628
            else:
629
                print(d['name'])
630
631
632
# find compiler
633
def find_compiler(c):
634
    w = Wandbox()
635
    r = w.get_compiler_list()
636
    for d in r:
637
        if d['language'] == 'C++' and d['name'] == c:
638
            return True
639
    return False
640
641
642
# listup options
643
def listup_options(compiler):
644
    w = Wandbox()
645
    r = w.get_compiler_list()
646
    for d in r:
647
        if d['name'] == compiler:
648
            print('# ' + compiler)
649
            if 'switches' in d:
650
                switches = d['switches']
651
                for s in switches:
652
                    if 'name' in s:
653
                        if s['default']:
654
                            print(s['name'] + ' (default)')
655
                        else:
656
                            print(s['name'])
657
                    elif 'options' in s:
658
                        print(s['default'] + ' (default)')
659
                        for o in s['options']:
660
                            print('  ' + o['name'])
661
662
663
def get_options(compiler):
664
    w = Wandbox()
665
    r = w.get_compiler_list()
666
    opt = []
667
    for d in r:
668 View Code Duplication
        if d['name'] == compiler:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
669
            if 'switches' in d:
670
                switches = d['switches']
671
                for s in switches:
672
                    if 'name' in s:
673
                        opt.append(s['name'])
674
                    elif 'options' in s:
675
                        opt.append(s['default'])
676
                        for o in s['options']:
677
                            opt.append(o['name'])
678
    return opt
679
680
681
# get default options
682
def get_default_options(compiler):
683
    w = Wandbox()
684
    r = w.get_compiler_list()
685
    opt = []
686
    for d in r:
687 View Code Duplication
        if d['name'] == compiler:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
688
            if 'switches' in d:
689
                switches = d['switches']
690
                for s in switches:
691
                    if 'name' in s:
692
                        if s['default']:
693
                            opt.append(s['name'])
694
                    elif 'options' in s:
695
                        opt.append(s['default'])
696
    return opt
697
698
699
# get permlink
700
def get_permlink(options):
701
    w = Wandbox()
702
    r = w.get_permlink(options.permlink)
703
    p = r['parameter']
704
    show_parameter(p)
705
    print('result:')
706
    b = show_result(r['result'], options)
707
    if options.output:
708
        f = open(options.output, 'w')
709
        f.write(p['code'])
710
        f.close()
711
    sys.exit(b)
712
713
714
def main():
715
    options, parser = parse_command_line()
716
    if options.list_compiler:
717
        listup_compiler(options.verbose)
718
    elif options.list_options:
719
        listup_options(options.list_options)
720
    elif options.permlink:
721
        get_permlink(options)
722
    else:
723
        if options.check_config:
724
            check_config(options)
725
        elif len(options.code) == 0:
726
            parser.print_help()
727
            sys.exit(1)
728
        run(options)
729
730
if __name__ == '__main__':
731
    main()
732