22# SPDX-License-Identifier: Apache-2.0
33
44import re
5- import sys
6- import getopt
75import datetime
86import logging
7+
8+ import click
99import yaml
1010
1111from scs_cert_lib import load_spec , annotate_validity
1414logger = logging .getLogger (__name__ )
1515
1616
17- def usage (file = sys .stdout ):
18- """Output usage information"""
19- print ("""Usage: select-testcases.py [options] SPEC_YAML
20-
21- Arguments:
22- SPEC_YAML: yaml file specifying the certificate scope
23-
24- Options:
25- -d/--date YYYY-MM-DD: Check standards valid on specified date instead of today
26- -V/--version VERS: Force version VERS of the standard (instead of deriving from date)
27- -S/--sections SECTION_LIST: comma-separated list of sections to test (default: all sections)
28- -t/--tests REGEX: regular expression to select individual testcases based on their ids
29- """ , file = file )
30-
31-
32- class Config :
33- def __init__ (self ):
34- self .arg0 = None
35- self .checkdate = datetime .date .today ()
36- self .version = None
37- self .sections = None
38- self .tests = None
39-
40- def apply_argv (self , argv ):
41- """Parse options. May exit the program."""
42- try :
43- opts , args = getopt .gnu_getopt (argv , "hd:V:S:t:" , (
44- "help" , "date=" , "version=" , "sections=" , "tests=" ,
45- ))
46- except getopt .GetoptError :
47- usage (file = sys .stderr )
48- raise
49- for opt in opts :
50- if opt [0 ] == "-h" or opt [0 ] == "--help" :
51- usage ()
52- sys .exit (0 )
53- elif opt [0 ] == "-d" or opt [0 ] == "--date" :
54- self .checkdate = datetime .date .fromisoformat (opt [1 ])
55- elif opt [0 ] == "-V" or opt [0 ] == "--version" :
56- self .version = opt [1 ]
57- elif opt [0 ] == "-S" or opt [0 ] == "--sections" :
58- self .sections = [x .strip () for x in opt [1 ].split ("," )]
59- elif opt [0 ] == "-t" or opt [0 ] == "--tests" :
60- self .tests = re .compile (opt [1 ])
61- else :
62- logger .error (f"Unknown argument { opt [0 ]} " )
63- if len (args ) != 1 :
64- usage (file = sys .stderr )
65- raise RuntimeError ("need precisely one argument" )
66- self .arg0 = args [0 ]
67-
68-
6917def select_valid (versions : list ) -> list :
7018 return [version for version in versions if version ['_explicit_validity' ]]
7119
7220
73- def main (argv ):
74- """Entry point for the checker"""
75- logging .basicConfig (format = '%(levelname)s: %(message)s' , level = logging .INFO )
76- config = Config ()
77- config .apply_argv (argv )
78- with open (config .arg0 , "r" , encoding = "UTF-8" ) as specfile :
21+ @click .group ()
22+ def cli ():
23+ return
24+
25+
26+ @cli .command ()
27+ @click .option ('--version' , '-V' , 'version' , type = str , default = None )
28+ @click .option ('--tests' , '-t' , 'tests' , type = str , default = None )
29+ @click .option ('--section' , '-S' , 'sections' , type = str , multiple = True )
30+ @click .argument ('specpath' , type = click .Path (exists = True ))
31+ def select (specpath , version , sections , tests ):
32+ with open (specpath , "r" , encoding = "UTF-8" ) as specfile :
7933 spec = load_spec (yaml .load (specfile , Loader = yaml .SafeLoader ))
80- annotate_validity (spec ['timeline' ], spec ['versions' ], config .checkdate )
81- if config .version is None :
34+ checkdate = datetime .date .today ()
35+ annotate_validity (spec ['timeline' ], spec ['versions' ], checkdate )
36+ if version is None :
8237 versions = select_valid (spec ['versions' ].values ())
8338 else :
84- versions = [spec ['versions' ].get (config . version )]
39+ versions = [spec ['versions' ].get (version )]
8540 if versions [0 ] is None :
86- raise RuntimeError (f"Requested version '{ config . version } ' not found" )
41+ raise RuntimeError (f"Requested version '{ version } ' not found" )
8742 if not versions :
88- raise RuntimeError (f"No valid version found for { config . checkdate } " )
43+ raise RuntimeError (f"No valid version found for { checkdate } " )
8944 title = spec ['name' ]
90- if config .sections :
91- title += f" [sections: { ', ' .join (config .sections )} ]"
92- if config .tests :
93- title += f" [tests: '{ config .tests .pattern } ']"
45+ if sections :
46+ title += f" [sections: { ', ' .join (sections )} ]"
47+ if tests :
48+ title += f" [tests: '{ tests } ']"
49+ tests_re = re .compile (tests )
9450 # collect all testcases we need
9551 testcase_lookup = spec ['testcases' ]
9652 all_testcase_ids = set ()
9753 for version in versions :
9854 for tc_id in version ['testcase_ids' ]:
99- if config . sections and testcase_lookup .get (tc_id , {}).get ('section' ) not in config . sections :
55+ if sections and testcase_lookup .get (tc_id , {}).get ('section' ) not in sections :
10056 continue
101- if config . tests and not config . tests .match (tc_id ):
57+ if tests and not tests_re .match (tc_id ):
10258 continue
10359 all_testcase_ids .add (tc_id )
10460 logger .info (f"{ title } : { len (all_testcase_ids )} testcases" )
@@ -107,10 +63,5 @@ def main(argv):
10763
10864
10965if __name__ == "__main__" :
110- try :
111- sys .exit (main (sys .argv [1 :]))
112- except SystemExit :
113- raise
114- except BaseException as exc :
115- logger .critical (f"{ str (exc ) or repr (exc )} " )
116- raise
66+ logging .basicConfig (format = '%(levelname)s: %(message)s' , level = logging .INFO )
67+ cli ()
0 commit comments