Wiki

Ticket #225: cmdline-subOpts.patch

File cmdline-subOpts.patch, 24.7 KB (added by hopscc, 7 years ago)
  • Source/BackEndClr/SharpGenerator.cobra

     
    7272        _modules.add(SharpModule(fileName, _verbosity)) 
    7373 
    7474    def writeSharpRunAllTests(cw as CurlyWriter) 
    75         runner = .options['test-runner'] to String  # ex: Cobra.Lang.CobraCore.runAllTests, ex: MyProgram.runTests 
     75        runner = .options.getSubOpt('testifyArgs', 'runner') to String  # ex: Cobra.Lang.CobraCore.runAllTests, ex: MyProgram.runTests 
    7676        if runner <> 'nil' 
    7777            if runner.endsWith('()'), runner = runner[:-2] 
    7878            if runner.startsWith('Cobra.Lang.'), runner = 'CobraLangInternal.' + runner['Cobra.Lang.'.length:] 
  • Source/CommandLine.cobra

     
    3434     
    3535    get type as String 
    3636        require .isUnpacked 
    37         ensure result in ['accumulator', 'args-list', 'bool', 'int', 'menu', 'set', 'string'] 
     37        ensure result in ['accumulator', 'args-list', 'bool', 'int', 'menu', 'set', 'string', 'multival'] 
    3838        return _type 
    3939 
    4040    get synonyms from var 
     
    7777        if _type == 'main' 
    7878            _isMain, _type = true, 'bool' 
    7979        if .containsKey('is-main'), _isMain = this['is-main'] to bool 
    80         assert _type in ['accumulator', 'args-list', 'bool', 'int', 'menu', 'set', 'string'] 
     80        assert _type in ['accumulator', 'args-list', 'bool', 'int', 'menu', 'set', 'string', 'multival'] 
    8181        if .containsKey('synonyms') 
    8282            for syn in this['synonyms'] 
    8383                _synonyms.add(syn) 
     
    9494        _unpackPlatforms 
    9595        _isUnpacked = true 
    9696        assert .type=='menu' implies .choices.count > 0 
    97         assert .choices.count <> 0 implies .type in ['menu', 'set'] 
     97        assert .choices.count <> 0 implies .type in ['menu', 'set', 'multival'] 
     98        assert .type=='multival' implies .containsKey('subOptions') and .containsKey('choices') 
     99        assert .type=='multival' implies this['subOptions'].specsList.count == this['choices'].count 
     100        assert .type=='multival' implies .choices.count > 0 
    98101 
    99102    def _unpackPlatforms 
    100103        if not .containsKey('platforms') 
     
    103106            assert platform in ['jvm', '.net', 'objc'] 
    104107        this['platforms'] = Set<of String>(this['platforms'] to List<of String>) 
    105108 
     109    def defaultIfOn as dynamic 
     110        if .containsKey('defaultIfOn'), return this['defaultIfOn'] 
     111        if .containsKey('default'), return this['default'] 
     112        return 'on'  
     113         
     114    def subOptions as List<of OptionSpec> 
     115        """Return SubOption list ( of OptionSpec) or empty list if no subOptions""" 
     116        if .containsKey('subOptions')   
     117            clos = this['subOptions'] 
     118            assert clos inherits CommandLineOptionSpecs 
     119            return clos.specsList  
     120        return List<of OptionSpec>() 
     121        # TODO: cache this in unpack and just return cached value from here 
    106122 
     123    def subOptionValue(name as String, keyList as vari String) as dynamic 
     124        """ 
     125        Find subOptions spec with given name; using keys from keyList return the value for  
     126        the first existing key in spec.  
     127        Return empty string if no subOptions or no matching keys found. 
     128        """ 
     129        for subOpt in .subOptions 
     130            if subOpt['name'] == name   
     131                for key in keyList 
     132                    if subOpt.containsKey(key), return subOpt[key] 
     133                break    
     134        return ''    
     135         
     136    def subOptionSpec(name as String) as OptionSpec 
     137        """Return subOption for name or fail""" 
     138        require .containsKey('subOptions')   
     139        for subOpt in .subOptions 
     140            if subOpt['name'] == name   
     141                return subOpt 
     142        assert subOpt, name 
     143        return  OptionSpec() 
     144         
    107145class CommandLineOptionSpecs 
    108146    """ 
    109147    Returns the command line option specifications, via .specsList, as a List of OptionSpec. 
     
    114152 
    115153    cue init 
    116154        base.init 
    117         for rawSpec in _rawCommandLineOptionSpecs 
     155        __initInternal(_rawCommandLineOptionSpecs) 
     156             
     157    cue init(rawOptionSpecs)  
     158        base.init 
     159        __initInternal(rawOptionSpecs) 
     160         
     161    def __initInternal(rawOptionSpecs)  
     162        assert rawOptionSpecs.count 
     163        for rawSpec in rawOptionSpecs 
    118164            spec = OptionSpec() 
    119165            if rawSpec inherits Dictionary<of String, Object> 
    120                 for key in rawSpec.keys, spec[key] = rawSpec[key] 
     166                for key in rawSpec.keys 
     167                    spec[key] = if(key == 'subOptions', CommandLineOptionSpecs(rawSpec[key]), rawSpec[key]) 
    121168            else if rawSpec inherits Dictionary<of String, String> 
    122169                for key in rawSpec.keys, spec[key] = rawSpec[key] 
    123170            else 
    124171                throw FallThroughException(rawSpec.getType) 
    125172            spec.unpack 
    126173            _specs.add(spec) 
    127  
     174                 
    128175    def specsList as List<of OptionSpec> 
    129176        """ 
    130177        Returns the option specs in the order they were declared. 
    131178        """ 
    132179        return _specs 
    133180 
     181    # Spec for each cobra compiler commandline option - List of Dictionaries 
     182    # TODO: doc the types 
     183    #type: main 
     184    #type: string 
     185    #type: int 
     186    #type: bool 
     187    #type: set 
     188    #type: menu 
     189    # 
     190    # type: multival supports a single cmdline option supporting multiple subOptions as comma separated name[=value] pairs 
     191    #   e.g. -multiValueDefault  -multival:key0,key1=15,key2=fred  
     192    #   Uses standard entries  
     193    #   (e.g. 'default' for a default value (commaSep list of pairs) if the cmdline option not given) 
     194    #   On the cmdline you can specify just the option (without any subOptions - to enable a default set) 
     195    #       this uses the value of entry 'defaultIfOn' (or 'default' if non existent.) 
     196    #   Must have a  'choices' entry which is a list of the recognised subOption names AND  
     197    #   Must have a 'subOptions' entry whose contents is a list of Dictionaries, one for each subOption supported 
     198    #       Each subOption dict must have at least entry for 'name' but more commonly also  
     199    #       'type', 'description' (for help display) and possibly entries for defaults  
     200    #       'defaultIfKeyOnly' and  'default' 
     201    #       On cmdline can give just a subOption( without '=value'). If want to support this and its different from  
     202    #           a value for 'default' (below) provide an entry for 'defaultIfKeyOnly' giving the value for this case. 
     203    #       If want a subOption value set if the option is enabled regardless of the subOption being given 
     204    #           then provide a 'default' entry. 
     205    #    
    134206    var _rawCommandLineOptionSpecs = [ 
    135207        { 
    136208            'name': 'about', 
     
    332404            'args': 'TYPENAME', 
    333405        }, 
    334406        { 
     407            'name': 'metrics', 
     408            'type': 'multival', 
     409            'args': r'[loc[=value],][mcc[=value]...]', 
     410            'description': 'Enable metrics calculations; name specific metrics to be done and any threshold values as comma separated name=value pairs.', 
     411            'choices': ['loc', 'mcc'],  #allowable subOption keys 
     412            'example': ['loc=80,mcc=10', 'mcc,loc=50', 'mcc=12', 'mcc,loc'], 
     413            #'default': 'loc=100,mcc=25',       # default if not specify name at all (none) 
     414            'defaultIfOn': 'loc=100,mcc=25',    # default (what subOpt values enabled) if only specify name 
     415            'subOptions' : [ 
     416                { 
     417                    'name': 'loc', 
     418                    'type': 'int', 
     419                    'description': 'Show methodname and number of codelines if greater than threshold value.',  
     420                    'defaultIfKeyOnly': '100',  # value to set if only specify subOpt name 
     421                },   
     422                { 
     423                    'name': 'mcc', 
     424                    'type': 'int', 
     425                    'description': 'Show method name and McCabe Complexity Calculation value if omplexity more than threshold. Reasonable values are in range 12-30', 
     426                    'defaultIfKeyOnly': '25', # value to set if only specify subOpt name 
     427                }, 
     428            ], 
     429        }, 
     430        { 
    335431            'name': 'namespace', 
    336432            'synonyms': ['name-space', 'ns'], 
    337433            'type': 'string', 
     
    429525            'type': 'main', 
    430526        }, 
    431527        { 
    432             'name': 'test-runner', 
    433             'type': 'string', 
    434             'description': 'Specify the method to invoke to run the unit tests. The method must be "shared". Typically the method will make use of classes in Cobra.Lang.Test to set up and initiate the test run.', 
    435             'default': 'Cobra.Lang.CobraCore.runAllTests', 
    436             'args': 'QUALIFIED-METHOD-NAME|nil', 
    437         }, 
    438         { 
    439528            'name': 'testify', 
    440             'description': '...', 
     529            'description': 'Run Cobra compiler test suite', 
    441530            'type': 'main', 
    442531            'developer-only': true, 
    443532        }, 
    444533        { 
    445             'name': 'testify-results', 
    446             'description': 'The filename to write the testify results to. Progress is still written to console.', 
    447             'type': 'string', 
    448             'default': 'r-testify', 
     534            'name': 'testifyArgs', 
     535            'type': 'multival', 
     536            'description': 'Set names and values for controlling testify as a list of comma separated name=value pairs.', 
     537            'choices': ['resultsFile', 'runner', 'numThreads'],  #allowable subOption keys 
     538            'example': ['numThreads=4,resultsFile=testResult', 'runner=Core.myTestRunner', 'numThreads=2'], 
    449539            'developer-only': true, 
     540            'default': 'resultsFile=r-testify,runner=Cobra.Lang.CobraCore.runAllTests,numThreads=1', 
     541            'subOptions' : [ 
     542                { 
     543                    'name': 'resultsFile', 
     544                    'type': 'string', 
     545                    'description': 'Filename to write the testify results to. Progress is still written to console.', 
     546                    'default': 'r-testify',        # value to default to if not specify name at all 
     547                    #'defaultIfKeyOnly': 'r-testify', # value to set if only specify subOpt name 
     548                },   
     549                { 
     550                    'name': 'runner', 
     551                    'type': 'string', 
     552                    'description': 'method to invoke to run the unit tests. The method must be "shared". Typically the method will make use of classes in Cobra.Lang.Test to setup and initiate the test run.', 
     553                    'default': 'Cobra.Lang.CobraCore.runAllTests', 
     554                }, 
     555                { 
     556                    'name': 'numThreads', 
     557                    'type': 'int', 
     558                    'description': 'Number of threads to run the testify testsuite in.', 
     559                    'default': '1', 
     560                }, 
     561            ], 
    450562        }, 
    451563        { 
    452             'name': 'testify-threads', 
    453             'description': '...', 
    454             'type': 'int', 
    455             'developer-only': true, 
    456         }, 
    457         { 
    458564            'name': 'timeit', 
    459565            'description': 'Gives the total duration of running cobra (including the target program, if it is to be run). This is "wall time", not "cpu time".', 
    460566            # although this option is implied by 'testify', the description does not say so, since 'testify' is a hidden option 
     
    488594            'type': 'main', 
    489595        }, 
    490596    ] 
     597     
    491598 
    492  
    493599class CommandLine 
    494600    """ 
    495601    The main options that control the command line's behavior are: 
     
    589695            dest = _htmlWriter to TextWriter 
    590696        else 
    591697            dest = Console.out 
    592         if _htmlWriter 
    593             stylePath = Path.combine(Path.getDirectoryName(CobraCore.exePath), 'styles-output-html.css') 
    594             _htmlWriter.writeHtml('<html><head><link href="file://[stylePath]" rel=stylesheet type="text/css"></head><body>[_htmlWriter.newLine]') 
     698             
     699        _runPreamble 
    595700        print to dest 
    596701            paths = _pathList to ! 
    597702            options = _options 
     
    609714                print 'Paths:' 
    610715                for path in paths 
    611716                    print '    [path]' 
     717 
    612718            if options.boolValue('testify') 
    613719                .doTestify(paths) 
    614720            else if options.boolValue('run') 
     
    635741                .doHelp 
    636742            else 
    637743                .doRun(paths) 
     744            _runPostamble 
     745                 
     746    def _runPreamble         
    638747        if _htmlWriter 
     748            stylePath = Path.combine(Path.getDirectoryName(CobraCore.exePath), 'styles-output-html.css') 
     749            _htmlWriter.writeHtml('<html><head><link href="file://[stylePath]" rel=stylesheet type="text/css"></head><body>[_htmlWriter.newLine]') 
     750 
     751    def _runPostamble 
     752        if _htmlWriter 
    639753            _htmlWriter.writeHtml('</body></html>[_htmlWriter.newLine]') 
    640754 
    641755    def doHighlight(paths as List<of String>) as Compiler 
     
    679793            # Each phase of the compiler may throw an exception to stop compilation. 
    680794            # Before doing so, it prints its errors. 
    681795            assert c.errors.count>0 
    682             if _options.containsKey('editor') 
    683                 spec = _options['editor'] to String? 
    684             else 
    685                 spec = Environment.getEnvironmentVariable('COBRA_EDITOR') 
    686             if spec and spec <> '' 
    687                 if spec.indexOf('FILE')==-1 
    688                     .error('Missing FILE from editor spec.') 
    689                 if spec.indexOf('LINE')==-1 
    690                     .error('Missing LINE from editor spec.') 
    691                 i = spec.indexOf('_') 
    692                 if i == -1 
    693                     i = spec.indexOf(' ') 
    694                     if i == -1 
    695                         .error('Missing underscore or space from editor spec.') 
    696                 exeName = spec.substring(0, i) 
    697                 args = spec.substring(i+1) 
    698                 for error in c.errors 
    699                     if error.isError and error.hasSourceSite 
    700                         if error.fileName.trim <> '' 
    701                             # trace error.fileName, error.lineNum 
    702                             args = args.replace('FILE', error.fileName) 
    703                             args = args.replace('LINE', error.lineNum.toString) 
    704                             p = System.Diagnostics.Process() 
    705                             p.startInfo.fileName = exeName 
    706                             p.startInfo.arguments = args 
    707                             p.startInfo.useShellExecute = false 
    708                             if _verbosity >= 3 
    709                                 print 'Running: [p.startInfo.fileName] [p.startInfo.arguments]' 
    710                             try 
    711                                 p.start 
    712                                 p.waitForExit  # TODO: is this really needed? 
    713                             catch exc as Exception 
    714                                 print 'Cannot invoke editor:' 
    715                                 print '    Command: [p.startInfo.fileName] [p.startInfo.arguments]' 
    716                                 print '    Exception: [exc]' 
    717                             break 
     796            editorSpec = if(_options.containsKey('editor'), _options['editor'] to String?, Environment.getEnvironmentVariable('COBRA_EDITOR')) 
     797            if editorSpec and editorSpec.length 
     798                _editorOnErrorLines(c, editorSpec to !) 
     799     
    718800        CobraMain.linesCompiled = c.linesCompiled  
    719801        CobraMain.nodesCompiled = c.nodesCompiled  
    720802        CobraMain.tokensCompiled = c.tokensCompiled  
    721803        return c 
    722804 
     805    def _editorOnErrorLines(c as Compiler, editorSpec as String) 
     806        if editorSpec.indexOf('FILE')==-1,  .error('Missing FILE from editor spec.') 
     807        if editorSpec.indexOf('LINE')==-1,  .error('Missing LINE from editor spec.') 
     808        i = editorSpec.indexOf('_') 
     809        if i == -1 
     810            i = editorSpec.indexOf(' ') 
     811            if i == -1, .error('Missing underscore or space from editor spec.') 
     812 
     813        editorExe = editorSpec.substring(0, i) 
     814        args = editorSpec.substring(i+1) 
     815        for error in c.errors 
     816            if error.isError and error.hasSourceSite 
     817                if error.fileName.trim <> '' 
     818                    # trace error.fileName, error.lineNum 
     819                    args = args.replace('FILE', error.fileName) 
     820                    args = args.replace('LINE', error.lineNum.toString) 
     821                    p = System.Diagnostics.Process() 
     822                    p.startInfo.fileName = editorExe 
     823                    p.startInfo.arguments = args 
     824                    p.startInfo.useShellExecute = false 
     825                    if _verbosity >= 3 
     826                        print 'Running: [p.startInfo.fileName] [p.startInfo.arguments]' 
     827                    try 
     828                        p.start 
     829                        p.waitForExit  # TODO: is this really needed? 
     830                    catch exc as Exception 
     831                        print 'Cannot invoke editor:' 
     832                        print '    Command: [p.startInfo.fileName] [p.startInfo.arguments]' 
     833                        print '    Exception: [exc]' 
     834                    break 
     835         
    723836    def doDocument(paths as List<of String>) as Compiler 
    724837        comp = .doCompile(paths, false, false, do(c as Compiler)=c.lastPhase inherits BindInterfacePhase) 
    725838        GenerateHtmlDocVisitor(do(module)=module inherits CobraModule).gen(comp) 
     
    799912     
    800913        exeFileName as String? = nil 
    801914        runArgs = .options.getStringList('run-args') 
    802         # TODO: what's this? 
     915        # TODO: exeArgs as arglist of Strings exe-name exe-arg-0 exe-arg-1 ... cf argv list 
    803916        # exeArgs = .options.getDefaultLOStr('exe-args') 
    804917        # if exeArgs.count 
    805918        #   exeFileName = exeArgs[0] 
     
    838951        print '      -test ....... Run the unit tests of a library.' 
    839952        print '      -document ... Document the program (partial compilation). Also, -doc' 
    840953        print '      -highlight .. Syntax highlight the program in HTML.' 
     954        if Utils.isDevMachine 
     955            print '      -testify .... Run the compiler testsuite (cwd must be cobra Source dir).' 
    841956        print '' 
    842957        print '  cobra <options> <command>' 
    843958        print '    * standalone commands are:' 
     
    877992                    sep = ', ' 
    878993                print 
    879994            s = spec.description 
    880             while s.length 
    881                 if s.length < width 
    882                     print '[leftMarginStr][s]' 
    883                     s = '' 
    884                 else 
    885                     # TODO: bug in here for narrow widths. try "width = 20" to reproduce 
    886                     j = width + 1 
    887                     if j >= s.length, j = s.length - 1 
    888                     while j > 0 and s[j] <> ' ', j -= 1 
    889                     if j 
    890                         sub = s.substring(0, j) 
    891                         s = if(s.length, s.substring(j+1), '') 
    892                         print '[leftMarginStr][sub]' 
     995            if s.length 
     996                _printWrapped(s, width, leftMarginStr)  
     997            for subOptionSpec in spec.subOptions  
     998                assert subOptionSpec.name.length 
     999                if subOptionSpec.containsKey('description') 
     1000                    _printWrapped('"[subOptionSpec.name]" = [subOptionSpec.description]' , width, leftMarginStr + '  ')  
     1001                if subOptionSpec.hasDefault 
     1002                    soDefault = subOptionSpec['default'] 
     1003                    print '[leftMarginStr]    (default is [soDefault])' 
    8931004            if spec.containsKey('example') 
    8941005                if spec['example'] inherits System.Collections.IList 
    8951006                    first = true 
     
    9031014            if spec.containsKey('eg') # verbatim example line 
    9041015                print '[leftMarginStr]e.g. [spec["eg"]]' 
    9051016 
     1017    def _printWrapped(s as String, width as int, leftMarginStr as String) 
     1018        while s.length 
     1019            if s.length < width 
     1020                print '[leftMarginStr][s]' 
     1021                s ='' 
     1022            else     
     1023                # TODO: bug in here for narrow widths. try "width = 20" to reproduce 
     1024                j = width + 1 
     1025                if j >= s.length, j = s.length - 1 
     1026                while j > 0 and s[j] <> ' ', j -= 1 
     1027                if j 
     1028                    sub = s.substring(0, j) 
     1029                    s = if(s.length, s.substring(j+1), '') 
     1030                    print '[leftMarginStr][sub]' 
     1031 
    9061032    def doAbout 
    9071033        # CC: multiline string 
    9081034        print 
     
    12571383             
    12581384    def _addInDefaults(valueDict as Dictionary<of String, Object>) 
    12591385        for spec in _optionSpecs 
     1386            if spec.containsKey('subOptions') and valueDict.containsKey(spec.name)  
     1387                # set defaults for unspecified subOptions with defaults if any subOption is set 
     1388                _addInSubOptionDefaults(spec, valueDict) 
     1389 
    12601390            if not valueDict.containsKey(spec.name) and spec.hasDefault 
    12611391                defaultValue = _interpretValue(spec.default, spec) to ! 
    12621392                if .verbosity 
    12631393                    print 'Setting option "[spec.name]" to default value [defaultValue].' 
    12641394                valueDict[spec.name] = defaultValue 
    1265  
     1395                 
     1396    def _addInSubOptionDefaults(spec as OptionSpec, valueDict as Dictionary<of String, Object>) 
     1397        ov = valueDict[spec.name] to OptionValues # that whats been explicitly set 
     1398        for subOptSpec in spec.subOptions 
     1399            if subOptSpec.hasDefault 
     1400                if not ov.containsKey(subOptSpec.name) # value not set already 
     1401                    defaultValue = _interpretValue(subOptSpec['default'], subOptSpec) to ! 
     1402                    # Should we force subOptions to always have a default value ?? 
     1403                    if .verbosity 
     1404                        print 'Setting option "[spec.name]:[subOptSpec.name]" to default value [defaultValue].' 
     1405                    ov[subOptSpec.name] = defaultValue 
     1406                                     
     1407                         
    12661408    def _unpackOptions(valueDict as Dictionary<of String, Object>, fileList as List<of String>)  
    12671409        """ 
    12681410        Unpack certain options (verbosity and timeit) into specific class fields,  
     
    13811523                    else 
    13821524                        valueSet.add(choice) 
    13831525                value = valueSet 
     1526            on 'multival' # comma separated  key=value pairs  - key1[=value],key2[=value],... 
     1527                if valueStr =='on', valueStr =  spec.defaultIfOn 
     1528                pairs = List<of String>(valueStr.split(c',')) 
     1529                assert pairs.count > 0 
     1530                subValueOpts = OptionValues() 
     1531                for kvp in pairs 
     1532                    kve = List<of String>(kvp.trim.split(c'=')) 
     1533                    assert kve.count > 0 
     1534                    key = kve[0] 
     1535                    if not key in spec.choices and key <> 'on' 
     1536                        print 'Unknown subOption key "[key]" in option "[spec.name]"' 
     1537                        continue 
     1538                    valStr = if(kve.count > 1, kve[1], spec.subOptionValue(key, 'defaultIfKeyOnly', 'default') to String) 
     1539                    iValue = _interpretValue(valStr, spec.subOptionSpec(key))    
     1540                    subValueOpts.setKV(key, iValue) 
     1541                value = subValueOpts     
    13841542            else 
    13851543                throw FallThroughException(spec.type) 
    13861544        return value 
     
    14281586 
    14291587 
    14301588class OptionValues inherits Dictionary<of String, Object> 
    1431  
     1589     
    14321590    var _isSpecified = Dictionary<of String, bool>()  # CC: could just be a Set 
    14331591 
    14341592    cue init 
     
    14601618 
    14611619    def get(key as String) as dynamic? 
    14621620        return this[key] 
    1463  
     1621         
     1622    def setKV(key as String, value as Object) 
     1623        this[key] = value 
     1624        .didSpecify(key) 
     1625         
    14641626    def getDefault(key as String, default as dynamic?) as dynamic? 
    14651627        if .containsKey(key) 
    14661628            return this[key] 
     
    14771639        else 
    14781640            return List<of String>() 
    14791641 
     1642    def getSubOpt(majorKey as String, minorKey as String, default as dynamic) as dynamic 
     1643        """ 
     1644        Return subOption value for the given option and subOption (for a multi key=value Option) 
     1645        SubOptions are stored themselves as a set of OptionValues. 
     1646        If no major or minor key value return default.   
     1647        """ 
     1648        if .containsKey(majorKey) 
     1649            so = .get(majorKey) to OptionValues 
     1650            if  so.containsKey(minorKey) 
     1651                return so[minorKey]  
     1652        return default 
     1653                 
     1654    def getSubOpt(majorKey as String, minorKey as String ) as dynamic 
     1655        """ 
     1656        Return subOption value for the given option and subOption (multivalued option,  multi key=value). 
     1657        Both the Option and subOption must exist otherwise an assert exception is incurred 
     1658        """ 
     1659        assert .containsKey(majorKey) 
     1660        so = .get(majorKey) to OptionValues 
     1661        assert  so.containsKey(minorKey) 
     1662        return so[minorKey]  
     1663 
    14801664    # CC: def getDefault<of T>(key as String, value as T) as T ... 
    14811665 
    14821666    def setValue(key as String) as Set<of String> 
  • Source/TestifyRunner.cobra

     
    5858        paths = _pathList 
    5959        if paths.count == 0 
    6060            paths = .cobraTestPaths + [Path.getFullPath(Path.combine('..', 'HowTo'))] 
    61         numThreads = .options.getDefault('testify-threads', 1) to int 
     61        #numThreads = .options.getDefault('testify-threads', 1) to int 
     62        numThreads = .options.getSubOpt('testifyArgs', 'numThreads', 1) to int 
    6263        if numThreads > 1 
    6364            .runThreaded(numThreads, paths) 
    6465        else 
     
    7778 
    7879        args = CobraCore.commandLineArgs 
    7980        _subCobraExe = args[0] 
    80         _subCommandLineArgs = for arg in args[1:] where arg.startsWith('-') and not '-testify-threads:' in arg 
     81        #_subCommandLineArgs = for arg in args[1:] where arg.startsWith('-') and not '-testify-threads:' in arg 
     82        _subCommandLineArgs = for arg in args[1:] where arg.startsWith('-') and not '-testifyArgs:' in arg 
    8183 
    8284        _statusWriter.writeLine('Queueing for threads:') 
    8385        for path in paths 
     
    102104            concat.append(sep) 
    103105            concat.append(File.readAllText(fileName)) 
    104106            sep = sepNl 
    105         File.writeAllText(.options['testify-results'] to String, concat.toString) 
     107        File.writeAllText(.options.getSubOpt('testifyArgs','resultsFile') to String, concat.toString) 
    106108        for fileName in _subResultsFileNames 
    107109            try 
    108110                File.delete(fileName) 
     
    110112                _statusWriter.writeLine('warning: Cannot delete "[fileName]" due to: [exc]') 
    111113 
    112114    def _printTotals 
    113         resultsFileName = .options['testify-results'] to String 
     115        resultsFileName = .options.getSubOpt('testifyArgs', 'resultsFile') to String 
    114116        using resultsWriter = File.appendText(resultsFileName) 
    115117            __printTotals(resultsWriter to !) 
    116118        __printTotals(_statusWriter to !) 
     
    133135                pathIndex = _subDirQueue.count 
    134136                resultsFileName = 'r-testify-[pathIndex]' 
    135137                lock _subResultsFileNames, _subResultsFileNames[pathIndex] = resultsFileName 
    136                 args = _subCommandLineArgs + ['-testify-results:[resultsFileName]', '-testify-threads:1', '"[path]"'] 
    137                 lock _statusWriter, _statusWriter.writeLine('Thread [tid] start: [args.join(" ")]') 
     138                args = _subCommandLineArgs + ['-testifyArgs:resultsFile=[resultsFileName],numThreads=1', '"[path]"'] 
     139                lock _statusWriter, _statusWriter.writeLine('Thread [tid] start: [_subCobraExe] [args.join(" ")]') 
    138140            p = Process() 
    139141            p.startInfo.useShellExecute = false 
    140142            p.startInfo.redirectStandardOutput = true 
     
    177179        _statusWriter = IndentedWriter(AutoFlushWriter(Console.out)) 
    178180        _statusWriter.indentString = '    ' 
    179181        try 
    180             resultsFileName = .options['testify-results'] to String 
     182            resultsFileName = .options.getSubOpt('testifyArgs', 'resultsFile') to String 
    181183            using resultsWriter = File.createText(resultsFileName) 
    182184                _resultsWriter = IndentedWriter(AutoFlushWriter(resultsWriter)) 
    183185                print to _resultsWriter to ! 
  • Developer/IntermediateReleaseNotes.text

     
    9494 
    9595* Added -verbosity-ref option to output information about resolving references to libraries. 
    9696 
    97  
     97* Added support for specifying a cmdline option with subOptions and modified   
     98    -test-runner, -testify-Threads, -testify-results to use it becoming a new multival option  
     99    -testifyArgs with subOptions runner,results and numThreads. 
     100    e.g. -testifyArgs:results=tResults,numThreads=4,runner=Core.Runner 
     101         -testifyArgs:numThreads=4 
     102         
    98103================================================================================ 
    99104Samples etc. 
    100105================================================================================